这是一篇总结,是在工作中遇到问题后,得出的方法论,希望可以帮到你。
基础知识
工作区(Working Directory)、暂存区(stage)、版本库(Repository)的关系
1、Git使用基本流程
安装Git(Linux系统):
sudo apt-get install git
初始化:
git init
查看仓库状态(可以查看修改文件的路径 <filePath>):
git status
开始工作!新增,修改,删除文件等等
查看某个文件的修改:
git diff -- <filePath>
添加某个文件到暂存区(获取文件路径<filePath>请使用上一条命令):
git add <filePath>
添加当前路径下所有文件到暂存区(stage):
git add .
提交到本地仓库:
git commit -m "本次修改的描述"
查看提交日志:
git log --pretty=oneline
其中--pretty=oneline
是可选参数,表示在一行显示(个人理解)
至此,本地git仓库的基本操作完成,接下来就是与远程仓库建立连接,然后推送代码。
1.1 关联远程仓库
适合先创建了本地仓库,再在远程创建了空的仓库:git remote add origin git@server-name:path/repo-name.git
其中origin
是远程仓库的名称,可以自定义;
关联后,使用命令git pull origin dev --allow-unrelated-histories
拉取远程分支内容,然后才能正常推送;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin branchName
推送最新修改,不用带-u
参数了。
2、另一种创建git仓库的方式(克隆远程仓库)
刚刚我们演示了第一种创建git仓库的方法:先本地初始化git仓库,然后与远程仓库关联。
如果你觉得第一种方式太繁琐,你可以使用克隆远程仓库的方法:新建一个远程仓库(例如在gitHub上面新建仓库,具体操作请自行百度),然后克隆到本地的某个文件夹。要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone
命令克隆。
例如:git clone git@github.com:michaelliao/gitskills.git
Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快
克隆到本地后,就可以在本地文件夹下使用各种git的命令了,例如:git add .
git commit -m "xxx"
git push origin branchName
等。
3、撤销与回退
git的精髓就是可以记录下你的每一次有效的更改,可以随时回退,如时光穿梭一般。
撤销与回退可以分为三种情况:
情况一:你修改了文件,但是没有commit到本地仓库中,即没有执行 git commit -m 'xxxx'
这命令;此时可以使用git checkout
命令;
情况二:你修改了文件,并且已经commit到本地仓库了。这个时候你可以使用撤销命令git reset --hard commitId
,commitId是你commit成功后返回的唯一的哈希值。可以通过git log
命令找到;
情况三:修改了文件,已经commit到本地仓库,并且push到了远程仓库,即使用了git push
命令,这个就比较棘手了!!建议初学者谨慎push代码到远程。别紧张,补救的方法还是有的。
前面两种情况都属于本地仓库的撤销与回退,情况三属于远程仓库的撤销与回退。解决办法请参照下面的3.1和3.2。
3.1 本地仓库的撤销与回退
撤销修改:
git checkout -- <filePath>
,让这个文件回到最近一次git commit
或git add
时的状态。git checkout -- file
命令中的--
很重要,没有--
,就变成了”切换到另一个分支“的命令。 <filePath>可以是某个文件的路径,也可以是一个文件夹的路径。如果是文件夹会回退该文件夹下所有的文件(谨慎操作)。回退:
git reset <filePath>
可以把暂存区的修改撤销掉,重新放回工作区。git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。版本回退:
git reset --hard HEAD^
,参数HEAD^
表示回退一步,HEAD^^
表示回退2步,HEAD~n
表示回退n步。也可以后跟一个commit id
,例如:git reset --hard 1094a
。显示所有操作历史:
git reflog
,这个命令可以让你恢复到”未来“的版本,只要你找到”未来“的commit id
就可以了。这个命令的好处多多,如果你以后找不到commitId了,别忘了试试这个命令。
3.2 远程仓库的回滚
上面的操作都只是本地的撤销与回退,万一你不小心把不该提交的修改,推送到了远程。这个时候,你需要做远程仓库的回滚。远程回滚有三种方法(个人总结的):
方法一:本地回滚,强推到远程。先将本地代码回滚到合适的节点,使用命令git push -u origin master -f
origin:远程仓库名 master:分支名称 -f:force:强制。
可能遇到的问题:
remote: GitLab: You don't have permission
To git@10.255.223.213:code-ddreader/media-hapi.git
! [remote rejected] master (pre-receive hook declined)
这个问题一般是权限问题,或者分支设置了保护,需要对远程仓库分支设置合理的权限。
方法二:先reset回滚到本地,然后再提交到一个新的分支,删除错误的分支(git brach -d master),再把新的分支重命名删除掉的分支。
可能遇到的问题:
- 做好备份,使用命令
git checkout backup
创建一条备份分支 - 这需要团队的其他人把本地的删除掉,然后重新下载一份,任何一个人未重新下载就可以出问题
- 默认分支是无法删除的,遇到master远程仓库要回滚就会出问题,我们master是默认的主干,所以不允许删除,要删除的话还要设置一个新的分支为主分支
方法三:手动回滚,如果知道修改了哪些文件或者文件夹的内容,可以将这部分文件或文件夹备份到仓库以外的某个文件夹中,然后将当前分支回退到某个想要的节点,最后把刚刚备份的文件或文件夹覆盖当前分支的对应文件或文件夹。
具体操作步骤如下:
1、备份有用的文件或文件夹到仓库外的地方,例如桌面的某个文件夹
2、回滚到想要的节点 git reset 07fecc82858854ca2a67c3a5c8b19ebf491df286
3、把刚刚备份的文件或文件夹,放到仓库中对应的文件夹中
这个办法是比较无损的,但是需要在当事人的电脑上操作,并且需要知道哪些文件或者文件夹是有用的,可能用到的命令:git log
和git status
。
4、删除文件
删除工作区的文件:通过Linux命令
rm <fileName>
,或者直接找到文件手动删除删除版本库的文件:
git rm <fileName>
误删工作区的文件,可以从版本库恢复:
git checkout -- <fileName>
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”
命令git rm
用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
5、分支管理
查看分支
git branch 查看本地分支
git branch -v 查看本地分支的commit信息
git branch -a 查看所有分支(本地+远程)
git branch -a -v 查看所有分支(本地+远程)的commit信息
拉取远程分支
git fetch origin/xxx 将远程xxx分支拉取到本地
切换分支
git branch xxx 基于当前分支创建xxx分支
git checkout xxx 切换到xxx分支
git branch xxx origin/xxx 基于远程xxx分支,创建本地xxx分支
git checkout -b xxx origin/xxx 基于远程xxx分支,创建新分支并且切换到新分支
合并分支
git merge xxx 这条命令表示把`xxx`分支合并到当前分支
通常,合并分支时,如果可能,Git会用Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息。使用--no-ff
可以禁用Fast forward
模式。例如:git merge --no-ff -m "merge with no-ff" dev
删除分支
git branch -d dev 如果删除不掉,可以使用`git branch -D dev`强行删除某个分支
6、解决冲突
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。
7、保存工作空间(BUG紧急修复git工作流)
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,当前正在dev上进行的工作还没有提交。
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash
功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
存储当前分支的工作空间:
git stash
切换到需要修复bug的分支:
git checkout master
创建修复bug分支:
git checkout -b issue-101
修复完毕bug后,提交commit,然后切换到master分支,合并代码
切换之前分支的工作空间:
git checkout dev
查看存储的工作空间:
git stash list
恢复工作现场,有两种方法:
一是用
git stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop
来删除另一种方式是用
git stash pop
,恢复的同时把stash内容也删了
你可以多次stash,恢复的时候,先用git stash list查看。然后恢复指定的stash,用命令:git stash apply stash@{0}
8、查看某个 commit 的改动
git show COMMITID
或者git diff COMMIT^!
例如:
git show d34ff657f5
git diff d34ff657f5^!
9、多人协作流程
多人协作的工作模式通常是这样:
首先,可以试图用git push origin <branchName>
推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull
试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin <branch-name>
推送就能成功!
如果git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
- 多人协作时,如果项目比较庞大,可以按模块拆分,基本的工作流如下图所示:
10、Rebase(变基)
rebase操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
11、标签管理
一句话总结:tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
创建标签
git tag <tagName> 例如:`git tag v1.0.0`
对某次提交打tag
git tag v0.9 <commitId>
创建带有说明的标签
git tag -a v0.1 -m "version 0.1 released" <commitId>
查看所有标签
git tag
查看某个标签的信息( 注意,标签不是按时间顺序列出,而是按字母排序的)
git show <tagname>
注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
删除本地标签
git tag -d <tagname>
推送某个标签到远程
git push origin <tagname>
一次性推送全部尚未推送到远程的本地标签
git push origin --tags
删除远程标签
先删除本地标签: `git tag -d <tagname>`
再删除远程标签:`git push origin :refs/tags/<tagname>`
12、忽略特殊文件的git跟踪
配置.gitignore
文件即可,把需要忽略的文件名或者后缀添加到文件中,例如:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
# My configurations:
db.ini
deploy_key_rsa
.gitignore
文件本身要放到版本库里,并且可以对.gitignore
做版本管理!
13、设置命令别名
将设置status
的别名为st
:git config --global alias.st status
--global
参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中
参考文献:
廖雪峰的Git教程
Git 远程代码回滚master