1. 问题背景

A 页面的代码莫名其妙消失了,而且不清楚是什么时候被删的。

6e2827b3b0226a09de7921483bbe8bcf.png

4bfd1648d1466b5f86e704d81403ca67.png

发现这个问题之后,心里除了一句“草泥马”以外,也萌生了很多疑惑。比如说,团队在代码上线前,是有 CR 流程的,为什么这个代码消失的 commit 会逃过这么多高工的法眼?

我们希望能找回代码,并查出是哪次 commit 涉及到的,进而找出操作过程,以防后续再有人出现类似操作。

2. 处理方式

2.1 通过 git log 查找出修改过指定文件的 commit

目前文件已经被删除了,但是根据项目的代码结构,可以推测出原本是存在 A/index.js 这个文件的。

尝试检测一下在所有历史记录中,对该文件的处理,用到的命令如下:

git log --stat --full-history --simplify-merges -- A/index.js

3a62ba19303cb29a8f373759949e1620.png

上述命令将会展示涉及到该文件更改的 commit,从输出结果我们可以看到,在 fix:1 这个 commit 中,删了 200 行代码,而之后就再没有 commit 处理过该文件了,所以可以推测文件就是在这个 commit 中被删除了。

然后通过 git checkout 6df716248794c3c54873f73002b8bd0854ac0805,去到删除操作前最后修改过该文件的的 commit,即可拿到被删除前的代码了。

2.2. 解释一下命令及每个参数的作用

2.2.1. git log 查看对指定文件修改过的commit
git log -- A/index.js

只使用上述命令去查找文件历史,会存在一个问题:如果文件目前不存在,则什么记录都没有。

e85717d21683c4b29c714641ae003aeb.png

既然如此,我们先把代码恢复,再看看会展示什么:

b4f02dca9a991ebe6cf403081e224af0.png

上图可以看到,只有恢复之后的那次 commit 的记录。删除代码、以及删除代码前对该文件的所有 commit 都不会展示出来。这又是为什么呢?

这是因为 git log 的一个默认策略:

bd6cb98a961c0e1ea0acfdf2b1404133.png

也就是默认模式下,git log 会简化文件历史,如果一些分支合起来看之后的结果是相同的,就不会展示这些分支。

因为之前对这个 index.js 文件从新建到删除,中间的所有 commit 合起来看是相互抵消的(因为文件最后被删除了,相当于没有新建过),所以单单输入 git log 指令,什么也看不到。即使代码被恢复后再输入 git log 指令,也只会展示恢复代码的那次 commit。

2.2.2. --stat 生成差异统计

git log 默认情况下不会生成文件差异:

95aecf427b203b9da7dc6e73b373b471.png

加了 --stat 参数,即可生成文件差异的统计,执行以下命令:

git log --stat -- A/index.js

6b6ded4046f4379f2abfcf9a85e968f7.png

对比没加 –stat 参数的结果,可以看到多输出了文件的变更记录,具体到变更了多少文件、多少行代码。

2.2.3. --full-history

由 2.2.1 的介绍可知,git log 的默认模式是会简化文件历史的。为此,我们需要加上 --full-history 这个参数,去掉这个简化的功能。

19ab69f3239b8a4533b757c8cad45bf3.png

执行以下命令:

git log --full-history -- A/index.js

8f2f441f3ae199344217e6de18e43add.png

对比 2.2.1,可以看到加了 --full-history 参数的输出结果没有进行简化,所有处理过该代码的 commit 都展示出来了。

2.2.4. --simplify-merges

--simplify-merges 可以增强 --full-history 的能力,因为 --full-history 会把一些无用的合并 commit 也输出出来(可以看 2.2.3 中的 commit 信息,有一些是 Merge branch xxx),增加 --simplify-merges 参数可以去除这些无用的 commit 信息。

077e7295d4599021eb8e8a06405220c1.png

执行以下命令:

git log --full-history --simplify-merges -- A/index.js

bcfd03bbc8d06a60d4e5736e6a0e34eb.png

