跳至内容
GitTree

Git 指南

如何在命令行和三向编辑器中解决 Git 合并冲突

如何解决 Git 中的合并冲突:读取冲突标记,使用普通 Git 命令或在可视化三向编辑器中修复它们,并在合并之前查看冲突。加上 rerere、安全中止和撤消合并。

撰写者 Kodmora已更新 阅读 3 分钟
GitTree 分支菜单,包含命名两个分支的合并、变基、交互式变基、快进和重置选项

要解决 Git 中的合并冲突,请打开 Git 报告为冲突的每个文件,确定 <<<<<<<、======= 和 >>>>>>> 标记之间的代码应是什么,删除标记,使用 git add 暂存文件,并以 git commit(或 git merge --continue)结束。要退出,请运行 git merge --abort。本指南将在命令行上逐步介绍该循环,然后在可视化三向编辑器中进行循环,最后以使冲突更加罕见且易于撤消的习惯结束。要练习暂停合并、变基或择优选择为您提供的选择,请参加免费课程 继续、跳过或中止活动操作。

视觉示例使用我们为 macOS、Windows 和 Linux 制作的 Git 客户端 GitTree。它运行您计算机上安装的 Git,因此单击并键入会得到相同的结果; GitTree 功能列表 具有更广泛的图片。

Git 中的合并冲突实际上是什么

Git 使用每个文件的三个版本逐行合并:base(两个分支共享的最后一次提交)、ours(您当前的分支,HEAD)和 theirs(传入分支,MERGE_HEAD)。如果只有一侧更改了某个区域,Git 就会接受该更改。如果双方对相同的行进行了不同的更改,Git 就会停止,将两个版本写入文件,并将决定权留给您。

同样的情况也可能发生在 git pull、git rebase、git cherry-pick、git revert 和 git stash pop 中。修复方法是相同的;只有最终命令不同。 git status 标记每个冲突路径:

  • 都修改了:两个分支都更改了相同的行。这是常见的情况。
  • 被我们删除/被他们删除:一方删除了文件,另一方更改了文件,因此您保留更改的文件或确认删除。
  • 两者都添加了:每个分支在同一路径创建了不同的文件。

如何在命令行上解决合并冲突

1.找到冲突的文件

Git 在合并停止时列出冲突,并且 git status 保留该列表直到您完成。 git diff --name-only --diff-filter=U 仅打印未合并的路径。

$ git merge feature/login
Auto-merging src/auth.ts
CONFLICT (content): Merge conflict in src/auth.ts
Automatic merge failed; fix conflicts and then commit the result.

$ git status
On branch main
You have unmerged paths.

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   src/auth.ts

2. 读取冲突标记

标记之外的所有内容都干净地融合在一起。 <<<<<<< HEAD 之后的块是当前分支,>>>>>>> feature/login 之前的块是传入分支,======= 行将它们分开。

export const retries = 3;
<<<<<<< HEAD
export const timeout = 45;
=======
export const timeout = 60;
>>>>>>> feature/login
export const debug = false;

两个版本通常不足以做出决定。设置 Git 的 zdiff3 冲突样式一次,每次冲突也会在 ||||||| 行之后显示基础:

$ git config --global merge.conflictStyle zdiff3

<<<<<<< HEAD
export const timeout = 45;
||||||| 556e564
export const timeout = 30;
=======
export const timeout = 60;
>>>>>>> feature/login

现在您可以看到 main 将超时从 30 提高到 45,功能分支提高到 60:决定产品需要哪个值,而不是哪个分支获胜。

3. 编辑文件并将其标记为已解决

编写您想要的代码(一侧、另一侧、混合或新的代码)并删除每个标记行。让 Git 在暂存之前检查是否有剩余内容,因为意外提交的杂散 ======= 是典型的损坏构建。

$ git diff --check          # lists any leftover conflict markers
$ git add src/auth.ts
$ git commit                # or: git merge --continue

如果整个文件的一方版本正确,则直接采用。要让 Git 在合并时为每个冲突块选择一侧,请改为使用 git merge -X ours 或 git merge -X theirs 开始合并;不冲突的更改仍然来自两个分支。

