我该如何解决Git仓库中的合并冲突?
我该如何解决Git仓库中的合并冲突?
尝试:
git mergetool
它打开一个GUI,引导您通过每个冲突,并允许您选择如何合并。有时候需要一些手动编辑,但通常这已经足够了。这比完全手工完成要好得多。
根据 Josh Glover 的评论:
[此命令] 不一定会打开GUI,除非你安装了一个。对我而言运行
git mergetool
导致使用vimdiff
。你可以安装以下工具中的一个来代替它:meld
、opendiff
、kdiff3
、tkdiff
、xxdiff
、tortoisemerge
、gvimdiff
、diffuse
、ecmerge
、p4merge
、araxis
、vimdiff
、emerge
。
下面是使用 vimdiff
解决合并冲突的示例过程,基于此链接。
在终端中运行以下命令:
git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false
这将把vimdiff
设置为默认的合并工具。
在终端中运行以下命令。
git mergetool
您将会看到一个如下格式的 vimdiff
显示: ╔═══════╦══════╦════════╗
║ ║ ║ ║
║ LOCAL ║ BASE ║ REMOTE ║
║ ║ ║ ║
╠═══════╩══════╩════════╣
║ ║
║ MERGED ║
║ ║
╚═══════════════════════╝
这4个视图分别是:
你可以使用 ctrl+w 在这些视图中导航。你可以直接使用 ctrl+w 后跟 j 来直接进入 MERGED 视图。
你可以像这样编辑MERGED视图:
如果你想从REMOTE获取更改
:diffg RE
如果您想从BASE获取更改
:diffg BA
如果您想从本地获取更改
:diffg LO
保存、退出、提交和清理
:wqa
保存并退出 vi
git commit -m "message"
git clean
删除额外的文件(例如*.orig
)。警告:如果不传递任何参数,它将删除所有未跟踪的文件。
git mergetool
使用的是vimdiff
。您可以安装以下工具之一来代替使用:meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis vimdiff emerge
。 - Josh Glovergit mergetool -t bc3
)来进行操作。 - AzP以下是一个可能的使用案例,从最上面开始:
你将要拉取一些更改,但糟糕的是,你不是最新的:
git fetch origin
git pull origin master
From ssh://gitosis@example.com: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://gitosis@example.com: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://gitosis@example.com:22/projectname
* branch master -> FETCH_HEAD
Already up-to-date.
哒哒!
git merge --help
。 - mmell<<<<<<<
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>
diff3
选项是合并时非常有用的功能。我遇到的唯一一个显示它的图形用户界面是Perforce的 p4merge
,可以单独安装和使用,与Perforce的其他工具分开(我没用过,但听说有人抱怨)。 - alxndrdiff3
,这是一个大加分项。默认的冲突样式使得一些冲突无法解决。更多信息请参见https://dev59.com/pl4c5IYBdhLWcg3w59qQ#63739655。 - Tom Ellis确定哪些文件有冲突(Git 会告诉你)。
打开每个文件并查看差异;Git 会标记它们。希望很明显哪个版本的每个块应该保留。您可能需要与提交代码的其他开发人员讨论。
解决了文件中的冲突后,运行git add the_file
。
一旦您解决了所有冲突,请运行 git rebase --continue
或者 Git 在完成时提示执行的任何命令。
git add
将文件加入索引,但不会将其添加到仓库中。 git commit
才是将内容添加到仓库中的命令。这种用法对于合并操作很有意义——合并会自动将所有能够自动合并的更改加入暂存区;您需要在完成剩下的更改并将它们添加到索引后进行合并。 - Mark E. Haase当多个人同时修改同一个文件时,就会发生合并冲突。以下是解决方法。
git
命令行界面以下是在出现冲突状态时应采取的简单步骤:
git status
命令查看冲突文件列表(在Unmerged paths
部分)。按以下任一方式逐个解决每个文件的冲突:
使用GUI解决冲突:git mergetool
(最简单的方法)。
接受远程/其他版本,请使用:git checkout --theirs path/file
。这将拒绝您对该文件所做的任何本地更改。
接受本地/我们的版本,请使用:git checkout --ours path/file
但是,您必须小心,因为冲突的远程更改有其原因。
手动编辑冲突文件,并查找<<<<<
/>>>>>
之间的代码块,然后从上面或下面的=====
中选择版本。请参阅:如何呈现冲突。
路径和文件名冲突可以通过git add
/git rm
解决。
最后,使用git status
命令查看准备提交的文件。
如果您仍然有任何Unmerged paths
下的文件,并且已经手动解决了冲突,则通过以下方式让Git知道您已经解决了它:git add path/file
。
如果所有冲突都已成功解决,请使用git commit -a
提交更改,并像往常一样推送到远程。
另请参阅:GitHub上的从命令行解决合并冲突。
查看实用教程,请访问:Katacoda的场景5 - 修复合并冲突。
我成功地使用了DiffMerge,它可以在Windows、macOS和Linux/Unix上直观地比较和合并文件。
它可以图形化地显示3个文件之间的更改,并允许自动合并(安全时)和完全控制编辑结果文件。
图片来源: DiffMerge (Linux 截图)
只需下载并在仓库中运行即可:
git mergetool -t diffmerge .
在 macOS 上,您可以通过以下方式安装:
brew install caskroom/cask/brew-cask
brew cask install diffmerge
如果没有提供,您可能需要以下额外的简单包装器放置在您的路径中(例如 /usr/bin
):
#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"
请查看Stack Overflow问题中的答案Aborting a merge in Git,特别是Charles Bailey的答案,它展示了如何查看存在问题的文件的不同版本,例如:
# Common base version of the file.
git show :1:some_file.cpp
# 'Ours' version of the file.
git show :2:some_file.cpp
# 'Theirs' version of the file.
git show :3:some_file.cpp
ours
还是 theirs
,那么之后,我该如何确定哪个选项被选择并在工作树和暂存区中准备提交? - tarekahfgit log --merge
查看提交注释,然后使用git diff
来查看冲突。git config merge.tool "your.tool"
将设置你选择的工具,然后在合并失败后使用git mergetool
即可显示差异和上下文。git add filename
将更新索引,并且你的差异将不再显示。当处理完所有冲突并将它们的文件git add
后,git commit
将完成合并。我希望能够全面接受我的版本或他们的版本,或者对每个变更进行审核并分别决定是否接受。
全面接受我的或他们的版本:
接受我的版本(本地,我们的):
git checkout --ours -- <filename>
git add <filename> # Marks conflict as resolved
git commit -m "merged bla bla" # An "empty" commit
接受他们的版本(远程,他们的):
git checkout --theirs -- <filename>
git add <filename>
git commit -m "merged bla bla"
如果您想针对所有冲突文件进行操作,请运行以下命令:
git merge --strategy-option ours
或者
git merge --strategy-option theirs
审查所有更改并逐个接受
git mergetool
git add <filename>
git commit -m "merged bla bla"
默认的mergetool
在命令行中工作。如何使用命令行mergetool应该是一个单独的问题。
您也可以安装用于此操作的可视化工具,例如meld
并运行
git mergetool -t meld
它将会打开本地版本(我们的),"base"或者"merged"版本(合并后的当前结果)以及远程版本(他们的)。当你完成后保存合并版本,再次运行git mergetool -t meld
直到得到"No files need merging",然后继续步骤3和4。
请参阅如何呈现冲突或者在Git中查看git merge
文档,以了解合并冲突标记的含义。
此外,如何解决冲突部分详细说明了如何解决这些冲突:
看到了冲突后,你可以做两件事情:HEAD
提交以撤销2和清理工作树更改所做的3; 可以使用 git merge --abort
。git add
。使用git commit
来完成操作。git mergetool
启动图形合并工具,指导你完成合并。
- 查看差异。使用git diff
显示三方差异,突出显示来自HEAD
和MERGE_HEAD
版本的更改。
- 查看每个分支的差异。git log --merge -p <path>
将首先显示HEAD
版本的差异,然后是MERGE_HEAD
版本的差异。
- 查看原始版本。git show :1:filename
显示共同的祖先,git show :2:filename
显示HEAD
版本,git show :3:filename
显示MERGE_HEAD
版本。
对于希望半自动解决合并冲突的Emacs用户:
git diff --name-status --diff-filter=U
显示需要解决冲突的所有文件。emacs $(git diff --name-only --diff-filter=U)
访问需要在Emacs中进行编辑的缓冲区时,请输入
ALT+x vc-resolve-conflicts
这将会打开三个缓冲区(我的缓冲区、他们的缓冲区和输出缓冲区)。按下'n'(下一个区域)、'p'(上一个区域)来切换。按下'a'和'b'分别将我的或他们的区域复制到输出缓冲区,或者直接编辑输出缓冲区。
完成后:按下'q'。Emacs会询问您是否要保存此缓冲区:是。 完成缓冲区标记为已解决,通过从终端运行:
git add FILENAME
完成所有缓存后,输入以下命令:
git commit
完成合并。