三、Git中常用命令——分支管理
为什么要使用分支管理?
分支就是科幻电影里面的平行宇宙,也就是当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。
如果两个平行宇宙互不干扰,那就对现在的你也没有什么影响。当然,如果在某一时间点两个平行宇宙合并了,那你就既学会了Git又学会了SVN。
3.1 创建与合并分支
-
为什么要创建分支?
在实际开发的过程中,假设你准备开发一个新功能,但是需要几周才能完成,可是你在过去的两周里也只完成了50%的代码,这个时候如果你直接提交,那么不完整的代码会导致别人不能继续编写,如果你等代码全部写完再一次提交,你又会面临着代码丢失每天进度的巨大风险。
如果你创建了自己的分支,这个分支别人是看不到的,你可以在你的分支上工作,想何时提交就何时提交,直到你完成全部的开发工作后,再一次性的合并到原来的分支上,这样既安全又不会影响别人的工作。
-
创建分支
-
创建并切换分支(这两种命令作用相同)
#分开执行(先创建 再切换) $ git branch dev $ git checkout dev Switched to branch 'dev' #合并命令(创建并切换) git checkout -b dev
-
对readme.txt文件做修改,加上一行:
Creating a new Branch called dev.
-
把readme.txt文件添加至版本库:
$ git add readme.txt $ git commit -m "add new branch" [dev 96c9108] add new branch 1 file changed, 2 insertions(+), 1 deletion(-)
-
创建过程
- 合并分支
-
切换到主分支
$ git checkout master Switched to branch 'master'
-
合并分支
$ git merge dev Updating 2217b6e..96c9108 Fast-forward readme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
▲ merge命令用于合并指定分支到当前分支;
▲ Fast-forward合并是“快进模式”,也就是直接把master指向dev当前的提交;
▲ $ git merge --no-ff -m “merge with no-ff” dev表示强制禁用“快进模式”,Git会在merge时生成一个新的commit,这样的话,从分支历史上可以看出分支信息。
▲ 合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。 -
删除分支
$ git branch -d dev Deleted branch dev (was 96c9108).
-
合并过程
小贴士:
防止和撤销修改的checkout命令搞混淆,创建并切换分支可以使用:$ git switch -c dev这个命令,直接切换到已有的master分支可以使用:$ git switch master这个命令。
3.2 解决冲突
我们创建并快速合并分支的方法对我们来说很是便利,但是合并的过程也往往并不是一帆风顺的,当遇到合并冲突时,我们必须要先解决冲突再合并。
-
创建一个新的分支feature:
$ git switch -c feature Switched to a new branch 'feature'
-
修改readme.txt文件的内容:
Creating a new Branch called dev is quick.
-
在分支feature上提交:
$ git add readme.txt $ git commit -m "feature changes" [feature dffe6fe] feature changes
-
切换到master分支:
$ git switch master Switched to branch 'master'
-
再次修改readme.txt文件的内容:
Creating a new Branch called dev is quick and simple.
-
在分支master上提交:
$ git add readme.txt $ git commit -m "master changes" [master 0b14971] master changes 1 file changed, 1 insertion(+), 1 deletion(-)
-
快速合并:
$ git merge feature Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.
这个时候我们会看见,这和之前我们的合并结果怎么不一样呢?你没看错,它提示我们,合并起了冲突,那这个冲突是怎么引起的呢?
我们可以查看这时文件的状态:
同时,我们也可以在readme.txt文件中看到:
-
解决冲突:
现在我们可以查看最后一次msater修改的内容,只需要将内容的最终版本修改后再次提交即可:
Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes. Creating a new Branch called dev is quick and simple.
$ git add readme.txt $ git commit -m "deal with conflict" [master 06be32a] deal with conflict
-
查看合并情况:
用命令查看:$ git log --graph
-
删除分支:
$ git branch -d feature Deleted branch feature (was dffe6fe).
3.3 分支管理策略
Git分支十分强大,在团队开发中应该充分应用。
在实际开发中,我们应该按照几个基本原则进行分支管理:
▲ 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
▲ 然后那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
▲ 也就是说,你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就是这个样子的:
3.4 Bug分支
在软件开发的过程中,bug就像是家常便饭,有了bug就需要修复,在Git中的bug也是一样的。
在Git中,由于分支非常强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后合并分支,然后将临时分支删除。
-
查看当前分支状态:
$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: readme.txt no changes added to commit (use "git add" and/or "git commit -a")
很明显,当前我还正在工作,并且内容也并没有提交,这时我还必须要修复领导发来的一个bug任务,当我不知道该怎么办时,突然想起来,Git还提供了将当前工作现场藏起来的命令
-
隐藏当前工作现场:
$ git stash Saved working directory and index state WIP on master: 06be32a deal with conflict
-
创建临时分支:
$ git checkout master Already on 'master' $ git switch -c bug-101 Switched to a new branch 'bug-101'
-
修复bug:
这个bug我们假设就是将readme.txt中最后一句改为:bug is already resolved…,然后提交:
bug is already resolved...
$ git add readme.txt $ git commit -m "deal with bug-101" [bug-101 61a5f34] deal with bug-101 1 file changed, 2 insertions(+), 1 deletion(-)
-
合并分支:
$ git switch master Switched to branch 'master' $ git merge --no-f -m "merge bug-101" bug-101 Merge made by the 'recursive' strategy. readme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
-
删除bug-101分支:
$ git branch -d bug-101 Deleted branch bug-101 (was 61a5f34).
-
回到工作现场:
$ git stash list stash@{0}: WIP on master: 06be32a deal with conflict #恢复的同时把stash内容也删除 $ git stash pop Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt The stash entry is kept in case you need it again. #先恢复 $ git stash apply #再删除 $ git stash drop
思考?
我们刚刚是在master分支上修复了bug,那么如何在master分支分出的dev分支上修复同样的bug呢?
重复上述操作,晕…我当然知道,但是有没有更简单的方法呢?
那必须得有啊!!!
Git中提供了一个 $ git cherry-pick 版本号这个命令,将master分支上修复bug的提交复制到dev分支上,只是这时Git自动给dev分支做了一次提交,它的版本号并不等同于master中的版本号。
3.5 Feature分支
在开发的过程中,可能需要不断的添加新功能,这个时候你就需要不断经历的添加新的分支,完成开发后合并到最后删除这个过程。
但是!当你已经开发完毕之后准备合并,却从老板口中传来不幸的噩耗:因经费不足,此功能必须取消!oh!My God!白干了呜呜呜…
虽然白干了,但是这些机密的资料的分支还是必须要销毁的,当使用命令删除时:
$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
他会不断的提示你:此分支还没有被合并,如果删除,将丢掉修改,如果要强行删除,需要使用-D参数:
$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e).
哎,世界终于清净了…
3.6 多人协作
-
查看远程库信息,使用git remote -v;
-
本地新建的分支如果不推送到远程,对其他人就是不可见的;
-
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
-
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
-
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
-
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
温馨小贴士:后期我们一般使用开发工具推送和抓取,对于要求不高的小伙伴可以了解即可。
3.7 Rebase
-
rebase操作可以把本地未push的分叉提交历史整理成直线;
-
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。