0.摘要
本文主要介绍Git的分支管理操作。
1.什么是分支
从前面的内容可知,当我们创建了一个Git仓库后会得到一个默认分支,叫做master,但只有一个分支显然是不合适的。
比如:多人协作时,大家为了备份代码频繁地将自己的代码提交到master分支中,这必然会造成大量的冲突,如果每个人都有一个独立的分支,直到每个人的工作都结束后,再统一合并到master分支中,这样就井然有序了。
或者:当你的项目已经被成功上线后却出现了Bug,但这时候你却在开发新的功能,Bug必须马上修复,而现在的工作也需要进行保存。你可以新建一个分支用于修复Bug,待Bug修复完毕后,将这一分支与主分支进行合并。然后,再切换到新功能开发的分支,继续完成相应的工作。
2.创建并切换到新分支
方式一:
git branch #查看当前已有分支
git branch dev #创建名为dev的分支
git checkout dev #切换到dev分支
方式二:我们也可以一条命令完成分支的创建和切换
git checkout -b dev
-b 参数表示:创建并切换到该新建分支。
完成分支创建与切换之后,我们再来看一下当前已有的分支:
git branch 会列出当前库下存在的所有分支,并用 '*' 标记处当前分支。
从结果上看,我们已经成功创建并将dev切换为当前分支。
并且,此时dev分支上的内容与master分支上完全相同。
3.在新分支上进行一些工作并合并到主分支
首先,我们查看一下目前dev分支下的 README.md文件:
目前,dev分支下的README.md文件只有一行,下面我们在该文件下添加一行:
vim README.md #编辑README.md,添加一行内容
git add README.md #在dev分支下,add修改后的README.md
git commit -m "branch test" #在dev分支下,commit修改后的README.md
通过查看新的README.md文件可以看出内容已修改:
4.将dev分支合并到master分支并删除dev分支
当我们在dev分支下完成了相应的工作,就需要把该分支merge到master分支上,这样别人才能看到我们所做的修改。
git checkout master #切换到主分支
git branch #查看是否切换成功,如果'*'标记在master分支前就表示切换成功
git merge dev #把dev分支合并到master分支上
git branch -d dev #删除dev分支
git branch #查看是否删除dev分支
cat README.md #查看README.md内容
查看结果我们发现,我们已经成功删除了dev分支,并且在dev分支下的添加的内容也成功合并到了master分支下。
5.分支冲突
在分支合并的过程中,往往并不像上面那么顺利,可能会存在冲突的问题。下面,我们就用实例模拟一下分支冲突的问题。
step1:新建文件并commit
vim mission.txt #新建一个文件,并填入以下内容:
#[progress]:
#mession1:
#mession2:
git add mission.txt
git commit -m "first commit"
step2:新建分支dev1,并对mission.txt进行修改
git checkout -b dev1 新建分支dev1
vim mission.txt #修改文件,内容如下
#[progress]:
#mession1: completed by dev1
#mession2:
git add mission.txt
git commit -m "dev1 has completed mission1"
git checkout master
step3:新建分支dev2,也对mission.txt进行修改
git checkout -b dev2 新建分支dev2
vim mission.txt #修改文件,内容如下
#[progress]:
#mession1:
#mession2: completed by dev2
git add mission.txt
git commit -m "dev2 has completed mission2"
git checkout master
step4:将dev1,dev2与master合并
git merge dev1 #合并分支dev1
git merge dev2 #合并分支dev2
下面,重点来了:
由于两个分支都对mission.txt进行了修改,并且分别修改了不同的部分,这时候就产生了冲突。因为,Git也不知道究竟该听谁的了,所以“友善地”提醒了您fix好冲突之后再merge。
这种情况并不是特例,在多人协作时需要格外注意。当两位开发人员同时建立了自己的分支并独立开展工作,但由于之前没商量好,同时对某一文件进行了修改。那么在merge的时候,必然有一位需要解决冲突问题。
6.分支冲突解决
解决冲突只能依靠人工修改。如果其他人只是多敲了一个空格,你只需要在你的文件对应位置不上空格即可。但如果冲突的地方很多,那么工作量就非常大,这也就是为什么提醒读者在一定要注意这个问题的原因。多人合作完成任务的时候,一定要对文件有明确的划分。
下面,我们介绍如何查找冲突。发现问题才能解决问题嘛。
git status #帮助我们定位冲突的文件
Git告诉我们,冲突的文件是mission.txt,它被重复编辑。
此时,我们显示一下该文件的内容:
cat mission.txt
我们可以看到冲突的地方,Git已经使用<<<<<<<,=======,>>>>>>>帮我们分隔开来。并且,我们还能看出冲突内容所在的分支。
解决的方法就是直接在master分支下编辑mission.txt文件并保存,至于修改成什么样子,那就完全认为决定了,即便是删除了素有内容,Git也不会报错。
修改完文件后,在master下add+commit,之后删除分支:
git add mission.txt #add文件
git commit -m "fix comflict" #提交文件
git branch -d dev1 #删除分支dev1
git branch -d dev2 #删除分支dev2
这里留个小问题,如果我们把mission.txt中,每一行之间都添加一个空行,那么就不会出现分支冲突的问题,比如:
初始的mission.txt为:
dev1分支下修改的mission.txt为:
dev2分支下修改的mission.txt为:
当我们在master分支下执行:
git merge dev1 #合并分支dev1,顺利merge
git merge dev2 #合并分支dev2,需要添加merge说明,但也可以merge
除了合并dev2需要添加说明外,并不会产生冲突:
merge结束后,两个分支的内容都成功merge到master下了:
原因是:
如果不同分支同时更改了同一文件的同一文本块,这时候会产生冲突;
如果不同分支同时更改了同一文件的不同一文本块,这时候不会产生冲突;
如果两个分支修改的内容,中间有空行,那么就属于不同文本块,自然也就不冲突了。
7.Fast forword 模式
在上述的merge过程中,我们会看到一个关键词叫做:Fast Forword,下面解释一下Fast Forword的含义和用法:
为了直观理解两者的差别,打个比方(为避免例子过于臃肿,这个实例不过分深究Git的细节):
有三个人分别叫:master、dev1、dev2。首先master有一份问卷,dev1复印了一份问卷并填写,之后就直接把问卷交给了master;dev2也复印了一份问卷并填写,但dev2不愿意把问卷直接给master,所以master只能把问卷的答案抄下来带走;
由于master可以直接拿走dev1填好的问卷,所以回收问卷很快捷,这就是Fast Forword;
由于master不能拿走dev2的问卷,只能多花点时间把答案抄下来,所以回收问卷很慢,这就是No-Fast Forword;
总结一下:
Fast Forword:当前分支合并到另一分支时,在没有冲突的情况下,Git直接移动文件指针到当前分支,这个过程叫做Fast Forward。
比如,我们新建了一个分支dev1,并使用Fast Forward合并到master下:
HEAD同时指向了master和dev1两个分支,Git中出现这种情形的唯一可能就是master和dev1目前是同一个分支。
No-Fast Forword:当前分支合并到另一分支时,如果在merge时生成一个新的commit,这个过程叫做No-Fast Forward。
比如,我们新建了一个分支dev2,并使用--no-ff参数合并到master下:
需要说明的是,由于--no-ff方式需要新建commit,因此在合并的时候,需要添加commit说明:
git merge --no-ff -m "merge with no-ff " dev2
那么,Fast Forword和No-Fast Forword有什么区别呢?
两者主要在查看git log信息方面有差别:
Fast Forword没有新建commit,合并后的没有历史有分支,看不出来曾经做过合并。
No-Fast Forword新建commit,合并后的历史有分支,能看出来曾经做过合并。