解决 Git 合并冲突

合并冲突通常是处理复杂开发项目的一部分。在本指南中,我们将了解如何处理它们,以及它们何时发生。

什么时候发生合并冲突?#

如果您对您所在的分支上的同一个文件进行了更改,那么 Git 中的合并冲突将会发生,并且您尝试合并到的那个文件。在这种情况下,Git 不知道应该使用哪一个——所以它会抛出一个合并冲突错误。

考虑file.mdmain分支和my-branch. 当我们 checkoutmain并尝试 merge my-branchintomain时,会遇到以下错误:

git merge my-branch

Auto-merging file.md
CONFLICT (content): Merge conflict in file.md
Automatic merge failed; fix conflicts and then commit the result.

Git 不知道在这里做什么,所以尝试解决它是我们的工作。

稳定当前分支#

有时,当我们尝试合并文件时,合并会完全失败:

error: Your local changes to the following files would be overwritten by merge:
        file.md
Please commit your changes or stash them before you merge.

发生这种情况是因为我们在当前分支上有未提交的更改。在合并之前,我们需要关闭当前分支上的所有更改。为此,您可以运行git stash我在这里更详细地介绍了 git stash),或者您可以简单地在此分支上提交您的更改以使其稳定:

git add -A
git commit -m "My commit message"

现在我们的分支已经稳定了,我们可以尝试运行git merge my-branchmy-branch你的分支在哪里)将我们的分支合并回main. 如果我们现在遇到合并冲突,我们需要解决它们。

如何通过 GUI 解决 git 中的合并冲突#

如果您使用的是现代代码编辑器(如 Visual Studio Code),则合并冲突将出现在 GUI 中,您可以在其中接受传入的更改或接受分支上的当前更改。这提供了一种非常简单的方法来解决您的冲突。在 Visual Studio Code 中,这通过如下所示的 GUI 在冲突文件中表示。您有多种选择:

  • “接受当前更改” – 这将使用您当前分支的内容。
  • “Accept Incoming Changes” – 这将使用您正在合并的分支中的内容。
  • “Accept Both Changes” – 这将保持两者,一个在另一个之下。
  • “比较更改” – 这将打开一个额外的屏幕来并排比较更改。

查看所有冲突后,您可以添加文件并正常提交它们:

git add -A
git commit -m "My commit message"

如何通过终端解决 git 中的合并冲突

在某些情况下,您可能没有用于解决合并冲突的 GUI。您可以使用许多命令。

首先git status会告诉你受影响的文件:

git status
On branch my-branch
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   file.md

no changes added to commit (use "git add" and/or "git commit -a")

正如我们所看到的,只有file.md受到影响。接下来,我们可以git diff用来查看这个分支和我们要合并的分支之间的区别:

++<<<<<<< HEAD
 +Some  a
 +Some b
 +Some conflict c 
 +Some conflict d
 +Some e
++=======
+ Some conflict 1
+ Some b
+ Some conflict c
+ Some conflict 2
 -Some f
++Some f
++>>>>>>> main

在这里,++<<<<<<<之前和之后的所有内容都++=======代表当前分支的更改,而++=======之前和之后的所有内容都++>>>>>>> main代表您要合并的分支。

我们还可以通过运行查看冲突的提交git log --merge

在合并冲突期间中止合并

有时你意识到你在这个合并冲突上有点太深了——在这种情况下,你可以通过运行git merge --abort.

git merge --abort

这将使我们回到非合并状态,因此我们可以在两个分支中手动解决合并冲突,然后再尝试再次合并。

通过接受传入或当前更改来解决

解决某些文件合并冲突的另一种简单方法--theirs--oursgit checkout. 我们的合并冲突是 on file.md。如果我想接受file.md来自我试图合并的分支的所有传入更改,我可以写:

git checkout --theirs file.md

这会检查file.md“他们的”代码版本。如果我想在当前分支中使用该版本,我会使用--ours. 两者都--ours需要--theirs一个文件作为参数 – 所以这必须在一个文件一个文件的基础上完成。

容易,对吧?这对于合并整个文件来说很好,但是如果我们在一个文件中有多个合并冲突怎么办?

通过编辑文件本身来解决

请记住,当您创建 git 合并冲突时,我们最终得到的内容在我们运行时看起来像这样git diff

++<<<<<<< HEAD
 +Some  a
 +Some b
 +Some conflict c 
 +Some conflict d
 +Some e
++=======
+ Some conflict 1
+ Some b
+ Some conflict c
+ Some conflict 2
 -Some f
++Some f
++>>>>>>> main

该内容也存在于发生冲突的文件中(当然没有+and -)。如果您想在没有 GUI 帮助的情况下解决合并冲突,最简单的方法是转到有问题的文件,然后简单地删除您不想接受的部分。这只是意味着删除和之间的文本<<<<<<< HEAD=======如果你想接受当前,或者之间的文本=======>>>>>>>如果你想接受传入。

添加和提交您的更改

解决合并冲突后,不要忘记在当前分支上添加并提交更改,以便它们保持保存:

git add -A
git commit -m "Merge message"

结论#

我们的代码编辑器中有强大的工具来解决合并冲突。话虽如此,有时环境中的限制意味着我们必须解决自己的 git 合并错误 – 或者我们可能更喜欢从终端完成这项工作。一些特定的边缘情况也可能意味着我们必须从终端完成这项工作。

无论如何,合并冲突是 git 开发的一部分,只需从存在冲突的文件中删除我们不再需要的内容即可解决它们。我们还可以使用git checkout --theirsgit checkout --ours更快地解决问题。