防止 git merge 丢失代码(谨防 three way merge 的异常行为)

本文揭示了Git三路合并可能导致代码丢失的问题,并提供了避免策略。当两个分支对同一文件进行修改时,Git的自动合并可能会误删代码。建议包括避免多人在同一文件上工作、主动制造冲突以便手动合并、使用高级Git工具或提前保存合并结果。通过这些方法,可以更好地控制合并过程,防止重要代码被意外删除。

防止 git merge 丢失代码(谨防 three way merge 的异常行为)


Git 工具在执行 merge 操作时,为了尽最大可能去自动的处理,所以使用了 three way merge 的方式作为了其 merge 手段。然而,这种 Git 尽最大可能自动化的处理在一些时候会造成十分令人困惑的问题。本文旨在指出问题并提供一些避免手段。


1. Git’s Three Way Merge

在 branch-A 和 branch-B 进行 merge 操作时,若两个分支均包含有 Main.py 文件,Git 会使用 Three way merge 的方式进行合并处理。简单来说,就是会找到 branch-A HEAD Commit 和 branch-B HEAD Commit 的公共根节点 Commit-Base,综合对比来进行合并。

详细内容可以参考 Git三路合并算法(Three Way Merge),本文不再赘述原理部分。

为了方便讨论,我们不会涉及多个公共 Base Commit 节点的复杂案例。


2. 案例说明(Merge 造成了代码丢失而引发异常)

我们制造一个场景,让我们的 Git 分支情况如下:
Git Branches
在 master 分支,文件如下:
On Master
dev_a 的修改为:
dev-a
dev_b 的修改为:
dev-b

2.1 场景描述

  • Main.py 为主要的工作文件
  • 开发者 A 在 dev_a 下新增了 get_json_thing 的方法
  • 开发者 B 在 dev_b 下新增了主函数的打印,同时删掉了一些没有使用的 import 语句

2.2 Merge and Boom

现在开发者 A 想要通过 merge dev_b 来把开发者 B 的打印日志合并进来,于是他执行:

git merge dev_b

现在 merge 成功了,但是他发现自己的代码不 work 了,因为 Git 自作聪明的 Three Way Merge 将 import json 删掉了:
result
结合在第一节的参考链接,我们很容易理解 Git 这次 Merge 的操作原理,因为不涉及到冲突,Git 把 dev_a 和 dev_b 相对于 master 的更改全部采纳了。

这只是一个非常非常简单的例子而已,在实际的开发工作中,我们的代码要复杂的多,而这样的情况稍稍复杂一些,我们很可能因为 Git Merge 的自动行为造成大量的代码丢失。


3. 如何避免

3.1 避免多个人在多个 Branch 对同一个文件进行大量修改

只要不涉及到在不同的 Branch 对同一个文件进行修改,Git 的 Three Way Merge 自动行为将不会自动删掉我们的潜在有用的代码。

3.2 主动造成 Conflict 并使用高级 Git 工具手动 Merge

我们将我们的案例稍稍改动,使其在 Merge 的时候造成冲突:
Conflict
值得注意的是,Git 只会将 Conflict 的部分进行标注,它能够 Three Way Merge 自动解决的部分仍然无法标注出来。我们仍然无法自行决定要保留来自两个分支的哪些更改。

而来自 JetBrains IDE 和 Visual Studio 等的高级 Git 工具均可以将两个 Branch 的所有的变更进行显示,自行决定要保留各个分支的哪部分更改
JetBrains IDE
Visual Studio

3.3 提前保留最终结果

我们可以利用 diff&merge 工具(Two Way Merge)提前手动决定一份最终版本的结果,然后在合并结束后覆盖合并后的文件即可。

3.4 最理想但是无解的方法

最理想情况下,我们应该可以控制 Git Merge 使其强制使用 Two Way Merge 的方式合并,制造大量冲突让我们手动判定(多做人工操作,不相信机器)。但是来自 Git 的文档 显示并不支持这种方式。

所以如果你有更好的方案,欢迎探讨!

### 解决 Git 合并代码时出现的代码丢失问题 当遇到 `git merge` 导致代码丢失的情况,通常是因为三路合并过程中某些文件或行未被正确处理。为了恢复这些丢失的内容,有几种方法可供尝试。 #### 方法一:利用暂存区和工作目录差异检查 可以通过比较当前的工作树与最近一次提交之间的区别来查找可能遗漏的部分: ```bash git diff HEAD ``` 这会显示自上次提交以来所有更改过的文件及其具体内容变化[^1]。 #### 方法二:通过历史记录追踪变更 如果已经完成合并并且推送至远程仓库,则可以查看项目的历史记录以定位具体在哪一步发生了错误: ```bash git log --oneline -n 5 ``` 上述命令将展示最新的五个提交摘要,帮助快速找到涉及合并的那个点。接着可以根据该信息进一步调查特定文件的变化情况: ```bash git show <commit-hash>:<file-path> ``` 这里 `<commit-hash>` 是指代目标提交对象哈希值的一部分;而`<file-path>`则是受影响源码的位置路径[^4]。 #### 方法三:撤消合并操作 对于尚未推送到公共分支上的本地改动而言,最简单的方式可能是直接撤销整个合并过程,并按照更加谨慎的方式来重复这一流程。注意,在执行下面的操作前最好先创建一个新的备份分支以防万一: ```bash # 创建临时备份分支 git checkout -merge-issue # 返回到合并之前的最后一个稳定状态 git reset --hard ORIG_HEAD~ # 或者使用revert来回滚指定的合并提交而不影响其他部分 git revert -m 1 <merge-commit-id> ``` 其中 `-m 1` 参数表示选择第一个父节点作为基础版本进行反向应用,这对于大多数情况下都是适用的选择[^3]。 #### 方法四:重新解决冲突 有时简单的重做可能会解决问题。确保所有的冲突都得到了妥善处理后再继续前进。如果有多个开发人员参与了相同区域内的编辑活动,那么沟通协调就显得尤为重要了。可以在各自独立的基础上分别拉取最新更新再试一次完整的集成测试循环[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值