目录
[二、查看、创建分⽀(git branch)](#二、查看、创建分⽀(git branch))
[三、切换分支(git checkout,git checkout -b)](#三、切换分支(git checkout,git checkout -b))
[四、合并分支(git merge、git log查看合并情况)](#四、合并分支(git merge、git log查看合并情况))
[五、删除分支(git branch -d [])](#五、删除分支(git branch -d []))
[六、合并冲突(git log)](#六、合并冲突(git log))
[七、分支管理策略(Fast forward、--no--ff、git log --graph --pretty=oneline --abbrev-commit)](#七、分支管理策略(Fast forward、--no--ff、git log --graph --pretty=oneline --abbrev-commit))
[九、bug分支(git stash、git stash list、git stash pop)](#九、bug分支(git stash、git stash list、git stash pop))
一、分支是什么
在版本回退⾥,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即master分⽀。
再来理解一下HEAD,HEAD严格来说不是指向提交,而是指向master。
每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓,⽽ HEAD只要⼀直指向master分⽀即可指向当前分⽀。
通过查看当前的版本库,我们也能清晰的理出思路:
二、查看、创建分⽀(git branch)
Git⽀持我们查看或创建其他分⽀,在这⾥我们来创建第⼀个⾃⼰的分⽀dev,对应的命令为:
查看分支
git branch
创建分支
git branch [分支名]
例:
当我们创建新的分⽀后,Git新建了⼀个指针叫dev,*表示当前HEAD指向的分支是master分支。
同时,通过目录结构也可以发现,新的dev分支。
发现⽬前dev和master指向同⼀个修改。并且也可以验证下HEAD⽬前是指向master的。
总结:
三、切换分支(git checkout,git checkout -b)
git checkout
可以发现HEAD已经指向了dev,就表⽰已经成功的切换到了dev上!
接下来,在dev 分⽀下修改test⽂件,新增⼀⾏内容,并进⾏⼀次提交操作:
再切换回master,查看分支
会发现新增内容不见了,此时可以看看master分支指向,发现两者指向的提交不一样:
因为在dev上进行的提交,而master分支的提交点并没有发生改变,此时的状态:
git checkout -b []创建分支并切换到新的分支上
四、合并分支(git merge、git log查看合并情况)
为了在master主分⽀上能看到新的提交,就需要将dev 分⽀合并到master 分⽀,⽰例如下:
git merge命令⽤于合并指定分⽀到当前分⽀。合并后,master就能看到dev分⽀提交的内容了。此时的状态如图所示:
Fast-forward代表"快进模式",会直接把master指向dev的当前提交,所以合并速度⾮常快。
并不是每次合并都能Fast-forward。
五、删除分支(git branch -d [])
合并完成后,dev分⽀对于我们来说就没⽤了,那么dev分⽀就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀,如:
因为创建、合并和删除分支非常快,所以Git鼓励使用完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
六、合并冲突(git log)
在实际分⽀合并的时候,有时候可能会遇到代码冲突的问题。
例:
现在mater和dev分支都有各自新的分支了,因为都进行了提交。(可以对比第三点和第四点进行查看)
这种情况下,Git只能试图把各⾃的修改合并起来,但这种合并就可能会有冲突,如下所⽰:
我们再来查看一下test
发现⽂件有冲突后,Git会⽤<<<<<<<,=======, >>>>>>>来标记出不同分⽀的冲突内容。
此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘 记)
到这⾥冲突就解决完成,此时的状态变成了
git log
⽤带参数的git log也可以看到分⽀的合并情况:
最后,不要忘记dev分⽀使⽤完毕后就可以删除了:
七、分支管理策略(Fast forward、--no--ff、git log --graph --pretty=oneline --abbrev-commit)
通常合并分⽀时,Git会采⽤Fast forward 模式。采⽤ Fast forward 模式之后,形成的合并结果是?
在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提交到底是merge进来的还是正常提交的。
但在合并冲突部分,也能看到通过解决冲突问题,会再进⾏⼀次新的提交,得到的最终状态为:
那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。例如现在已经删除了在合并冲突部分创建的 dev 分⽀,但依旧能看到master其实是由其他分⽀合并得到:
Git⽀持强制禁⽤ Fast forward 模式,(--no--ff)就会在merge时⽣成⼀个新的 commit ,这样, 从分⽀历史上就可以看出分⽀信息。
git merge --no-ff -m "" [分支名]
注意--no--ff,表示禁用Fast forward模式。禁用Fast forward后合并会创建一个新的commit,所以加上-m参数,把描述写进去。
合并后,查看分⽀历史:
git log --graph --pretty=oneline --abbrev-commit
可以发现,不使用Fast forward模式merge后会像这样:
所以在合并分⽀时,加上 --no-ff 参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾经做过合并,⽽ fast forward 合并就看不出来曾经做过合并。
八、分支策略
在实际开发中,应该按照⼏个基本原则进⾏分⽀管理:
⚠️⾸先,master分⽀应该是⾮常稳定的,也就是仅⽤来发布新版本,平时不能在上⾯⼲活;
建议干活都在分支上进行,也就是说dev分支没有那么稳定,等稳定版本出来后,再把dev合并到master上。在实际项目中,每个人都有自己的分支,时不时往一个分支合并就行。
九、bug分支(git stash、git stash list、git stash pop)
假如现在正在dev分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有bug,需要解决。在Git中,每个bug都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。
可是现在dev的代码在工作区中只进行开发了一半,还是不能提交:
可以看见checkout到master显示test修改了(modify)
Git提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时间恢复出来。
而存储位置则是在:
多了一个stash,再看工作区就是干净的,(除⾮有没有被Git管理的⽂件),因此可以放⼼地创建分⽀来修复bug。
储藏 dev ⼯作区之后,由于我们要基于master分⽀修复bug,所以需要切回 master 分⽀,再新
建临时分⽀来修复bug,⽰例如下:
前面说git branch可以创建分支,那么这里顺带演示前面第三点所说的git checkout -b[]创建并切换到该分支
修复完成后,切换到master分⽀,并完成合并,最后删除fix_bug分⽀:
⾄此,bug的修复⼯作已经做完了,我们还要继续回到dev 分⽀进⾏开发。切换回dev 分⽀:
可以发现工作区是干净的,那么刚才的工作内容呢?(git stash list命令)
⼯作现场还在,Git把stash内容存在某个地⽅了,需要恢复⼀下,可以使
⽤git stash pop 命令,恢复的同时会把stash也删了,⽰例如下:
再次查看的时候,我们已经发现已经没有现场可以恢复了
另外,恢复现场也可以采⽤git stash apply 恢复,但是恢复后,stash内容并不删除,你需要
⽤git stash drop 来删除;
你可以多次stash,恢复的时候,先⽤git stash list 查看,然后恢复指定的stash,⽤命令
git stash apply stash@{0} 。
恢复完代码之后我们便可以继续完成开发,开发完成后便可以进⾏提交。
但我们注意到了,修复bug的内容,并没有在dev 上显⽰。此时的状态图为:
Master 分⽀⽬前最新的提交,是要领先于新建dev 时基于的master 分⽀的提交的,所以我们
在dev中看不⻅修复bug的相关代码。
我们的最终⽬的是要让 master 合并 dev分⽀的,那么正常情况下我们切回master 分⽀直接合并即可,但这样其实是有⼀定⻛险的。是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单, 有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免手误出错,导致错误的代码被合并到master上。此时的状态为:
解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并 dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态为:
对应的实操演示如下:
首先dev合并master,会发现发生了冲突
解决冲突重新提交,再切回master,再进行合并分支,最后删除分支
十、删除临时分支
软件开发中,总有⽆穷⽆尽的新的功能要不断添加进来。 添加⼀个新功能时,不希望因为⼀些实验性质的代码,把主分⽀搞乱了,所以,每添加⼀个新功能,最好新建⼀个分⽀,我们可以将其称之为feature 分⽀,在上⾯开发,完成后,合并,最后,删除该 feature 分⽀。
可是,如果我们今天正在某个feature分⽀上开发了⼀半,被突然叫停,说是要停⽌新功能的开发。虽然⽩⼲了,但是这个feature 分⽀还是必须就地销毁,留着⽆⽤了。这时使⽤传统的 git branch -d 命令删除分⽀的⽅法是不⾏的。演⽰如下:
创建并切换到feature分支,开发新功能
提交后被叫停,准备切回主分支删除feature分支
就会发现常规方法删不了,需要使用git branch -D