Git:如何排查非线性历史中被隐秘覆盖的修改(完整实战笔记)

在多人协作开发中,尤其是 i18n 文案文件(如 assets/locales/ja_JP.json)体量庞大时,某一段 key 被突然"消失" ,往往不是故意删除,而是:

  • 同事基于旧分支开发
  • merge commit 采取 ours/theirs 策略自动覆盖
  • 或 merge 的某个 parent 版本较旧,导致新 key 在另一个 parent 中被丢弃
  • 没有线性历史,GitLab UI 的 diff 不一定能看到

这个问题很隐蔽,但可以完全定位。

本文总结排查流程。

第一步:确认问题是否被覆盖(非故意删除)

我们要知道:

这个 Key 是 "被人写代码删掉" 还是 "merge 自动覆盖掉"?

使用:

bash 复制代码
git log -S "modbus_server" -p -- assets/locales/ja_JP.json

含义:

  • S 搜索文本出现/消失的位置
  • p 展示 diff

结果显示:

✔️ Key 的添加出现在最早的 commit

❌ Key 的删除并未以明显 diff 方式出现

→ 说明不是编辑删除,而是 merge 导致覆盖


2️⃣ 第二步:锁定 key 仍存在时的最后一个 commit

通过定位:

复制代码
2b86a183de12891ae463bcb941defb8a338d2046

这个版本中 key 仍然存在。


3️⃣ 第三步:查找它的直接 children

因为 develop 历史是非线性的,所以不能只看时间顺序。

使用:

css 复制代码
git rev-list --children develop | grep 2b86a183

输出:

erlang 复制代码
2b86a183 ... ce3ba83f ... f8e8dc155ae6...
80e7ca4386... 2b86a183...

含义:

  • commit 2b86a183两个 child

    • ce3ba83f
    • f8e8dc155ae6

只要找到哪个 child 删除了 key,就能定位元凶


4️⃣ 第四步:对比两个 child 与 parent

A. 对比第一个 child:

bash 复制代码
git diff 2b86a183..ce3ba83f -- assets/locales/ja_JP.json

输出明确显示:

✔️ modbus_server 整段内容被 删掉了

关键:这就是删除 key 的确切 commit!

B. 对比第二个 child:

复制代码
git diff 2b86a183..f8e8dc155ae6

没有涉及该 key

→ 不是它的问题。


5️⃣ 第五步:在 GitLab 远端查看(UI)

GitLab Compare 页面必须使用格式:

perl 复制代码
<http://xxxx/-/compare/><base>...<target>

三个点:

复制代码
2b86a183...ce3ba83f

如果使用两个点或反向,会失败。

例如:

bash 复制代码
<http://code-oss.sigenpower.com:8090/sigen_app/sigenmain/-/compare/2b86a183de12...ce3ba83f5dce>

即可在 UI 中看到该 diff。


6️⃣ 为什么 GitLab 看不到删除 diff?

因为:

  • 提交 ce3ba83f 是一个 merge commit
  • GitLab 默认显示 merge commit 的 diff 是对所有 parent 的 combined diff
  • 若包含文件完全覆盖,GitLab UI 会"隐藏"这类大块变更
  • JSON 巨文件会触发 GitLab 的 "cut diff" 行为,不展示全部内容

所以:

本地 diff 能看到删掉整段

GitLab UI 不一定展示

很常见。


7️⃣ 最终确认:这个 commit 确实就是删除的来源吗?

✔️ 是的。

判断依据:

  1. git diff parent..child 直接显示删除 → 100% 明确
  2. 另一个 child 没删除
  3. git log -S 没找到显式删除的记录 → merge 覆盖导致
  4. Git DAG 可证明唯一路径包含这个 child

结论:

删除源头 commit 明确为:

ce3ba83f5dce2bcda26d1d2081d9259c904aa8e7


8️⃣ 总结:如何在非线性历史中定位"被覆盖的改动"

流程简化版:

  1. 查找 key 最后出现的 commit

    bash 复制代码
    git log -S "xxx-key"
  2. 找它的 children

    css 复制代码
    git rev-list --children develop | grep <commit>
  3. 对比 parent 与 children

    xml 复制代码
    git diff <parent>..<child>
  4. 哪个 child 删除了 key → 问题提交

  5. GitLab Compare 使用:

    python 复制代码
    ...   (三个点)
相关推荐
weixin_377634844 小时前
【Git使用】PyCharm中的Git使用
ide·git·pycharm
爱吃泡芙的小白白6 小时前
vscode、anaconda、git、python配置安装(自用)
ide·git·vscode·python·anaconda·学习记录
ALex_zry13 小时前
Git大型仓库推送失败问题解决方案:大文件传输优化指南
git
草莓熊Lotso13 小时前
Git 分支管理:从基础操作到协作流程(本地篇)
大数据·服务器·开发语言·c++·人工智能·git·sql
w***Q35016 小时前
Git工作流自动化
运维·git·自动化
舒一笑21 小时前
GitPulse:让代码的故事自己讲述
git·程序员·intellij idea
5***o5001 天前
Git在代码中的GitHub
git·github
还是会想她1 天前
git 常见命令
git
1***y1781 天前
Git在发布流程中的自动化标签
运维·git·自动化