Git 的原理与使用(中)(一)+ https://developer.aliyun.com/article/1521951?spm=a2c6h.13148508.setting.14.439a4f0e3zzkc2
补充:查看分支合并的情况
用带参数的 git log
命令可以看到分支的合并情况:
命令:git log --graph --abbrev-commit
上图中,星号 * 代表的就是之前的“提交(commit)”。
最后,不要忘记dev1分支使用完毕后就可以删除了:git branch -d dev
8.分支管理策略
Fast Forward 模式(ff模式)
通常合并分支时,如果可以,Git 会采用 Fast forward 模式。
Fast forward 模式形成的合并结果:
在Fast forward模式下,当我们合并分支后查看分支历史时,分支历史的展示中会丢失部分分支信息,即看不出来最新的提交到底是merge进来的还是正常提交的。
非Fast Forward模式(no-ff模式)
我们知道,当发生合并冲突时,在解决冲突问题后还需要再进行一次新的commit,然后才能得到最终状态:
这里就不是 Fast forward 模式了。
在非 Fast forward 模式中,从分支历史上是可以看出分支信息的。例如我们现在已经删除了在合并冲突部分创建的 dev1 分支,但依旧能看到 master 其实是由其他分支合并得到的:
如何在正常提交的时也选择no-ff模式呢?
Git支持我们强制禁用fast forward,那么就会在 merge 时生成⼀个新的 commit 。这样,从分⽀历史中就可以看出分支信息。
在执行 git merge 时添加 --no-ff 选项,就表示不使用ff模式。--no-ff选项表示的就是禁用 Fast forward 模式。禁用 Fast forward 模式后,在合并分支后会创建一个新的 commit ,所以要加上-m参数,把描述(message)也写进去:
由下面的图可知,在no-ff模式下生成一个新的commit,最终master也会指向一个新的提交:
ff模式和no-ff模式最大的区别是,用 git log --graph --abbrev-commit
命令查看提交日志时,能否区别出git的master中的每个commit是merge进来的还是正常提交的。
(在企业实操中一般更建议使用no-ff模式。)
9.分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活。
干活都在dev分支上。(dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本)。
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
10.bug分支
假设我们现在正在 dev2 分支上进行开发,开发到一半还没提交,突然发现 master 分支(即线上环境的代码)上有严重的 bug(如闪退之类的),需要马上解决。
直接在master主分支上编辑代码进行bug修复,这肯定是不可以的。
安全起见,必须遵守分支的策略,即在本地创建一个新的临时分支来修复,修复后,经过测试团队的测试后将稳定的代码合并到master分支,然后将临时分支删除。
可现在dev2的代码在工作区中开发了一半,还无法提交,而要修复master中的bug怎么办?
dev2中的修改都在工作区中,dev2在工作区中的做的修改会影响在其余分支的工作区进行工作。此时就需要先对dev2工作区中的内容进行保存。Git 提供了
git stash
命令,可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来:
执行完git stash
命令后,tree ./git
,可以查看到当前git目录下多了一个stash目录,dev2的修改就被存储在这个stash目录中:
git stash
后用git status
查看工作区,工作区是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复bug:
注意,如果工作区还有没被 git 管理起来的文件,则该文件不能被暂存起来:
储藏dev2工作区之后,由于我们要基于master分支修复bug,所以需要切回分支,再新建临时分支来修复bug,示例如下:
修复完成后,切换回master主分支,并将bug分支合并到master分支,最后删除bug分支即可:
至此,针对master主分支上的bug修复工作(即:切回主分支,拉一个bug_fix新分支,在bug_fix上修复完bug后再合并到master这样的一系列操作)已经做完了,我们还要继续回到dev2分支进行一开始未完成的内容的开发。
切换回dev2分支:
在dev2分支下检查 git status
会发现,工作区是干净的:
hyb@bite:~/gitcode$ git status On branch dev2 nothing to commit, working tree clean
可以用git stash list
查看stash存放哪些内容,使用
git stash pop
命令来恢复现场,恢复的同时会把stash中的内容删了,示例如下:
补充: 恢复现场除了 git stash pop, 也可以采⽤ git stash apply 。但是,用git stash apply恢复后,stash内容并不删除,需要我们自己调⽤ git stash drop 来删除。可以多次进行git stash,恢复的时候,先⽤ git stash list 查看,然后恢复指定的stash,⽤命令git stash apply stash@{0}即可。
再次查看stash中的内容,我们已经发现已经没有现场可以恢复了:
hyb@bite:~/gitcode$ git stash list # 没有内容显示
恢复完工作区的代码之后,我们便可以继续在dev2完成开发,开发完成后便可以进行提交:
但修复bug的内容并没有在 dev2 上显示。
为什么dev2下的ReadMe文件中,内容还是abcde而不是abcdef呢?这是因为创建dev2的时候,是基于还未修复的master的,也就是还有bug的master的。
此时的状态图为:
最终目的是要让 master 分支和 dev2 分支合并。正常情况下我们切回 master 分支,直接将dev2分支的内容合并到master中即可,但这样其实是有一定风险的。
因为在master分支与dev2分支合并时可能会发生冲突,而代码冲突需要我们手动解决(在 master 上解决)。我们无法保证对于冲突问题可以正确地一次性解决掉,因为在实际的项目中,代码冲突不只一两行那么简单,有可能几十上百行,甚至更多,解决的过程中难免手误出错,导致错误的代码被合并到 master 上。此时的状态为:
解决这个问题的一个好的建议是:先在自己的dev2分支上合并 master主分支,再让 master 去合并dev2分支。这样做的目的是,一旦有冲突可以在本地分支dev2上解决并进行测试,而不影响 master 。
此时的状态为:
实操演示如下:
最后执行 git branch -d ,将已经完成使命的dev2分支和bug_fix分支合并即可。
疑问解决
对于上述分支策略下的一系列操作,有的朋友可能会有疑问:dev2从master中拉出来的时候,ReadMe文件内容是abcde;但是master后来又拉了bug_fix分支,并把内容改成了 abcdef。如果工作区是共享的话,在bug_fix分支更改为abcdef的时候为什么没有影响到dev2分支呢?
原因:
abcdef已经提交了,属于版本库的内容,对于master来说,此时工作区是干净(clean)的,无变动。工作区是干净的,那么dev2分支的工作区也是干净的。git是基于提交来管理文件的,提交之前工作区共享。提交之后,提交的内容就已经被隔离了。
也就是说,如果bug_fix分支改成abcdef之后,没有进行add操作,那么bug_fix、master和dev2三个分支工作区的内容都会是abcdef;而如果bug_fix提交修改之后,工作区变成干净的,其他的分支的工作区也会变回原本的样子。
11.删除临时分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,我们肯定不希望一些实验性质的代码把主分支搞乱了。所以,每添加一个新功能,最好新建一个分支,我们可以将其称之为 feature 分支。在feature 分支上进行开发,开发完成后再合并,最后删除该 feature 分支。
可是,如果我们今天正在某个 feature 分支上开发了一半,被产品经理突然叫停,说是要停止新功能的开发。虽然白干了,但是这个 feature 分支还是必须就地销毁,留着无用了。
这时使用原来的 git branch -d 命令删除分支的方法是不行的。
之前之所以有可以用git branch -d删除分支的情况,是因为当时已经把分支和master主分支merge过了。而如果当前分支没有和master主分支merge过、且已在当前分支进行过一些提交的时,git是会在删除时保护当前分支的(git认为只要分支被创建出来了且在上面有过提交,那么这个分支就是有用的,不能随便删除)。
使用
git branch -D
命令则可以强制删除:
12.分支小结
分支在实际中有什么用呢?
假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样既安全,又不影响别人工作。
并且 Git 无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
六、远程操作
1.理解分布式版本控制系统
我们目前所说的所有内容(工作区,暂存区,版本库等等),都是在本地,也就是在你的笔记本或者计算机上。而我们的Git其实是分布式版本控制系统。什么意思呢?
可以简单理解为,我们每个人的电脑上都是一个完整的版本库,这样你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了。也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。有了这个“中央服务器”的电脑,这样就不怕本地出现什么故障了(比如运气差,硬盘坏了,上面的所有东西全部丢失,包括git的所有内容)。
Git 的原理与使用(中)(三)
+https://developer.aliyun.com/article/1521975?spm=a2c6h.13148508.setting.16.439a4f0eWJ4WIw