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 复制代码
    ...   (三个点)
相关推荐
vibecoding日记8 小时前
为什么我就想要「线性历史 + Signed Commits」,GitHub 却把我当猴耍 🤬🎙️
git·编程工具
程序员小崔日记18 小时前
如何将代码轻松上传到 Gitee?Git 使用全攻略!
git·gitee·上传
Bigger2 天前
为什么你的 Git 提交需要签名?—— Git Commit Signing 完全指南
git·开源·github
DianSan_ERP2 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
红豆子不相思3 天前
Tomcat 环境搭建与集群实战
服务器·git·tomcat
杰哥技术分享3 天前
Git 仓库迁移技术文档:从 CODING.net 迁移至腾讯云 CNB
git
梅孔立3 天前
Ansible 100 台服务器一键管控实战 进阶版
服务器·git·ansible
qq_426003963 天前
git切换当前分支到远程分支
git
ON10N3 天前
100% 纯 Vibe Coding,我是怎么用 AI 撸出一个 VS Code 插件的
git·ai编程·visual studio code