前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【消失的代码】Git 合并分支导致代码消失

【消失的代码】Git 合并分支导致代码消失

作者头像
用户1097444
发布2022-06-29 15:05:52
3.7K0
发布2022-06-29 15:05:52
举报
文章被收录于专栏:腾讯IMWeb前端团队

1. 问题背景

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

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

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

2. 处理方式

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

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

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

代码语言:javascript
复制
git log --stat --full-history --simplify-merges -- A/index.js

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

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

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

2.2.1. git log 查看对指定文件修改过的commit
代码语言:javascript
复制
git log -- A/index.js

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

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

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

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

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

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

2.2.2. --stat 生成差异统计

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

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

代码语言:javascript
复制
git log --stat -- A/index.js

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

2.2.3. --full-history

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

执行以下命令:

代码语言:javascript
复制
git log --full-history -- A/index.js

对比 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 信息。

执行以下命令:

代码语言:javascript
复制
git log --full-history --simplify-merges -- A/index.js

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

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

代码语言:javascript
复制
git log --stat --full-history --simplify-merges -- <path>

3. 分析原因

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

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

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

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

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

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

3.2.1 工蜂的结论

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

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

新建 new2.js 如下:

修改 const.js 如下:

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

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

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

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

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

3.2.2 分析一下

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

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

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

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

4. 预防措施

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

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

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

紧追技术前沿,深挖专业领域

扫码关注我们吧!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题背景
  • 2. 处理方式
    • 2.1 通过 git log 查找出修改过指定文件的 commit
      • 2.2. 解释一下命令及每个参数的作用
      • 3. 分析原因
        • 3.1 为什么代码被删除了,CR 时却没有发现,仍能合到主干?
          • 3.2 为什么工蜂和 git show 无法展示该 commit 的记录呢?
            • 3.2.1 工蜂的结论
            • 3.2.2 分析一下
        • 4. 预防措施
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档