$ git checkout --ours -- src/auth.ts     # keep the current branch's version
$ git checkout --theirs -- src/auth.ts   # keep the incoming version
$ git add src/auth.ts

4. 完成操作

当每个文件都暂存后,继续停止的任何操作:git commit(或 git merge --continue)、git rebase --continue、git cherry-pick --continue 或 git revert --continue。变基可以在稍后提交时再次停止;重复循环。

在冲突出现时提供帮助的 Git 命令
命令它显示了什么
git diff每个冲突文件与双方的组合差异
git log --merge -p <path>接触文件的每一方的提交及其差异
git show :1:<path>文件的基本版本
git show :2:<path>,git show :3:<path>您的版本 (HEAD) 和传入版本 (MERGE_HEAD)
git mergetool打开 Git 中配置的合并工具,一次一个冲突文件
内置终端停靠在 GitTree 中的提交图下,在可视视图旁边运行您自己的 shell。
内置终端停靠在 GitTree 中的提交图下,在可视视图旁边运行您自己的 shell。

解决 GUI 中的合并冲突:三向 Git 冲突解决程序

标记对于两线冲突来说很好。由于长文件中存在十几个冲突,GUI 冲突解决程序速度更快且更不易出错。一个好的 Git 合并冲突工具会同时显示所有三个版本,让您通过冲突来决定冲突,并在标记保留时拒绝保存。

在 GitTree 中,停止的合并会显示一个横幅,其中包含冲突数量和冲突文件列表。打开一个,编辑器将占据整个窗口:当前分支和传入分支并排在顶部,每个分支都标有其分支名称,而输出(将要保存的文件)位于下方。

  • 每次冲突: 选择当前侧、传入侧、两者或两者都不选择,或从每一方中选择单行。
  • 对于按钮未涵盖的任何内容,手动 编辑输出。
  • 显示 Base 以查看共同祖先(当 merge.conflictStyle 为 diff3 或 zdiff3 时,Git 会写入它)。
  • 撤消选择后退一步做出您的决定。
  • 删除的文件:当一方删除另一方更改的文件时,保留该方的文件或确认删除。

GitTree 不会保存仍包含标记线的结果。它还可以在外部合并工具中打开文件:VS Code、Cursor、JetBrains IDE、Beyond Compare、Meld、KDiff3、P4Merge、WinMerge、自定义程序或 Git 自己的 merge.tool。如果该工具在未解析文件的情况下关闭,则文件将保持冲突状态。

如何逐步解决 GitTree 中的合并冲突

  1. 开始合并

    打开要引入的分支上的分支菜单并将其合并到当前分支,或将一个分支拖到另一个分支上。菜单上有两个分支的名称,因此方向永远无法猜测。

  2. 阅读冲突预览

    在进行任何更改之前,合并对话框会显示分支合并时不会发生冲突,或列出将停止的文件。选择如何记录合并,然后确认。

  3. 打开冲突的文件

    如果合并停止,横幅会对冲突进行计数,并且文件列表会显示每个冲突的文件。在三向编辑器中打开第一个。

  4. 决定每个冲突

    选择当前侧、传入侧、两者或两者都不选择、选择单行或编辑输出。使用 Show Base 查看任一分支更改之前的代码。

  5. 保存并标记文件已解决

    选择保存并标记为已解决。 GitTree 写入并暂存该文件,然后您继续处理下一个文件。当冲突标记线仍然存在时,它会拒绝。

  6. 提交合并

    解决每个文件后,选择“提交并合并”(继续重新设置基准以进行重新设置)。后来改变主意了吗?从提交菜单将分支重置为合并之前的提交; GitTree 首先拍摄重置的快照,以便撤消可以撤销它。

GitTree 的浅色主题中的提交图,选择了合并提交,其中两个分支通道连接在一起。
GitTree 的浅色主题中的提交图,选择了合并提交,其中两个分支通道连接在一起。

在合并之前预测合并冲突

