背景
git作为目前使用最广泛的分布式版本控制软件,集团内基本上所有开发同学都使用它来做代码管理。
一个最典型的使用场景,是一个git仓库存在一个master主干分支,多个需求基于master拉自己的开发分支,然后在发布日时,新建一个release分支,然后原先并行的几个开发分支merge到release分支上,最后基于该分支发布上线,上线后release再merge到master主干上,一次发布完成。
但由于每位开发同学对git的掌握程度不一,可能对git使用不当,导致某次提交丢失了部分曾经已经在git仓库的代码,最后该分支发布上线后造成故障。并且这种丢代码情况在代码改动量本身就很多的时候,往往比较隐秘,并且如果丢失的代码不在本次变更的范围内,测试回归时可能也就不会涉及到,结果就是只有在线上真正发生故障时才意识到问题。
所以这里梳理了一下有哪些不当使用git可能会导致代码丢失的场景,防止踩坑。如果有遗漏的其它场景,也请留言补充。
场景梳理
1)强制Push
触发场景
在多人并行开发同一个分支时,某人写完代码,git push,如果此时该分支已经也被别人改过且push过了,则会提示这个信息:
此时不熟悉git的同学,可能会通过加 -f 参数,强制push:
git push -f origin branchA
或者在IDEA里面,选择了Force Push:
这样之前别人已经push的代码,就被丢掉了(因为将会以你本地非最新的代码为准)。
正确操作
push代码遇到本地不是最新时,不要强制push!务必先git pull拉最新代码,如果遇到冲突则解决冲突,解决完再git push。
2)Merge时错误处理冲突
触发场景
在自己的分支上开发,然后需要将其它分支(例如master)的代码merge过来时,遇到了代码冲突,此时处理完冲突后,push代码,如果没有发生冲突的其它分支文件,没有同时也勾选push的话,则代码也会丢失。
例如下面的例子:
-
在dev分支上修改了Tester.java文件和其它内容,merge master提示其中Tester.java有冲突;
-
处理完Tester.java的冲突后,在IDEA里面准备push代码,此时展现了有修改的文件列表(如下图)。此时列表内不仅有自己在dev分支里面修改的代码,还有被合并过来的分支(master)修改的文件(图中ClassA和ClassB)。
-
此时正确操作,是必须要把ClassA和ClassB 这些master上修改的文件内容,也勾选上。 如果未勾选,而只勾了自己在dev上修改的文件,再去push,则此时master上这些修改的代码会丢失。
正确操作
merge后遇到冲突,解决完冲突后,不要部分提交!push时务必把所有修改文件都勾选,再push。
这个对于IDEA这种图形化界面容易犯错。对于命令行,其实merge冲突后,未冲突的文件,是默认已经放入暂存区了,所以git push时这些未冲突文件就会一起被正确push上去。
3)错误使用Merge
触发场景
有的时候可能遇到这种情况:自己的开发分支,需要将其他开发分支上的改动merge过来,但是只需要其中部分功能,此时如果使用git merge的话,就可能会存在问题。
例如下面这个例子:
主干Master上有两个文件:fileA和fileB。其中fileA的内容是AAA,fileB的内容是BBB。最新的CommitId是M1;
-
张三基于Master,拉了一个分支:Dev1,其最新CommitId是G1,其中fileA和fileB的内容没有变更;
-
李四也基于Master,拉了一个分支:Dev2,其最新CommitId是P1,其中fileA和fileB的内容也没有变更;
-
Dev1分支,做了一次commit,ID是G2,其中把fileA和fileB的内容都做了变更(fileA变成AAA1,fileB变成BBB1);
-
Dev2分支,希望能将Dev1的代码Merge过来,但只想要fileB的改动,而暂时不需要fileA的改动,于是他执行git merge Dev1,然后rollback了其中fileA的变化,提交,commitId为P2;
-
Dev1分支发布,代码被合并到了Master,此时Master的CommitId为M2,并且fileA和fileB内容都以Dev1的G2为准(即fileA是AAA1,fileB是BBB1);
-
Dev2继续开发,然后等Dev2自己也准备要发布了,于是他执行git merge master合并最新主干代码(CommitId是P3)。此时他以为fileA的内容会被改成AAA1,因为Master上就是AAA1,但其实因为之前merge Dev1时,fileA被自己人工改过了,所以会以自己版本为准,即实际内容还是AAA。此时Dev2的代码已经有问题了;
-
最后Dev2分支发布,代码被合并到了Master,其CommitID是M2,其中fileA的内容也在主干里面被丢失了,导致故障。
正确操作
出问题的点在Dev2的Commit P2。对于这种希望将其它分支上的部分改动(例如某几个commit)移动到自己分支上的情况,强烈建议是不要使用git merge,而是使用cherry-pick将这几个commit合并过来。
预防策略
目前能做的更多还是在机制上做兜底。典型的就是在发布前,发布分支和master做diff。在这个环节里,不再关心需求代码写的怎么样(这个是之前CR时做的),而是只关心Diff出来的内容,是否是我们要的,特别是diff出来被删除/修改的逻辑,确认是否是发布的业务需求逻辑。如果不是,或者没人知道这部分逻辑是谁改的为啥改,那就有问题,可能是之前Merge时丢代码了。