Whoosy's Blog

藏巧于拙 用晦而明 寓清于浊 以屈为伸

0%

失踪人口回归之首谈Git丢失代码

元旦假期,无所事事,只能在家里刷刷b站,打打LOL,回想起这半年工作上的事项,也是挺唏嘘的,996已成常态,好在项目最终验收,至少几个月努力没有白费。
突然想起将近1年多没写文章了,主要是工作行业上有些变动,新的工作涉及一些新的领域 - git代码研发管理,所以在这块上投入了大量的时间进行行业、技术的研究。

废话不多说,直接进入重点。

近半年来,除了负责gitee主线正常的迭代外,还插手交付几家银行类的私有云大客户的事项,当时交付后不少用户频繁遇到此问题,虽然现象千奇百怪,但是无非是错误的操作导致的代码丢失,作为研发人员,应该关注这一类误操作的普及和说明,所以输出一篇文章,作为组内内部分享,让大家都能处理好此类问题。

“这个PR合并之后,我们的这个分支代码就丢失了一部分,你们靠不靠谱啊?!?!??”
“你们gitee怎么搞的!我们代码又莫名其妙丢了!”
“昨天代码提交之后,今天早上就看不到提交了,能帮我查查原因吗?”
“为什么bitbucket能看到冲突的代码,你们gitee看不到呢?”
“这些提交为什么出现在我们的发布分支上了,今晚我们要发版,麻烦查查”

每当收到这些反馈,我都非常紧张,紧张并不是因为Gitee真的有什么问题,而是在想怎么去跟用户去解释,怎么帮用户复现、处理问题。
有些私有云客户已经交付了将近一年,收到的此类反馈数不胜数,但是归根究底,造成这些现象的根源还是在于对Git的不熟悉,分支研发流程不规范,对自己git操作后的结果没有预期。其实这类丢失代码的情况,无外乎以下2种情况:

  • 使用 Git 进行推送的时候进行了强推操作
  • 不正确的Merge操作造成的文件版本回退

No.1 强推操作

在推送的时候往往会遇到远程仓库的版本领先于自己本地的版本,这个时候如果我们执行推送操作,就会看到 Git 给到我们的提示:

git-1

这个时候很多刚接触Git的新手看到error就会懵掉,甚至根本都不会去看提示,就会去网上搜

于是很兴奋的发现找到了解决方案
git-2

跟着答案在命令行加上了 -f 参数,或者图形化界面选中了 Force,然后进行推送,发现居然成功了,但是却苦了我们这些项目技术支持了,不出意外,过段时间就有人来群里面找我了。
git-3

“怎么我刚推的代码又没了,什么情况”
“谁把我代码覆盖了!”

幸好,为了甩锅,我们产品在动态里面加入了判断是否是强推的记录

git-4

没错,就是-f的问题,加了这个参数就是强制推送,如果在命令行推送的时候加了 -f
的参数,或者在图形化界面选择了强制推送的选项,就会把远程的版本强制替换为自己本地的版本,而别人之前推送的提交如果不在自己本地的那个版本里,就会造成丢失的现象。

怎么解决这种问题呢,其实Git在操作的时候已经给出了提示:

git-5

没错,就是git pull,先拉取远端仓库最新提交合并,这样可以保证本地代码除了你的提交,其他代码和远端保持一致,这样就可以重新推送不会覆盖远端的代码,当然这时候会产生一个merge节点,也可以使用rebase命令进行合并。

当然,最好的方式就是禁止强制推送,目前 Gitee 平台支持设置仓库禁止强推,从源头避免强推导致的各种问题。

No.2 不正确的Merge操作造成的文件版本回退

这类情况是最多了,导致的现象也是各不相同,挑一个范围最广的例子。

在开发过程中,文件之间的冲突是不可避免的,所以经常会遇到 Git 不能够自动合并的情况,所以我们需要自己进行代码的合并。
正常情况下,我们会对冲突的文件进行内容上的修复,并且在确认修复完成后提交到暂存区,通过提交合并的方式创建一个合并的提交,完成本次合并即可,过程如下图:

git-6

稍微对上图做些说明:

从第4个提交开始,我们衍生出了dev分支进行分支开发
同时master分支也有相应的提交
dev分支上做了7、8两次提交,分别在b.txt文件新增了第六行L6和第七行L7
同时master分支上也做了5、6两次提交,在a.txt新增了第九行L9,分别在b.txt文件新增了第六行L5和第七行L6
然后dev分支合并到master分支,由于两个分支都新增了b.txt文件的第六行L6,所以需要进行冲突合并,得出合并后的b.txt文件的第六行L6
最后,执行 git add . && git commit -m “merge dev into master” 等操作完成本次合并,生成第9次提交 推送到远端的master

整个过程是常规的合并操作,是一种标准实践了,但是上线的那天晚上,当团队复核代码的时候发现,最新版本的a.txt的L9变更不见了!

“有人覆盖了 a.txt 代码?”
“@我,帮忙看看我们团队投产的时候,发现有一些代码不见了,紧急!”
….

现场看起来是这样的:
git-7

我记得排查这个问题的时候也觉得非常诡异,后来才发现这种问题的复现方式,还是通过现场反向推断出来的,因为后来发现做合并提交9的这位同事使用的是图形化工具,于是在模拟了他的一系列操作之后,终于发现了端倪,原因是因为:
在处理完冲突进行合并的时候,并未选中所有的文件,这些未选中的文件就被回退到被合并的分支的版本,而命令行没问题是因为默认无冲突的文件都被添加进暂存区了!
命令行合并的时候我们关注的都是冲突的文件,并不会人为的去变更默认加入暂存区的文件,所以一般情况下不会出问题,那么图形化工具在合并的时候这种问题就会被暴露出来。

解决方式

解决方式就比较简单了,在进行合并的时候,无论是使用命令行还是图形化界面,一定注意不要对暂存区的文件进行操作,除非你非常清楚的知道你在做什么,否则在处理完冲突之后,请确保添加了所有未冲突的文件以及解决了冲突的文件到暂存区!