从 Git 2.38 开始,git merge-tree --write-tree 在内存中执行合并,无需读取或写入工作树或索引,也无需进行提交。使用 --name-only 会列出可能发生冲突的文件;当存在冲突时,退出状态为 1;当合并干净时,退出状态为 0。

$ git fetch
$ git merge-tree --write-tree --name-only HEAD origin/main
0d708adc4a836d088802870278cb1f3daf06355f
src/auth.ts

Auto-merging src/auth.ts
CONFLICT (content): Merge conflict in src/auth.ts

GitTree 为您运行此预览:合并对话框会在您确认之前显示预测结果。每次提取后,它还会根据其上游和基础分支(主分支或主分支,除非您设置另一个分支)检查您的分支,并在分支名称旁边显示警告,例如“将与 2 个文件中的主分支冲突”。第二个提示标记您正在更改的文件,其他获取的未合并分支也会更改。

两项检查仅使用您已获取的内容:不会获取、合并或更改任何内容来计算它们,也不会离开您的计算机。可以在“首选项”中关闭其中任何一个。

使用 git rerere 重用冲突解决方案

Rerere 代表“重用记录的分辨率”。打开它后,Git 会记录每个冲突以及您如何解决它。当相同的冲突再次出现时,比如对长期存在的分支进行重复变基或重做合并时,Git 会将您之前的解决方案写入文件中。

$ git config --global rerere.enabled true
$ git rerere forget src/auth.ts   # drop a recorded resolution that was wrong

除非设置了 rerere.autoUpdate,否则 Git 会将重用的结果保留下来以供审核。在 GitTree 中,存储库设置具有针对这些 Git 选项的 重用记录的解决方案 (rerere) 和 阶段重用的解决方案 开关;冲突视图标记重复使用的解决方案,忘记解决方案删除错误的解决方案。

如何在 Git 中中止或取消合并

要取消因冲突而停止的合并,请运行 git merge --abort。 rebase、cherry-pick 或 revert 有其自己的中止:

$ git merge --abort
$ git rebase --abort
$ git cherry-pick --abort
$ git revert --abort

Git 自己的文档警告说,git merge --abort 不能总是重建合并开始时未提交的更改。在合并之前提交或存储,并且中止仅已提交的工作需要恢复。

在 GitTree 中,Abort Merge(或 Abort Rebase、Cherry-Pick、Revert)首先解释了 Git 恢复操作之前的分支、索引和工作副本,并删除迄今为止所做的决议。 GitTree 将中止删除的所有内容(无论是否暂存)保存在恢复快照中,以便撤消可以将其恢复。

提交合并后如何撤消合并

做什么取决于您是否已推送合并:

# Not pushed yet, right after the merge:
$ git reset --hard ORIG_HEAD     # also discards uncommitted changes
$ git reset --merge ORIG_HEAD    # keeps uncommitted changes

# Already pushed:
$ git revert -m 1 <merge-commit> # a new commit that reverses it

合并会将分支的上一个提示保存在 ORIG_HEAD 中,因此重置它会删除合并,除非稍后重置或变基移动了 ORIG_HEAD。一旦其他人合并,就恢复。恢复合并告诉 Git 你永远不需要这些更改:再次合并该分支不会将它们恢复,除非你恢复恢复。

在 GitTree 中,在图表中选择合并的第一个父级(您的分支之前所在的提交),然后从提交菜单中选择对其进行软重置、混合重置或硬重置,每个重置都标有其保留的内容。 GitTree 在运行之前对 19 种操作进行快照,包括重置,因此撤消可以反转重置,并且引用日志视图恢复旧状态。 撤消重置、变基或提交指南 涵盖了深度恢复。

如何防止大多数合并冲突

  • 保持分支小且寿命短。 两个分支分叉的时间越长,它们接触的线就越多。
  • 经常引入基础分支,不要在最后引入一次。
  • 将格式化与逻辑分开。 同意一种格式化程序并自行进行整个文件重新格式化。
  • 重新生成锁定文件,而不是手动合并它们。 选择任一侧,然后再次运行包管理器。
  • 打开 zdiff3 并 rerere 一次。 两个命令,持久受益。
  • 在集成之前提交或存储,因此每次中止和撤消都是准确的。