对比 2.2.3 中的输出结果,可以看到已经没有 Merge branch xxx 的 commit 了,这里展示的每个 commit 都是实实在在对指定文件进行了修改的。

再加上 --stat 参数输出文件的差异信息,最终可以得出我们前文使用到的查询指令:

git log --stat --full-history --simplify-merges -- <path>

3. 分析原因

3.1 为什么代码被删除了,CR 时却没有发现,仍能合到主干?

从上面的分析可以知道,代码是在 fix:1 这个 commit 中被删除的。而在工蜂(公司内类似 gitlab 的代码管理平台)中,根本就没有记录显示代码被删除。

9af838758bbd1f975da2d3ae20adb4a4.png

我们使用 git show 命令来看下该 commit 的更改内容:

6e4c995913837aa2299381cdeff09057.png

结果发现没有显示任何文件更改。

这就是 CR 时没有发现问题的原因了,因为删除代码的记录根本就没有出现在工蜂上,所以没人知道这些代码被删除了。

3.2 为什么工蜂和 git show 无法展示该 commit 的记录呢?

3.2.1 工蜂的结论

20c0f96d6ffa34cab00b477b7b6ab92b.png

到底是不是因为这个原因呢?实践出真知,我们用一个例子去试一下:

在一个项目内,模拟两个分支在同时进行开发,在分支 A 新增了文件 new2.js,且修改 const.js。

新建 new2.js 如下:

3715241cf6c9e2cf4e7ba60ebf33e2d2.png

修改 const.js 如下:

a2b13f9a187414a7f94211331769a98e.png

然后分支 B 再修改了 const.js:

486eeaf836e427b924d6c0c53bb12195.png

分支 B 在 push 的时候,则需要处理一下冲突文件了。

此时我们关注到暂存区里的 new2.js:

6cf04eb95f2f2488c56fef4e69058833.png

如果在此时把 new2.js 从暂存区里剔除,冲突选择 Current Change,再提交代码,就能成功复现工蜂不展示代码被删的问题了。

4dc5614a2924e630e86974efe9366f8e.png

如果去 VSCode 上看,还是可以看到代码被删除的:

6fe9b44c682bc06a12beae6fb7091ae0.png

3.2.2 分析一下

8f4b7b7bd01a005b6be612add2198680.png

合并后,项目的主干路径变为了红色的三个点,相当于 A 分支的两个修改都被 B 分支的 merge 操作覆盖掉了(新文件剔除出暂存区、冲突选择分支B部分)。最终 fix:fix1 节点相对于分支 B 的最新节点没有变化,故工蜂中 fix:fix1 节点显示没有文件变化。在分支 A 里新增的 new2.js 文件,相对于合并后的主干代码来说,就像从来没有出现过一样,所以在合并分支的节点中就不会有它被删除的记录。

回到丢失代码的项目里,打开 VSCode 的 git 管理模块查看该 commit:

3ea88e7b3e2f43aff6a555386c9bb17a.png

能够看到是修改了很多文件的,其中就有删除 A 页面代码的记录,和我们例子的表现一致。

所以可以证明工蜂说的没错,应该是当时操作者在合并代码时,不知因为什么原因,把 A 页面代码剔除出了暂存区,最终导致 A 页面的代码像消失了一样。

4. 预防措施

目前发现代码被删除是被动的,也就是需要去找这些代码时,才能发现代码不见了,这也是代码被删了 8 个月才被发现的原因之一。

所以我们希望能够化被动为主动,通过程序去帮助开发者提前发现这些问题,而不是在需要用到这些代码的时候,才发现代码已经没了,时间久了再排查、恢复都比较困难。

因此可以考虑实现一个 主干检查程序,将手动的处理方式改为使用代码逻辑去实现,然后每隔一段时间触发一次,检查有无类似的情况发生,能够做到出现类似情况发生后及时通知到开发者。


最后

  • 欢迎加我微信,拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

27a2265b760db60568863970b80695d9.png

5f745a0d0b46d12a15d5b28fc5093cda.png

点个在看支持我吧

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