咱们来抽象的理解,分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另外一个你正在另外一个平行宇宙里努力学习SVN。若是两个平行宇宙互不干扰,那对如今的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了git又学会了SVN!git
那么分支在实际中有什么用呢?假设你准备开发一个新功能,可是须要两周才能完成,第一周你写了50%的代码,若是马上提交,因为代码还没写完,不完整的代码库会致使别人不能干活了。若是等代码所有写完再一次提交,又存在丢失天天进度的巨大风险。vim
如今有了分支,就不用怕了。你建立了一个属于你本身的分支,别人看不到,还继续在原来的分支上正常工做,而你在本身的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工做。安全
git把咱们以前每次提交的版本串成一条时间线,这条时间线就是一个分支。截止到目前只有一条时间线,在git里,这个分支叫主分支,即master分支。HEAD严格来讲不是指向提交,而是指向master,master才是指向提交的,因此,HEAD指向的就是当前分支。bash
1) 一开始的时候,master分支是一条线,git用master指向最新的提交,再用HEAD指向master,就能肯定当前分支,以及当前分支的提交点:学习
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也愈来愈长。this
2)当咱们建立新的分支,例如dev时,git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:spa
git建立一个分支很快,由于除了增长一个dev指针,改变HEAD的指向,工做区的文件都没有任何变化。3d
3)不过,从如今开始,对工做区的修改和提交就是针对dev分支了,好比新提交一次后,dev指针往前移动一步,而master指针不变:指针
4)假如咱们在dev上的工做完成了,就能够把dev合并到master上。git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:code
git合并分支也很快,就改改指针,工做区内容也不变。
5)合并完分支后,甚至能够删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,咱们就剩下了一条master分支:
实战案例演示:
执行以下命令能够查看当前有几个分支,而且看到在哪一个分支下工做
[root@kai git_test]# git branch * master [root@kai git_test]#
下面建立一个分支dev并切换到其上进行工做。
[root@kai git_test]# git branch * master [root@kai git_test]# git checkout -b dev Switched to a new branch 'dev' [root@kai git_test]# git branch * dev master [root@kai git_test]#
下面咱们修改code.txt内容,在里面添加一行,并进行提交。
[root@kai git_test]# echo "add one line" >> code.txt [root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "dev_branch_submit" [dev b63902b] dev_branch_submit 1 file changed, 1 insertion(+) [root@kai git_test]#
dev分支的工做完成,咱们就能够切换回master分支:
[root@kai git_test]# git commit -m "dev_branch_submit" [dev b63902b] dev_branch_submit 1 file changed, 1 insertion(+) [root@kai git_test]# git checkout master Switched to branch 'master' [root@kai git_test]# git branch dev * master [root@kai git_test]#
master分支查看code.txt,发现添加的内容没有了。由于那个提交是在dev分支上,而master分支此刻的提交点并无变:
[root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line [root@kai git_test]#
如今,咱们把dev分支的工做成果合并到master分支上:
[root@kai git_test]# git merge dev Updating f25e944..b63902b Fast-forward code.txt | 1 + 1 file changed, 1 insertion(+) [root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line [root@kai git_test]#
注意到上面的Fast-forward信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master指向dev的当前提交,因此合并速度很是快。
合并完成后,就能够放心地删除dev分支了,删除后,查看branch,就只剩下master分支了。
[root@kai git_test]# git branch -d dev Deleted branch dev (was b63902b). [root@kai git_test]# git branch * master [root@kai git_test]#
小结:
查看分支:git branch
建立分支:git branch <name>
切换分支:git checkout <name>
建立+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
合并分支每每也不是一路顺风的。
再建立并切换一个新分支dev,修改code.txt内容,并进行提交。
[root@kai git_test]# git checkout -b dev Switched to a new branch 'dev' [root@kai git_test]# git branch * dev master [root@kai git_test]# echo "add two line" >> code.txt [root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line add two line [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "dev_branch_submit" [dev 7da47b4] dev_branch_submit 1 file changed, 1 insertion(+) [root@kai git_test]#
切换回master分支,在master的code.txt添加一行内容并进行提交。
[root@kai git_test]# git checkout master Switched to branch 'master' [root@kai git_test]# echo "add two line in master" >> code.txt [root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line add two line in master [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "matser_branch_submit" [master e57c158] matser_branch_submit 1 file changed, 1 insertion(+) [root@kai git_test]#
如今,master分支和dev分支各自都分别有新的提交,变成了这个样子:
这种状况下,git没法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突。
执行以下命令尝试将dev分支合并到master分支上来。
[root@kai git_test]# git merge dev Auto-merging code.txt CONFLICT (content): Merge conflict in code.txt Automatic merge failed; fix conflicts and then commit the result. [root@kai git_test]#
git告诉咱们,code.txt文件存在冲突,必须手动解决冲突后再提交。
git status也能够告诉咱们冲突的文件:
[root@kai git_test]# git status # On branch master # You have unmerged paths. # (fix conflicts and run "git commit") # # Unmerged paths: # (use "git add <file>..." to mark resolution) # # both modified: code.txt # no changes added to commit (use "git add" and/or "git commit -a") [root@kai git_test]#
查看code.txt的内容。
[root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line <<<<<<< HEAD add two line in master ======= add two line >>>>>>> dev [root@kai git_test]#
git用<<<<<<<,=======,>>>>>>>标记出不一样分支的内容,咱们修改以下后保存,再次提交:
[root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line add two line in master add two line [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "resolve_the_conflict" [master b46a32f] resolve_the_conflict [root@kai git_test]#
如今,master分支和dev分支变成了下图所示:
用带参数的git log也能够看到分支的合并状况:
[root@kai git_test]# git commit -m "resolve_the_conflict" [master b46a32f] resolve_the_conflict [root@kai git_test]# git log --graph --pretty=oneline * b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict |\ | * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit * | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit |/ * b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit * f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt * 66a9c996749285bdb5e2010b992483e8a1a1771c version4 * f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3 * 6280fa584403809ac2078a81120acf33e6bec836 version2 * 020bf021ec6d1b77836db4e96541d3659251714e version1 [root@kai git_test]#
最后工做完成,能够删除dev分支。
[root@kai git_test]# git branch -d dev Deleted branch dev (was 7da47b4). [root@kai git_test]# git branch * master [root@kai git_test]#
一般,合并分支时,若是可能,git会用fast forward模式,可是有些快速合并不能成功并且合并时没有冲突,这个时候会合并以后并作一次新的提交。但这种模式下,删除分支后,会丢掉分支信息。
建立切换到dev分支下,新建一个文件code3.txt编辑内容以下,并提交一个commit。
[root@kai git_test]# git checkout -b dev Switched to a new branch 'dev' [root@kai git_test]# echo "this is the first line" >> code3.txt [root@kai git_test]# cat code3.txt this is the first line [root@kai git_test]# git add code3.txt [root@kai git_test]# git commit -m "create_new_code3" [dev a1f6ad6] create_new_code3 1 file changed, 1 insertion(+) create mode 100644 code3.txt [root@kai git_test]#
切换回master分支,编辑code.txt并进行一个提交。
[root@kai git_test]# git checkout master Switched to branch 'master' [root@kai git_test]# ls code.txt [root@kai git_test]# echo "add three line" >> code.txt [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "add_new_line" [master f4f5dd0] add_new_line 1 file changed, 1 insertion(+) [root@kai git_test]#
合并dev分支的内容到master分支。出现以下提示,这是由于此次不能进行快速合并,因此git提示输入合并说明信息,输入以后合并内容以后git会自动建立一次新的提交。
[root@kai git_test]# git merge dev Merge branch 'dev' # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit. ~ ~ ~ ".git/MERGE_MSG" 7L, 246C # 保存退出便可! Merge made by the 'recursive' strategy. code3.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 code3.txt [root@kai git_test]#
使用分支命令查看分支信息。
[root@kai git_test]# git log --graph --pretty=oneline * f6807c155cbb5aa59a04a6eb354d1df14d641c3c Merge branch 'dev' |\ | * a1f6ad699c62782ddf3cd2c6fc36773f7e55a365 create_new_code3 * | f4f5dd02154451492b799d9ce8346361e3898b00 add_new_line |/ * b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict |\ | * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit * | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit |/ * b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit * f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt * 66a9c996749285bdb5e2010b992483e8a1a1771c version4 * f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3 * 6280fa584403809ac2078a81120acf33e6bec836 version2 * 020bf021ec6d1b77836db4e96541d3659251714e version1 [root@kai git_test]#
删除dev分支。
[root@kai git_test]# git branch -d dev Deleted branch dev (was a1f6ad6). [root@kai git_test]#
若是要强制禁用fast forward模式,git就会在merge时生成一个新的commit,这样,从分支历史上就能够看出分支信息。
禁用fast forward模式:
建立并切换到dev分支,修改code.txt内容,并提交一个commit。
[root@kai git_test]# git checkout -b dev Switched to a new branch 'dev' [root@kai git_test]# echo "add new line" >> code.txt [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "add_nwe_line" [dev 5952b2f] add_nwe_line 1 file changed, 1 insertion(+) [root@kai git_test]#
切换回master分支,准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
[root@kai git_test]# git merge --no-ff -m 'forbid_fastforward_merge' dev Merge made by the 'recursive' strategy. code.txt | 1 + 1 file changed, 1 insertion(+) [root@kai git_test]#
由于本次合并要建立一个新的commit,因此加上-m参数,把commit描述写进去。
合并后,咱们用git log看看分支历史:
能够看到,不使用Fast forward模式,merge后就像这样:
[root@kai git_test]# git log --graph --pretty=oneline * aa22465083e104bf61d7a5c1b8190fe48557adf7 forbid_fastforward_merge |\ | * 5952b2f6b216ca88484ab92aafc636077c30c9a3 add_nwe_line |/ * f6807c155cbb5aa59a04a6eb354d1df14d641c3c Merge branch 'dev' |\ | * a1f6ad699c62782ddf3cd2c6fc36773f7e55a365 create_new_code3 * | f4f5dd02154451492b799d9ce8346361e3898b00 add_new_line |/ * b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict |\ | * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit * | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit |/ * b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit * f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt * 66a9c996749285bdb5e2010b992483e8a1a1771c version4 * f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3 * 6280fa584403809ac2078a81120acf33e6bec836 version2 * 020bf021ec6d1b77836db4e96541d3659251714e version1 [root@kai git_test]#
软件开发中,bug就像屡见不鲜同样。有了bug就须要修复,在git中,因为分支是如此的强大,因此,每一个bug均可以经过一个新的临时分支来修复,修复后,合并分支,而后将临时分支删除。
当你接到一个修复一个代号001的bug的任务时,很天然地,你想建立一个分支bug-001来修复它,可是,等等,当前正在dev上进行的工做尚未提交:
[root@kai git_test]# echo "this line is writing...." >> code.txt [root@kai git_test]# git status # On branch dev # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: code.txt # no changes added to commit (use "git add" and/or "git commit -a") [root@kai git_test]#
并非你不想提交,而是工做只进行到一半,还无法提交,预计完成还需1天时间。可是,必须在两个小时内修复该bug,怎么办?
git还提供了一个stash功能,能够把当前工做现场“储藏”起来,等之后恢复现场后继续工做:
[root@kai git_test]# git stash Saved working directory and index state WIP on dev: 5952b2f add_nwe_line HEAD is now at 5952b2f add_nwe_line [root@kai git_test]#
首先肯定要在哪一个分支上修复bug,假定须要在master分支上修复,就从master建立临时分支:
[root@kai git_test]# git checkout master Switched to branch 'master' [root@kai git_test]# git checkout -b bug-001 Switched to a new branch 'bug-001' [root@kai git_test]#
如今模拟修复bug,把 add new line删掉,而后提交。
[root@kai git_test]# vim code.txt [root@kai git_test]# cat code.txt this is the first line this is the second line this is the third line this is the forth line add one line add two line in master add two line add three line [root@kai git_test]# git add code.txt [root@kai git_test]# git commit -m "repair_bug" [bug-001 f52de9b] repair_bug 1 file changed, 1 deletion(-)
修复完成后,切换到master分支,并完成合并,最后删除bug-001分支。
[root@kai git_test]# git checkout master Switched to branch 'master' [root@kai git_test]# git merge --no-ff -m "repair_bug" bug-001 Merge made by the 'recursive' strategy. code.txt | 1 - 1 file changed, 1 deletion(-) [root@kai git_test]# git branch -d bug-001 Deleted branch bug-001 (was f52de9b). [root@kai git_test]#
如今bug-001修复完成,是时候接着回到dev分支干活了!
[root@kai git_test]# git checkout dev Switched to branch 'dev' [root@kai git_test]# git status # On branch dev nothing to commit, working directory clean [root@kai git_test]#
工做区是干净的,刚才的工做现场存到哪去了?用git stash list命令看看:
[root@kai git_test]# git stash list stash@{0}: WIP on dev: 5952b2f add_nwe_line [root@kai git_test]#
工做现场还在,git把stash内容存在某个地方了,可是须要恢复一下
[root@kai git_test]# git stash pop # On branch dev # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: code.txt # no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (ff39e6e47ea948b97d2587f2205c465fa789c5e9) [root@kai git_test]# git status # On branch dev # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: code.txt # no changes added to commit (use "git add" and/or "git commit -a") [root@kai git_test]#
小结:修复bug时,咱们会经过建立新的bug分支进行修复,而后合并,最后删除;当手头工做没有完成时,先把工做现场git stash一下,而后去修复bug,修复后,再git stash pop,恢复工做现场。