想先在安全的存储库上练习吗? Git 教程 中的免费课程 合并分歧分支并验证双亲 演示了真正的合并。还在权衡终端与 GUI 的区别吗? Git GUI vs 命令行 诚实地比较了两者。

GitTree 有一个免费计划,涵盖所有 Git 功能,包括私有存储库,而 AI 助手 Nour 则随 GitTree Pro 一起提供(请参阅定价);它需要 Git 2.39 或更新版本以及 GitTree 帐户才能登录。获取 macOS、Windows 或 Linux 的版本,或者在 GitTree 下载页面 上查看每个安装程序。在 Ubuntu 22.04 上,先升级 Git。陷入顽固的冲突? 请求 GitTree 支持。

常见问题

是什么导致了 Git 中的合并冲突?

当两个分支以不同的方式更改文件的相同行,或者当一个分支删除另一个分支修改的文件时,就会发生合并冲突。 Git 会自动组合对文件不同部分的更改,但它无法在对同一行的两次编辑之间进行选择,因此它会停止并要求您做出决定。

如何取消 Git 中的合并?

当合并因冲突而停止时运行 git merge --abort。 Git 将分支、索引和工作树恢复到合并开始之前的状态。对于变基、挑选或恢复,请使用 git rebase --abort、git cherry-pick --abort 或 git revert --abort。如果合并已经作为提交完成,则中止不再适用:而是通过重置或恢复来撤消它。

“您必须编辑所有合并冲突,然后使用 git add 将它们标记为已解决”是什么意思?

当您尝试继续时,Git 会打印它(通常使用 git rebase --continue),而文件仍然算作冲突。打开未合并路径下列出的每个文件 git status,删除冲突标记,对文件运行 git add 并再次继续。首先运行 git diff --check 会显示您错过的任何标记。

中止冲突合并是否安全?

是的,如果您首先提交或隐藏了自己的工作。 git merge --abort 恢复合并之前的分支、索引和工作树并放弃您的决议。合并之前未提交的编辑可能不会准确返回,这就是为什么首先提交或存储很重要。 GitTree 会对中止丢弃的任何内容进行快照,因此“撤消”可以将其恢复。

在 Git 冲突中我们的和他们的意味着什么?

在合并中,“我们的”是您所在的分支(HEAD),“他们的”是正在合并的分支。在变基中,它们交换:“我们的”是您要变基的分支,“他们的”是您自己正在重播的提交。这就是为什么 git checkout --ours 在 rebase 过程中让人们感到惊讶。 GitTree 用其分支名称和角色标记每一方。

如何撤消已经提交的合并?

如果您尚未推送,请在合并后立即运行 git reset --hard ORIG_HEAD,或运行 git reset --merge ORIG_HEAD 以保留未提交的更改。如果合并已经在共享分支上,请运行 git revert -m 1 <merge-commit> 以反转它而不重写历史记录。在 GitTree 中,从提交菜单将分支重置为合并的第一个父级;重置会首先被快照,因此如果您改变主意,撤消可以撤销它。

解决 Git 合并冲突的最佳工具是什么?

寻找一个合并冲突工具,它可以同时显示三个版本(您的版本、传入的版本和公共基础),让您通过冲突来决定冲突,并且不会保存带有标记的文件。 GitTree 包括一个类似的三向编辑器,还可以将文件传递给您已经使用的合并工具。无论哪种方式,请打开 zdiff3。

Git 下次能自动解决同样的冲突吗?

是的,有 rerere。运行 git config --global rerere.enabled true,Git 会记录您如何解决每个冲突。当完全相同的冲突再次出现时,例如在重复变基期间,Git 会将您之前的解决方案写入文件中。除非启用了 rerere.autoUpdate,否则您仍然可以查看并暂存它。 GitTree 显示决议何时被重复使用。

来源

有关其他产品的声明已根据其位于 2026年10月28日 的官方页面进行了检查。价格和功能发生变化;供应商的页面是事实的来源。