解决常见的 Git 合并冲突:逐步故障排除指南

借助这份重要的故障排除指南,掌握 Git 合并冲突。了解如何识别冲突标记(`<<<<<<<`、`>>>>>>>`),应用手动解决策略(保留本地、保留远程或组合),并安全地完成合并或变基。遵循这些清晰的、分步的冲突解决说明,将挫败感转化为生产力。

解决常见的Git合并冲突:逐步故障排除指南

Git合并冲突意味着Git发现了重叠的更改,需要您选择最终版本。当两个分支修改了相同的行、以不同方式重命名了同一个文件,或者都编辑了Git无法自动合并的文件时,通常会出现这种情况。

目标很简单:检查冲突,将文件编辑为您实际想要的版本,暂存它,然后继续合并或变基。

理解什么是Git合并冲突

当Git尝试将一个分支的更改整合到另一个分支(例如,使用git mergegit rebase)时,如果发现两个分支独立修改了同一文件的相同行,就会发生合并冲突。Git擅长组合不重叠的更改,但当更改直接重叠时,需要人工干预。

Git如何发出冲突信号

当合并过程中出现冲突时,Git会立即停止操作,并通知您合并失败。受影响的文件将在工作目录中被标记为冲突状态。您可以使用以下命令检查状态:

git status

输出将列出“未合并的路径”文件,表明在合并继续之前需要手动解决。

步骤1:识别冲突标记

一旦Git暂停合并,冲突文件会包含Git插入的特殊标记,用于划分冲突部分。这些标记帮助您准确查看哪些更改来自哪个分支。

冲突标记

在普通的文本冲突中,您会看到三个标记行包围着两个版本的内容:

  1. <<<<<<< HEAD
    • 标记当前分支(您正在合并的分支)更改的开始。
  2. =======
    • 作为两组冲突更改之间的分隔符。
  3. >>>>>>> branch-name
    • 标记传入分支(您正在合并的分支)更改的结束。

冲突块示例:

假设您正在将feature/A合并到main,并且两个分支都编辑了config.js的第10行:

// config.js

function getTimeout() {
<<<<<<< HEAD
  return 5000; // Main branch default
=======
  return 10000; // Feature A override
>>>>>>> feature/A
}

步骤2:通过编辑文件解决冲突

解决冲突涉及编辑文件以移除Git标记并选择所需的代码组合。您有三种主要的解决策略:

A. 保留HEAD(当前分支)的更改

如果您决定当前分支(HEAD)上的版本是正确的,则移除传入的更改和所有标记。

解决操作:

// config.js

function getTimeout() {
  return 5000; // Main branch default
}

B. 保留传入分支的更改

如果您决定合并进来的分支的更改是正确的,则移除当前分支的更改和所有标记。

解决操作:

// config.js

function getTimeout() {
  return 10000; // Feature A override
}

C. 合并或重写更改(混合方法)

通常,最佳解决方案是手动构建一个包含双方逻辑的新版本,或者完全重写代码以满足两个原始修改的要求。

解决操作(混合示例):

// config.js

function getTimeout() {
  // 基于环境变量设置超时,合并逻辑
  if (process.env.NODE_ENV === 'production') {
      return 10000;
  }
  return 5000; 
}

最佳实践: 在解决冲突块后,始终验证生成的代码能够编译并正常运行。强烈建议在此阶段运行单元测试。

步骤3:暂存已解决的文件

在您手动编辑每个冲突文件,移除所有<<<<<<<=======>>>>>>>标记后,必须暂存这些更改以告知Git冲突已处理。

对每个已解决的文件使用标准的git add命令:

git add config.js
git add src/utils/helper.py
# ... 对所有冲突文件重复操作

要验证Git是否识别了解决方案,再次运行git status。所有之前未合并的路径现在应显示在“要提交的更改”下。

步骤4:完成合并或变基

一旦所有冲突都已暂存,根据最初启动的命令完成操作:

完成git merge

如果您正在进行标准合并,通过提交来完成:

git commit

Git通常会打开您配置的文本编辑器,其中包含预填充的合并提交消息。检查它,保存并关闭编辑器。合并现已完成。

完成git rebase

如果您正在进行变基,则继续该过程,这将在已解决的状态之上应用后续提交:

git rebase --continue

如果变基序列中的后续提交也导致冲突,则对遇到的每个冲突重复步骤2到4。

困难冲突的故障排除技巧

虽然上述步骤涵盖了标准解决方案,但复杂场景可能需要替代方法:

中止操作

如果您开始合并或变基后意识到情况过于复杂,或者需要与团队成员协商,您可以随时恢复到发出命令之前的状态:

git merge --abort  # 如果您以'git merge'开始
git rebase --abort  # 如果您以'git rebase'开始

使用可视化差异工具

对于包含许多重叠更改的复杂文件,强烈建议使用专用的三路合并工具(如VS Code的内置合并编辑器、KDiff3或Meld)。您可以直接启动配置的工具:

git mergetool

该界面通常显示本地版本、远程版本和共同祖先基础版本,使手动选择更加清晰。

处理二进制文件

Git无法自动合并二进制文件(如图像或编译后的资源)。如果两个分支修改了同一个二进制文件,Git将报告冲突。在这种情况下,您必须通过将首选文件复制到工作目录、暂存并提交/继续来手动选择保留哪个版本。

# 在合并期间,保留当前分支的版本
git checkout --ours image.png

# 或保留合并进来的分支的版本
git checkout --theirs image.png

git add image.png
git commit

在变基期间,--ours--theirs可能会感觉颠倒,因为Git正在将提交重放到新的基础上。运行git status,检查文件,并在暂存之前确认所选版本。

要点

不要试图通过盲目删除标记来“解决冲突”。阅读双方的内容,决定最终代码应该是什么,运行相关测试,然后暂存已解决的文件。之后,对于合并使用git commit,对于变基使用git rebase --continue