协慌网

登录 贡献 社区

如何在 Git 中解决合并冲突

有没有一种很好的方法来解释如何解决 Git 中的合并冲突?

答案

试试: git mergetool

它会打开一个 GUI,引导您完成每个冲突,然后您可以选择合并方式。有时它需要稍后进行一些手工编辑,但通常它本身就足够了。这肯定比手工做整件事要好得多。

根据 @JoshGlover 评论:

除非您安装 GUI,否则该命令不一定会打开 GUI。为我运行git mergetool导致使用vimdiff 。您可以安装以下工具之一,而不是使用它: meldopendiffkdiff3tkdiffxxdifftortoisemergegvimdiffdiffuseecmergep4mergearaxisvimdiffemerge

下面是使用vimdiff解决合并冲突的示例过程。基于此链接

步骤 1 :在终端中运行以下命令

git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false

这会将 vimdiff 设置为默认合并工具。

步骤 2 :在终端中运行以下命令

git mergetool

第 3 步 :您将看到以下格式的 vimdiff 显示

+----------------------+
  |       |      |       |
  |LOCAL  |BASE  |REMOTE |
  |       |      |       |
  +----------------------+
  |      MERGED          |
  |                      |
  +----------------------+

这 4 个观点是

LOCAL - 这是当前分支的文件

BASE - 共同的祖先,文件在两个变化之前看起来如何

REMOTE - 您正在合并到您的分支机构的文件

合并 - 合并结果,这是在回购中保存的内容

您可以使用ctrl+w在这些视图中导航。您可以使用ctrl+w后跟j直接到达 MERGED 视图。

有关 Vimdiff 可以导航更多信息在这里这里

第 4 步 。您可以通过以下方式编辑 MERGED 视图

如果您想从 REMOTE 获得更改

:diffg RE

如果您想从 BASE 获得更改

:diffg BA

如果您想从 LOCAL 获得更改

:diffg LO

第 5 步 。保存,退出,提交和清理

:wqa保存并退出 vi

git commit -m "message"

git clean删除 diff 工具创建的额外文件(例如 * .orig)。

这是一个可能的用例,从顶部:

你要做一些改变,但是哎呀,你不是最新的:

git fetch origin
git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.

所以你得到最新的并再试一次,但是有冲突:

git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.

所以你决定看一下这些变化:

git mergetool

哦,我,我的,上游改变了一些事情,但只是为了使用我的改变...... 不...... 他们的改变......

git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"

然后我们尝试最后一次

git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Already up-to-date.

当当!

我发现合并工具很少帮助我理解冲突或解决方案。我通常更成功地在文本编辑器中查看冲突标记并使用 git log 作为补充。

以下是一些提示:

提示一

我发现的最好的事情是使用 “diff3” 合并冲突风格:

git config merge.conflictstyle diff3

这会产生如下冲突标记:

<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a 
feature/topic branch.
>>>>>>>

中间部分是共同祖先的样子。这很有用,因为您可以将它与顶部和底部版本进行比较,以更好地了解每个分支上的更改内容,从而更好地了解每个更改的目的。

如果冲突只有几行,这通常会使冲突非常明显。 (知道如何解决冲突是非常不同的; 你需要知道其他人正在做什么。如果你感到困惑,最好是把那个人叫到你的房间,这样他们就能看到你在看什么在。)

如果冲突时间较长,那么我会将这三个部分中的每一部分剪切并粘贴到三个单独的文件中,例如 “我的”,“普通” 和 “他们的”。

然后我可以运行以下命令来查看导致冲突的两个差异:

diff common mine
diff common theirs

这与使用合并工具不同,因为合并工具也将包括所有非冲突的差异。我觉得这会分散注意力。

提示二

有人已经提到了这一点,但理解每个差异背后的意图通常对于理解冲突的来源和如何处理它非常有帮助。

git log --merge -p <name of file>

这显示了在共同祖先和要合并的两个头之间触及该文件的所有提交。 (因此它不包括在合并之前已存在于两个分支中的提交。)这有助于您忽略明显不是当前冲突因素的差异。

提示三

使用自动化工具验证您的更改。

如果您有自动化测试,请运行它们。如果你有一个棉绒 ,那就跑吧。如果它是一个可构建的项目,那么在你提交之前构建它等等。在所有情况下,你需要做一些测试,以确保你的更改没有破坏任何东西。 (哎呀,即使没有冲突的合并也会破坏工作代码。)

提示四

未雨绸缪; 与同事沟通。

提前规划并了解其他人正在进行的工作可以帮助防止合并冲突和 / 或帮助他们提前解决 - 而细节仍然是新鲜的。

例如,如果您知道您和另一个人都在进行不同的重构,这两个重构都会影响同一组文件,那么您应该提前相互交谈,并更好地了解每个人的变化类型。制造。如果您按顺序而不是并行地执行计划的更改,则可能会节省大量时间和精力。

对于跨越大量代码的主要重构,您应该强烈考虑连续工作:当一个人执行完整的重构时,每个人都停止在代码的该区域工作。

如果你不能连续工作(由于时间压力,也许),那么沟通预期的合并冲突至少可以帮助你更快地解决问题,同时细节仍然是新鲜的。例如,如果同事在一周的时间内进行了一系列破坏性的提交,您可以选择在该周期间每天一次或两次合并 / 重组该同事分支。这样,如果你确实发现了合并 / rebase 冲突,你可以比等待几周将所有内容合并成一个大块的更快地解决它们。

提示五

如果您不确定合并,请不要强迫它。

合并可能会让人感到压力,特别是当存在大量冲突文件且冲突标记覆盖数百行时。通常在评估软件项目时,我们没有足够的时间来处理开销项目,例如处理粗糙的合并,因此花费几个小时来解决每个冲突感觉真的很麻烦。

从长远来看,提前规划并了解其他人正在开展的工作是预测合并冲突并准备好在更短的时间内正确解决冲突的最佳工具。