git冲突自动接受传入的安全改变(incoming change)

最后更新: 2026-01-30

在维护 fork / 下游仓库 时,一个高频但痛苦的操作是:

定期 merge 上游仓库的更新,同时保留我们自己的实现。

冲突一多,手动点 IDE 的 “Accept Incoming / Current” 很快就变成体力活,而且极易误操作。

本文总结一套 工程上可靠、可自动化、可解释 的 Git 冲突处理方案,目标很明确:

不是我们维护的代码,全部直接用 upstream;
只有我们(团队)碰过的文件,才值得人工处理。


一、先说清一个事实:Git 并不知道“谁导致了冲突”

Git 只能判断:

  • 同一文件
  • 同一位置
  • 双方都改了

它不知道“责任归属”,所以任何“自动判断谁该保留”的方案,本质都是:

基于历史规则的工程判断,而不是绝对真理。

我们的目标不是 100% 自动,而是:

让人只处理真正需要思考的冲突。


二、典型场景

  • 你维护一个下游仓库(fork)
  • 上游仓库持续更新
  • 你和 1~2 个伙伴在下游实现了部分功能
  • 很多文件你们从来没改过
  • 但 merge 时仍然产生大量冲突

这类冲突 99% 应该直接用 upstream


三、核心策略:用“我们是否改过”作为唯一判断标准

判断原则非常简单,也非常稳:

只要某个文件,在我们自己的提交历史里出现过,就不自动处理;
否则,一律使用 upstream。

这里的“我们”,简单说就是一个明确的作者白名单


四、操作流程

开始 merge(让 Git 停在冲突阶段)

Plain
1git merge upstream/main

此时出现冲突是正常且正确的状态


2️⃣ 自动处理「我们没改过的冲突文件」

下面这段脚本是全文的核心。

Plain
1git diff --name-only --diff-filter=U > /tmp/conflicts.txt 2 3while read file; do 4 if git log BASE_BRANCH..HEAD --pretty="%an <%ae>" -- "$file" \ 5 | grep -E "(Your Name|you@email.com|other@email.com)" -q; then 6 echo "KEEP MANUAL (team touched): $file" 7 else 8 echo "USE UPSTREAM: $file" 9 git checkout --theirs "$file" 10 git add "$file" 11 fi 12done < /tmp/conflicts.txt

你需要替换的只有两点:

  • BASE_BRANCH:你开始维护下游仓库的分支或基准点
  • grep -E:你和你同事的 作者名 / 邮箱白名单

查看当前分支的提交名单:

Plain
1git shortlog -sne

3️⃣ 剩下的文件,才值得人工处理

Plain
1git status

此时剩下的冲突文件,应该满足:

  • 你或你同事确实改过
  • 真正存在逻辑决策

4️⃣ 完成 merge

Plain
1git commit

五、强烈建议的长期优化

1️⃣ 用 .gitattributes 固定掉“永远不该冲突”的文件

Plain
1package-lock.json merge=theirs 2dist/** merge=theirs

这些文件以后 连冲突都不会出现


2️⃣ 如果你们的代码集中在固定目录

直接把这些目录当成“人工白名单”,其余全部自动化。

六、总结

自动化 merge 的本质是为了区分:哪些代码是我们的资产,哪些不是。

当你把判断标准从“我感觉”变成“Git 历史”,你会发现:

  • 冲突数量大幅下降
  • 人只处理真正重要的地方
  • 同步 upstream 变成一件可预期的事情