分支就类似于平行空间,当年在学习C++的时候,另一个你正在另外一个平行宇宙里学习JAVA。如果两个平行宇宙互不干扰,那对现在的你没有影响。在某个时间点,两个平行宇宙合并了,结果就是,你既学会了C++也学会了JAVA
从上一篇《版本回退》中我们知道了,每次提交,Git都把他们串成一条时间线,这条时间线就可以理解为一个分支。在每个git仓库中默认会创建一个master分支,即主分支。
HEAD严格来说不是指向提交,而是指向当前分支(现在是master分支),master分支才是指向提交的。每次提交,master分支都会向前移动一步,这样随着你不断提交,master分支的线也越来越长,而HEAD只要一直指向master分支即课指向当前分支。
Git支持我们查看或创建分支,咱们创建一个dev
分支。
另外,我们还可以通过目录结构查到新的dev
分支
发现dev和master打印出来的commit id一样,说明dev和master都指向同一个修改。
使用git checkout
命令即可完成分支切换
接下来,在dev
分支下修改file1文件,新增一行内容,并进行一次提交操作。
现在切换回master
分支,查看file1内容
切换回master分支后,发现file1文件中新增的内容不见了。这是为什么呢?让我们看看master
分支和dev
分支的指向,发现两者的指向的提交不一样。
这是因为新增内容是我们在dev分支上提交的,而master分支此刻的提交点并没有改变,状态图如下:
当切换到master分支时,HEAD指向master,当然看不到在dev分支上的提交了。
如何让master分支也能看到dev分支上的提交呢?这就需要将dev分支合并git merge
到master分支。
git merge
命令用于合并指定分支到当前分支,合并后,master分支就能看到dev分支提交的内容了。状态图如下:
Fast-forward快进模式:直接把master分支指向dev分支的当前的提交,所以合并速度非常快。
合并结束后,dev
分支对于我们来说已经失去作用了,那么dev
分支就可以被删除了。使用的命令是git branch -d
注意:如果当前正处于
dev
分支上,是不能删除dev
分支的,要在其他分支上才可以
此时状态图如下:
由于创建,合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删除分支,这和直接在master分支上工作效果是一样的,但过程更安全。
在实际分支合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。为了演示这个问题,咱们创建一个dev
分支,使用git checkout -b dev
一步完成创建并切换到dev的操作。
在dev
分支下修改file1
文件,并进行一次提交
接着在master
分支对file1
进行一次修改,并提交。
现在master
分支和dev
分支各自都有新的提交,状态图如下:
现在将dev分支合并到master分支上,就会发生冲突
此时我们需要手动调整冲突代码,并需要重新提交修正后的结果!
此时状态图如下:
使用git log --graph --pretty=oneline --abbrev-commit
可以查看到分支的合并情况。
最后,合并完成后记得把dev
分支删除掉
当正常合并分支时,Git采用Fast forward
模式。删除dev
分支后,查看分支历史时,会丢掉分支信息,看不出来这次提交是merge进来的还是正常提交得到的。当合并冲突部分时,我们能看到通过解决冲突问题,再进行一次新的提交的过程。能看到合并过程的就不是采用Fast forward
模式了,好处很明细,可以从分支历史上看出分支信息,例如我们现在已经删除了在合并冲突部分创建的dev
分支,但依旧能看到master
其实是由其他分支合并得到的。
Git支持我们强制禁用Fast forward
模式,那么就会在merge时生成一个新的commit,这样从分支历史上就可以看出分支信息了。使用的命令是--no-ff
合并完成后删除dev
分支,再查看分支历史
假如我们现在正在dev
分支上进行开发,开发到一半,突然发现master
分支上有bug,需要解决。在Git中,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
问题是
dev
分支在工作区开发了一半,还无法提交,怎么办?
Git为我们提供了git stash
命令,可以将当前工作区的内容进行存储,被存储的内容可以在将来某个时间恢复出来。
存储dev
分支之后,由于我们要基于master分支修复bug,所以需要切换回master
分支,再新建临时分支来修复bug。
修复完成后,切换到master
分支,并完成合并,最后删除fix_bug
分支
至此,bug的修复工作已经做完了,我们还要回到dev
分支继续开发。首先就是恢复现场,使用git stash pop
命令,恢复的同时也会把stash删除掉。接着使用git stash list
命令发现现场已经恢复干净了
补充:恢复现场还可以采用
git stash apply
恢复,但是恢复后,stash内容不会被删除,需要用git stash drop
删除。
你也可以多次stash
,恢复的时候,先用git stash list
查看,然后恢复指定的stash,使用命令git stash apply stash@{0}
恢复完代码就可以继续开发,开发完成也会便可以进行提交
此时的状态图如下:
在dev
分支上,在fix_bug分支修复完bug的内容,并没有在dev
上显示。此时master
分支的最新提交,是领先于新建dev
分支是基于master
分支的提交的,所以我们在dev
分支上看不见修复bug的相关代码。
我们的最终目的是要让master
合并dev
分支的,那么正常情况下是切换到master
分支进行合并的,但是这样存在一定风险。因为合并分支时可能发生冲突,而代码冲突需要我们手动解决(在master分支上解决)。我们无法保障对于冲突问题可以正确的一次性解决,因为在实际项目中,代码冲突不只是一两行代码,解决过程中难免手误出错,导致错误代码被合并到master
分支上。状态图如下:
正确的解决方案是:在dev
分支上合并master
分支,再让master
分支去合并dev
。这样做的目的是有冲突可以在本地dev
分支上解决并进行测试,而不影响master
分支。此时的状态图如下:
对应的代码如下:
添加?个新功能时,你肯定不希望因为?些实验性质的代码,把主分?搞乱了,所以每添加?个新功能,最好新建?个分?,我们可以将其称之为 feature 分?,在上?开发完成后,再合并,最后删除该 feature 分?。
可是,如果feature
分支开发了一半,被产品经理叫停,说要停止新功能的开发。这时候就要把feature
分支销毁掉,这时使用传统的git branch -d
命令删除分支的方法是不可行的。
根据他的提示,咱们使用git branch -D
命令删除已经提交过的分支