Git Rebase 踩坑复盘:合单支付分支代码丢失问题

1. 事件背景

时间:2026-04-28

场景combine_pay(合单支付)分支需要 rebase 到最新的 main 分支,过程中发生了静默的代码丢失,没有触发 git 冲突警告。

受影响的功能

  • wallet 明细查询接口(2 个方法)
  • 支付宝商户 PID 字段逻辑
  • QueryPendingTransactionParam 结构体字段缺失

2. 问题现象

预期行为

  • git rebase main 后,main 分支已有的 wallet 功能应该完整保留
  • 合单支付的新功能应该正常叠加
  • 有冲突应该提示人工解决

实际行为

✅ 编译最终通过(人工修复后)
❌ main 分支新增的 wallet 相关代码被静默覆盖,无冲突提示
❌ main 分支新增的支付宝 PID 字段逻辑被覆盖
QueryPendingTransactionParam 缺少 Status 字段


3. 根本原因分析

3.1 Git Diff 的"上下文匹配"机制

⚠️ 核心认知误区:很多人以为 git diff 是按"行号"记录修改,实际上是按上下文匹配

git diff 记录的修改格式:

在【GetTransactionByID】下面、【HandleRefund】上面的那一行,
要从【旧的7个参数版本】改成【新的 param 版本】

不是

把第 26 行改成新内容

3.2 为什么没有触发冲突?

冲突只会在以下情况触发:

  • ✅ 两个分支修改了同一行且内容不同
  • ❌ 一个分支修改了 A 行,另一个分支在 A 行附近新增了 B 行静默覆盖!

3.3 本次事件的精确触发点

// combine_pay 分支做的修改:把7个参数改成1个参数
- QueryPendingTransaction(ctx context.Context, tpwType types.TpwType, tradeType types.TradeType, startTime, endTime time.Time, isPos *bool, lastID int64, limit int)
+ QueryPendingTransaction(ctx context.Context, param *transactionparam.QueryPendingTransactionParam)

这个修改改变了整个 interface 代码块的"结束位置",导致 main 分支在 interface 末尾新增的两行 wallet 方法被 git 判定为"不属于最终代码",从而被静默删除。


4. Git Rebase 工作原理详解

4.1 Rebase = "搬家",不是"合并"

rebase 前:

main:     A --- B --- C --- D (HEAD)
              \
combine_pay:   E --- F (你的提交)

rebase 后:

main:     A --- B --- C --- D
                              \
combine_pay:                   E' --- F' (E 和 F 在新位置重新执行)

4.2 Rebase 的 3 个步骤

  1. 找到分叉点:git merge-base main combine_pay → B 提交
  2. 生成补丁:把 E、F 每个提交都转换成 patch 文件
  3. 依次应用:在 D 提交上,按顺序重新应用每个 patch

⚠️ 关键:每个 patch 应用时都是独立的上下文,不知道中间 main 加了什么。

4.3 Patch 应用的三种结果

场景 Git 行为 开发者可见
修改位置完全不重叠 自动合并 ✅ 无感知
同一行内容都改了 冲突报错 ❌ 必须手动解决
你整体替换了代码块,main 在块内加了东西 静默覆盖 ⚠️ 完全看不见!

第三种情况就是本次事故的元凶!


5. 本次事件时间线还原

时间线(从旧到新):

3d76ac00  main 分支基准(两分支分叉点)
    │
    ├─→ main 分支后续提交:
    │    a04f046d  feat: wallet查询和回调接口支持返回明细信息 ← 新增2个interface方法
    │    3579a47d  feat: 支付宝商户信息新增PID字段
    │    ...
    │    [main 继续往前发展了 13 个提交]
    │
    └─→ combine_pay 分支(基于 3d76ac00 开发,与 main 脱节):
         fd1983b5  fix: 合单支付
                   ↓↓↓ 这个提交包含:
                   - QueryPendingTransaction 从7参数改成 param结构体
                   - 新增合单支付相关接口
                   - 【不包含】main 后来加的 wallet 方法
                   - 【不包含】main 后来加的 PID 字段逻辑

rebase 时发生了什么

  1. git 把 fd1983b5 这个提交做成 patch
  2. 在 main 最新代码上应用这个 patch
  3. 这个 patch 说"Transaction interface 应该是这个样子"
  4. git 就真的按这个样子替换了 interface
  5. main 新增的 wallet 代码就没了 🫠

6. 本次问题的解决方案汇总

6.1 已修复的代码变更

文件 修复内容
internal/domain/transaction/svc/transaction.go 恢复 2 个 wallet 查询方法声明和实现
internal/domain/transaction/repo/transaction.go 恢复 2 个 wallet 查询接口声明
internal/infra/persistence/transaction/transaction.go 恢复 2 个 wallet 查询实现
internal/application/assembler/tpw_config.go 恢复支付宝 PID 逻辑,删除 PayerType 字段
internal/domain/transaction/params/transaction.go 补充 Status 字段到 QueryPendingTransactionParam
sql/tables.sql 同时保留 wallet SQL 和合单表 SQL

6.2 Vendor 目录处理

  • proto 文件和 wallet 相关类型由人工更新 vendor 目录解决

7. 预防措施和最佳实践建议

📌 建议 1:大功能分支优先考虑 merge,不要 rebase

适用场景:分支开发超过 2 周、涉及核心 interface 重构

# 推荐
git checkout combine_pay
git merge main

# 不推荐(风险高)
git checkout combine_pay
git rebase main

理由:merge 是真正的"两边内容做并集",静默覆盖的概率低很多。

📌 建议 2:rebase 前必须做"重叠文件检查"

rebase 前执行这条命令,看看哪些文件两边都改了:

# 列出两个分支都修改过的文件
git diff --name-only HEAD...main

如果输出包含核心文件(如 interface 定义),一定要提高警惕!

📌 建议 3:对共同修改的文件做预检查

# 看看这个文件两边具体差了什么
git diff HEAD main -- internal/domain/transaction/svc/transaction.go

如果发现 main 在你也改过的文件里加了很多东西,考虑改用 merge。

📌 建议 4:rebase 后必须编译+关键测试

不要 rebase 完就直接 push!

git rebase main

# ✅ 必须做的验证
go build ./...
go test ./... -run TestWallet # 跑一下被覆盖功能的关键测试

📌 建议 5:分支不要"离线"太久

  • 每周至少 sync 一次 main 分支
  • 大功能拆成小 MR 逐步合并,不要攒成一个巨型 MR
  • 越晚 rebase,冲突量越大,静默覆盖概率越高

📌 建议 6:核心 interface 尽量"只追加,不修改"

如果必须改 interface 签名:

  • 先加新方法,标记旧方法为 deprecated
  • 等所有分支都合入后,再删除旧方法
  • 不要直接修改已有方法的签名(这是 rebase 噩梦的源头)

8. 总结

本次事件的教训

  1. git rebase 不是安全的:静默覆盖是真实存在的风险
  2. 没有冲突 ≠ rebase 成功:最危险的 bug 是那些不报错的 bug
  3. 核心 interface 的签名修改是高危操作:很容易和其他分支产生"看不见的冲突"

记住这个反直觉的结论

改一个方法的签名,可能会导致别人新增的代码被删除。

而且 git 不会报错 🫠


附录:快速自查清单

每次 rebase 前问自己这 3 个问题:

问题 是 → 考虑用 merge 否 → rebase 安全
我的分支开发超过 2 周了吗?
我改了核心 interface 吗?
git diff --name-only HEAD...main 输出超过 5 个文件吗?

文档创建时间:2026-04-28
涉及分支:combine_pay, main

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容