Close

Git 合并冲突

版本控制系统就是管理多个分布式作者(通常是开发人员)之间的贡献。有时,多个开发人员可能会尝试编辑相同的内容。如果开发人员 A 尝试编辑开发人员 B 正在编辑的代码,则可能会发生冲突。为了缓解冲突的发生,开发人员将在单独的独立分支中工作。git merge 命令的主要职责是合并不同的分支并解决所有冲突的编辑。


了解合并冲突


冲突通常发生在两个人变更文件中的相同行时,或者一个开发人员在另一个开发人员修改文件时删除了文件。在这些情况下,Git 无法自动确定什么是正确的操作。冲突只影响进行合并的开发人员,团队的其他成员没有意识到冲突。Git 会将文件标记为冲突并停止合并流程。然后就由开发人员来解决冲突。

合并冲突的类型


合并可以在两个不同的点进入冲突状态:开始合并和合并流程中。以下是关于如何解决每种冲突情景的讨论。

Git 无法启动合并

当 Git 发现当前项目的工作目录或暂存区域有变化时,将无法启动合并。Git 无法启动合并,因为这些待处理变更可能会被合并的提交写入。发生这种情况时,不是因为与其他开发人员的冲突,而是因为与待处理的本地变更发生冲突。需要使用 git stashgit checkoutgit commitgit reset 来稳定本地状态。启动时合并失败将输出以下错误消息:

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)

Git 在合并过程中失败

合并期间的失败表示当前本地分支和正在合并的分支之间存在冲突。这表明与其他开发人员的代码存在冲突。Git 会尽力合并文件,但会将冲突文件中的问题留给您手动解决。合并中期失败将输出以下错误消息:

控制台窗口
相关资料

高级 Git 日志

Bitbucket 徽标
查看解决方案

了解 Bitbucket Cloud 的 Git

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

创建合并冲突


为了真正熟悉合并冲突,下一节将模拟冲突,供以后研究和解决。该示例将使用类似 Unix 的命令行 Git 接口来执行示例模拟。

$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[main (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt

此代码示例执行了一系列命令来完成以下操作。

  • 创建一个名为 git-merge-test 的新目录,切换到该目录,然后将其初始化为新的 Git 代码存储库。
  • 创建一个包含一些内容的新文本文件 merge.txt
  • merge.txt 添加到代码存储库并提交。

现在我们有了一个新的代码存储库,其中包含一个分支 main 和一个包含内容的 merge.txt 文件。接下来,我们将创建一个新分支用作冲突合并。

$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

接下来的命令序列实现了以下目的:

  • 创建并签出一个名为 new_branch_to_merge_later 的新分支
  • 覆盖 merge.txt 中的内容
  • 提交新内容

有了这个新分支:new_branch_to_merge_later,我们创建了一个覆盖 merge.txt 内容的提交

git checkout main
Switched to branch 'main'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[main 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)

这条命令链签出 main 分支,将内容附加到 merge.txt,然后提交。现在,这使我们的示例代码存储库处于有 2 个新提交的状态。一个在 main 分支,另一个在 new_branch_to_merge_later 分支中。此时 git merge new_branch_to_merge_later,看看会发生什么!

$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

爆炸 💥。出现冲突。谢谢 Git 告诉我们这件事!

如何识别合并冲突


正如我们在前面示例中所经历的那样,Git 将生成一些描述性输出,让我们知道冲突已经发生了。我们可以通过运行 git status 命令获得进一步的见解

$ git status
On branch main
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:   merge.txt

git status 的输出表明,由于冲突,存在未合并的路径。merge.text 文件现在显示为已修改状态。我们检查一下文件,看看修改了什么。

$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later

这里我们使用 cat 命令发布了 merge.txt 文件的内容。我们可以看到一些奇怪的新增内容

  • <<<<<<< HEAD
  • =======
  • >>>>>>> new_branch_to_merge_later

可以把这些新的行看作是"冲突分隔符"。======= 行是冲突的"中心"。中心行和 <<<<<<< HEAD 行之间的所有内容都是存在于 HEAD 引用指向的当前主分支中的内容。或者,介于中心和 >>>>>>> new_branch_to_merge_later 之间的所有内容都是存在于我们的合并分支中的内容。

如何使用命令行解决合并冲突


解决合并冲突的最直接方法是编辑冲突文件。在您最喜欢的编辑器中打开 merge.txt 文件。在我们的示例中,我们只是删除所有冲突分隔符。修改后的 merge.txt 内容应该如下所示:

this is some content to mess with
content to append
totally different content to merge later

编辑完文件后,使用 git add merge.txt 暂存新的合并内容。要完成合并,请执行以下命令创建一个新提交:

git commit -m "merged and resolved the conflict in merge.txt"

Git 将看到冲突已解决,并创建新的合并提交以完成合并。

可以帮助解决合并冲突的 Git 命令


通用工具

git status

使用 Git 时经常使用状态命令,在合并过程中,它将帮助识别冲突文件。

git log --merge

--merge 参数传递给 git log 命令将生成一个日志,其中包含合并分支之间冲突的提交列表。

git diff

diff 有助于找出存储库/文件状态之间的差异。这对于预测和防止合并冲突很有用。

git 无法启动合并时的工具

git checkout

checkout 可用于撤销对文件的变更或变更分支

git reset --mixed

reset 可用于撤销对工作目录和暂存区域的变更。

合并期间出现 git 冲突时的工具

git merge --abort

使用 --abort 选项执行 git merge 将退出合并流程,并将分支恢复到合并开始之前的状态。

git reset

可以在合并冲突期间使用 Git reset 将冲突文件重置为已知的良好状态

摘要


合并冲突可能是一种令人生畏的经历。幸运的是,Git 提供了强大的工具来帮助导航和解决冲突。Git 可以通过自动合并功能自行处理大多数合并。当两个不同的分支对文件中的同一行进行编辑时,或者当一个分支中的文件被删除但在另一个分支中编辑时,就会发生冲突。在团队环境中工作时,很可能会发生冲突。

有许多工具可以帮助解决合并冲突。我们在这里讨论过 Git 有很多命令行工具。有关这些工具的更多详细信息,请访问 git loggit resetgit statusgit checkoutgit reset 的独立页面。除了 Git 外,许多第三方工具还提供简化的合并冲突支持功能。


分享此文章
下一主题

推荐阅读

将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。

人们通过满是工具的墙进行协作

Bitbucket 博客

Devops 示意图

DevOps 学习路径

与 Atlassian 专家一起进行 Den 功能演示

Bitbucket Cloud 与 Atlassian Open DevOps 如何协同工作

注册以获取我们的 DevOps 新闻资讯

Thank you for signing up