Git 合并冲突 HEAD 和 incoming 分别是谁的

FreeGuideOnline 最新 2026-07-04

Git 合并冲突中 HEAD 和 incoming 分别代表哪一方

当你运行 git mergegit rebase 遇到冲突时,Git 会在冲突文件中插入特殊标记,展示两个不同来源的代码块。这些标记里最常见的就是 <<<<<<< HEAD>>>>>>> <branch-name>,而 incoming(或称为 theirs)则是许多开发工具和文档中用来指代“被合并过来的那一边”的术语。

本教程将用最直观的方式,帮助你彻底弄清楚:冲突标记里的 HEAD 到底是谁,incoming 又是谁,以及在不同 Git 操作下它们如何互换角色。

核心概念:HEAD 与 incoming 的定义

在 Git 中,HEAD 是一个指针,它始终指向你当前所处的提交(commit)。大多数情况下,HEAD 指向当前分支的最新提交。

当 Git 需要将两个不同的改动合并到同一个文件时,它会用冲突标记框出两个版本:

<<<<<<< HEAD
当前分支上的内容
=======
被合并分支上的内容
>>>>>>> feature-branch
  • <<<<<<< HEAD 下面的内容:属于 当前分支,也就是你正在操作的分支(例如 main)。它是你工作目录的“现状”。
  • >>>>>>> feature-branch 下面的内容:属于 被合并进来的分支(这里例子中是 feature-branch)。在许多图形界面工具和教程中,这一侧被称为 incomingtheirs,意为“外部传入的修改”。

简单记忆:

  • HEAD = ours(我们的),即你当前所在的、正在合并目标的分支。
  • incoming = theirs(他们的),即你尝试合并进来的分支。

场景一:git merge 时的 HEAD 与 incoming

这是最常见的合并场景。假设你现在在 main 分支,想把 feature 分支合并进来:

git checkout main
git merge feature

当发生冲突时,文件中会显示:

<<<<<<< HEAD
这里是 main 分支上的代码
=======
这里是 feature 分支上的代码
>>>>>>> feature
  • HEAD 就是 main 分支的内容(因为你正处于 main)。
  • incoming 就是 feature 分支的内容(你试图合并进来的那个分支)。

此时,如果你使用命令选择某一侧:

  • git checkout --ours <file> 会保留 main 的版本(HEAD)。
  • git checkout --theirs <file> 会保留 feature 的版本(incoming)。

场景二:git rebase 时角色会互换——这是最容易混淆的地方!

git rebase 的工作方式与 git merge 完全不同。它会将当前分支的提交“搬到”目标分支的顶端,因此在 rebase 过程中,HEAD 所指的上下文会发生变化

假设你在 feature 分支,想把它 rebase 到 main 上:

git checkout feature
git rebase main

此时 Git 会:

  1. feature 分支独有的提交临时保存。
  2. HEAD 移动到 main 分支的最新提交(即你正在“重放”提交的基准)。
  3. 逐个应用 feature 的提交。

在这个过程中如果发生冲突,冲突标记会变成:

<<<<<<< HEAD
这里是 main 分支上的代码(你当前 rebase 的基底)
=======
这里是 feature 分支上的代码(你正在应用的补丁内容)
>>>>>>> 你的提交信息(正在重放的 commit)

注意角色的反转:

  • 现在 HEAD 代表的是 你正在重放到其上的基底分支,也就是 main 的内容。但在 merge 思维里,你可能会觉得它是“别人的”。
  • incoming(标记右侧或 >>>>>>> 后面的内容)是 你自己的 feature 分支的内容,也就是你正在重放的补丁。

在 rebase 冲突中,记住这个反直觉的关系:

  • HEAD 此时相当于 merge 场景里的 theirs(因为基底是你要合并进的目标的上游代码)。
  • incoming(右侧的更改)相当于 merge 场景里的 ours(因为那是你自己分支上的工作)。

因此,如果你在 rebase 冲突中想要保留自己 feature 分支的代码,你应该选择 incoming(右侧),而不是 HEAD。很多初学者在这里选错,导致自己的改动被上游覆盖。

如何正确分辨并解决冲突

无论使用哪种操作,都可以通过以下两条规则来记忆:

操作 HEAD 代表…… incoming(theirs)代表……
git merge 当前分支(你 merge 时所在的分支) 被合并的分支(你指定的那个分支)
git rebase 被重放到其上的基分支(上游分支) 你正在应用补丁的分支(你自己的提交)

在命令行中解决:

  • 使用 git checkout --ours <file> 保留 HEAD 一侧的内容。
  • 使用 git checkout --theirs <file> 保留 incoming 一侧的内容。
  • 或者手动编辑文件,删除冲突标记,保留所需代码。

在 VS Code 等图形工具中:

通常会显示两个选项:

  • Accept Current Change(接受当前更改):对应 HEAD。
  • Accept Incoming Change(接受传入更改):对应 incoming/theirs。
  • 在 rebase 时,含义会随角色变化,务必根据上面表格判断哪一侧是你真正想要的。

实践技巧:永远先看清你在哪个分支、做什么操作

遇到冲突不要慌,按以下步骤确认:

  1. 运行 git status 查看你是否处于合并状态(You have unmerged paths)或变基状态(rebase in progress)。
  2. git branchcat .git/HEAD 确认当前 HEAD 指向哪个分支或提交。
  3. 回忆你输入的命令:是 git merge 还是 git rebase?哪个是目标分支?
  4. 打开冲突文件,根据标记文字下的分支名或提交信息判断:<<<<<<< HEAD 下方是当前基底的内容;>>>>>>> 后面跟着的分支名或提交信息是传入的来源。
  5. 决定保留 HEAD 还是 incoming,或两者结合后手动编辑保存。

总结

  • HEAD 永远是你当前工作的“基础点”。在 merge 里是你的目标分支;在 rebase 里是你要把 commit 移动到的上游分支。
  • incoming / theirs 是“从外部加入”的改动。在 merge 里就是那个被合并的分支;在 rebase 里则是你自己的补丁分支。
  • 角色互换是理解冲突的关键:merge 的 ours 是 rebase 的 theirs,反之亦然。
  • 掌握这个逻辑后,再也不会在冲突里删错代码。

希望这篇教程能帮你建立清晰的冲突思维模型。把这张对照表收藏起来,下次遇到冲突对照一下,很快就能熟练应对。