如何解决 Git 存储库中的合并冲突?

git git-merge merge-conflict-resolution git-merge-conflict

如何解决 Git 存储库中的合并冲突?

下面的博客文章似乎给出了一个很好的例子,说明如何处理与 Git 的合并冲突,这应该会让你朝着正确的方向前进。 Handling and Avoiding Conflicts in Git

您可以配置一个合并工具 (kdiff3 jebaird.com/2013/07/08/…),然后使用 git mergetool。当您在大型开发团队中工作时,您总会遇到合并冲突。

不要忘记,您可以通过定期合并下游来缓解大多数合并冲突!

另见git-tower.com/learn/git/ebook/command-line/tools-services/…

这似乎是一个详细的教程 - githubtraining.com/fix-merge-conflict-git-using-sourcetree

M
Mateen Ulhaq

尝试:

git mergetool

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

根据 Josh Glover's comment

[此命令] 不一定会打开 GUI,除非您安装一个。为我运行 git mergetool 导致使用 vimdiff。您可以安装以下工具之一来使用它:meld、opendiff、kdiff3、tkdiff、xxdiff、tortoisemerge、gvimdiff、diffuse、ecmerge、p4merge、araxis、vimdiff、emerge。

以下是基于 this link 使用 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 - 您正在合并到您的分支的文件

MERGED - 合并结果,这是保存在 repo 中的内容

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

关于 vimdiff 导航的更多信息是 herehere

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

如果您想从 REMOTE 获取更改

:diffg RE

如果您想从 BASE 获取更改

:diffg BA

如果您想从 LOCAL 获取更改

:diffg LO

第 5 步:保存、退出、提交和清理

:wqa 保存并退出 vi

git commit -m "message"

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

仅供参考,如果您一次合并大量文件,您可以使用 git mergetool -y 来节省一些击键。

好吧,除非您安装它,否则它不一定会打开 GUI。为我运行 git mergetool 导致使用了 vimdiff。您可以安装以下工具之一来使用它:meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis vimdiff emerge

好点乔希。在 ubuntu 上,我的 meld 运气最好,它的三向合并显示还不错。在 OSX 上,git 选择了一个不错的默认值。

这打开了 KDiff3。我完全不知道如何使用。

您现在也可以使用 Beyond Compare 3 (git mergetool -t bc3)。

P
Peter Mortensen

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

您将进行一些更改,但是糟糕,您不是最新的:

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.

达达!

这非常有用,因为我有很多与二进制文件(艺术资产)的合并错误并且合并这些似乎总是失败,所以我需要总是用新文件覆盖它而不是“合并”

小心! --ours 和 --theirs 的含义相反。 --ours == 遥控器。 --他们的==本地的。请参阅git merge --help

就我而言,我确认 --theirs = 远程存储库,--ours = 我自己的本地存储库。这与@mmell 评论相反。

@mmell 显然,仅在变基上。请参阅this question

伙计们,“我们的”和“他们的”是相对于你是合并还是变基。如果您要合并,那么“我们的”表示您要合并到的分支,而“他们的”是您要合并的分支。当您变基时,“我们的”表示您要变基的提交,而“他们的”是指您想要变基的提交。

P
Peter Mortensen

我发现合并工具很少能帮助我理解冲突或解决方案。我通常更成功地在文本编辑器中查看冲突标记并使用 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.
>>>>>>>

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

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

如果冲突时间较长,那么我会将三个部分分别剪切并粘贴到三个单独的文件中,例如“mine”、“common”和“theirs”。

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

diff common mine
diff common theirs

这与使用合并工具不同,因为合并工具也会包含所有不冲突的差异数据块。我觉得这让人分心。

提示二

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

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

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

提示三

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

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

提示四

未雨绸缪;与同事沟通。

提前计划并了解其他人正在做什么可以帮助防止合并冲突和/或帮助更早地解决它们 - 而细节仍然是新鲜的。

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

对于跨越大量代码的重大重构,您应该强烈考虑按顺序工作:每个人都停止在代码的那个区域工作,而一个人执行完整的重构。

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

提示五

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

合并可能会让人感到不知所措,尤其是当有很多冲突文件并且冲突标记覆盖数百行时。通常在估算软件项目时,我们没有足够的时间来处理诸如处理复杂合并之类的开销项目,因此花几个小时剖析每个冲突感觉真的很累。

从长远来看,提前计划并了解其他人正在做什么是预测合并冲突并准备在更短的时间内正确解决它们的最佳工具。

diff3 选项是合并的一个很棒的功能。我遇到的唯一显示它的 GUI 是 Perforce 的 p4merge,它可以与 Perforce 的其他工具分开安装和使用(我没有使用过,但听说过抱怨)。

在导致合并冲突的 rebase 尝试之后:$ git log --merge -p build.xml 输出:致命:--merge without MERGE_HEAD?

git config merge.conflictstyle diff3 - 谢谢您,先生。这是惊人的,并让我从试图找到(并支付 $$)一个好的 3 路合并 GUI 中解脱出来。 IMO这更好,因为它显示了共同的祖先以及本地/远程,显示了(AFAIK)没有GUI的最后提交日志行。提交绝对可以帮助您确定哪些代码属于哪个分支。

我发现,有时 diff3 冲突风格会导致大量相同的 diff 数据块,而默认设置会产生更小、更易于管理的数据块。不幸的是,我没有可用于错误报告的复制器。但如果您遇到此问题,您可能会考虑暂时关闭该选项。

大 +1 推荐 diff3。默认的冲突风格使得一些冲突实际上无法解决。有关详细信息,请参阅 stackoverflow.com/questions/27417656/…

d
davetron5000

确定哪些文件存在冲突(Git 应该告诉你这一点)。打开每个文件并检查差异; Git 对它们进行了划分。希望保留每个块的哪个版本是显而易见的。您可能需要与提交代码的其他开发人员讨论它。一旦你解决了文件中的冲突 git add the_file.解决所有冲突后,请执行 git rebase --continue 或 Git 在您完成时要求执行的任何命令。

@Justin 将 Git 视为跟踪内容而不是跟踪文件。然后很容易看到你更新的内容不在存储库中,需要添加。这种思维方式也解释了为什么 Git 不跟踪空文件夹:虽然它们在技术上是文件,但没有任何内容可以跟踪。

内容在那里,发生冲突是因为有 2 个版本的内容。因此“git add”听起来不正确。如果您只想在解决冲突后提交一个文件(“致命:在合并期间无法进行部分提交”),它不起作用(git add,git commit)。

是的,从技术上讲,这回答了所提出的问题,但在我看来,这不是一个可用的答案,对不起。使一个分支与另一个分支相同有什么意义?当然合并会有冲突..

Thulfir:谁说过要让一个分支和另一个分支一样?有不同的场景需要合并,而不是“使一个分支与另一个分支相同”。一种是当您完成一个开发分支并希望将其更改合并到主分支中时;在此之后,可以删除开发分支。另一个是当你想重新定位你的开发分支时,以简化最终合并到 master 中的过程。

@JustinGrant git add 在索引中暂存文件;它确实向存储库添加任何内容。 git commit 将内容添加到存储库。这种用法对合并有意义——合并会自动暂存所有可以自动合并的更改;完成后,您有责任合并其余更改并将其添加到索引中。

k
kenorb

当同时对文件进行更改时,会发生合并冲突。以下是如何解决它。

命令行界面

以下是当您进入冲突状态时要执行的简单步骤:

请注意冲突文件列表: git status (在未合并路径部分下)。通过以下方法之一分别解决每个文件的冲突: 使用 GUI 解决冲突:git mergetool(最简单的方法)。要接受远程/其他版本,请使用:git checkout --theirs path/file。这将拒绝您对该文件所做的任何本地更改。要接受本地/我们的版本,请使用: git checkout --ours path/file 但是你必须小心,因为远程更改是由于某种原因而发生的冲突。相关:git中“我们的”和“他们的”的确切含义是什么?手动编辑冲突文件并在 <<<<>>>>> 之间查找代码块,然后从上面或下面选择版本 =====。请参阅:如何呈现冲突。路径和文件名冲突可以通过 git add/git rm 解决。最后,使用以下命令查看准备提交的文件:git status。如果您在未合并的路径下仍有任何文件,并且您确实手动解决了冲突,那么让 Git 知道您通过以下方式解决了它:git add path/file。如果所有冲突都已成功解决,请通过以下方式提交更改: git commit -a 并像往常一样推送到远程。

另请参阅:GitHub 上的 Resolving a merge conflict from the command line

如需实用教程,请查看:Scenario 5 - Fixing Merge Conflicts by Katacoda

差异合并

我已成功使用 DiffMerge,它可以在 Windows、macOS 和 Linux/Unix 上直观地比较和合并文件。

它可以以图形方式显示 3 个文件之间的更改,并允许自动合并(在安全的情况下)和对编辑结果文件的完全控制。

https://i.stack.imgur.com/tAURE.png

图片来源:DiffMerge(Linux 截图)

只需下载它并在 repo 中运行:

git mergetool -t diffmerge .

苹果系统

在 macOS 上,您可以通过以下方式安装:

brew install caskroom/cask/brew-cask
brew cask install diffmerge

并且可能(如果未提供)您需要在 PATH 中放置以下额外的简单包装器(例如 /usr/bin):

#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"

然后,您可以使用以下键盘快捷键:

⌘-Alt-Up/Down 跳转到上一个/下一个更改。

⌘-Alt-Left/Right 接受左侧或右侧的更改

或者,您可以使用 opendiff(Xcode 工具的一部分),它允许您将两个文件或目录合并在一起以创建第三个文件或目录。

C
Community

查看 Stack Overflow 问题 Aborting a merge in Git 中的答案,尤其是 Charles Bailey's answer,它显示了如何查看有问题的文件的不同版本,例如,

# 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

还可以查看“git checkout -m”的“-m”选项 - 它允许您将不同的苍蝇提取回您的工作区

这救了我。分别查看每个文件让我记住了我在每个分支中的目标。然后我可以做出选择的决定。

P
Peter Mortensen

如果您经常进行小型提交,请先查看带有 git log --merge 的提交注释。然后 git diff 将显示冲突。

对于涉及多行的冲突,更容易查看外部 GUI 工具中发生的情况。我喜欢 opendiff——Git 还支持 vimdiff、gvimdiff、kdiff3、tkdiff、meld、xxdiff、emerge 开箱即用,您可以安装其他工具:git config merge.tool "your.tool" 将设置您选择的工具,然后在合并失败后显示 git mergetool你在上下文中的差异。

每次您编辑文件以解决冲突时,git add filename 都会更新索引,您的差异将不再显示它。当所有冲突都得到处理并且它们的文件已经被 git add 编辑后,git commit 将完成您的合并。

使用“git add”是这里的真正诀窍。您甚至可能不想提交(也许您想隐藏),但您必须执行“git add”才能完成合并。我认为 mergetool 会为您完成添加(虽然它不在手册页中),但如果您手动进行合并,则需要使用“git add”来完成它(即使您不想提交)。

P
Peter Mortensen

我要么想要我的或他们的完整版本,要么想要查看个别更改并为每个更改做出决定。

完全接受我或他们的版本:

接受我的版本(本地,我们的):

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 <文件名> git commit -m "merged bla bla"

默认 mergetool命令行中工作。如何使用命令行合并工具应该是一个单独的问题。

您也可以为此安装 visual tool,例如 meld 并运行

git mergetool -t meld

它将打开本地版本(我们的)、“基础”或“合并”版本(合并的当前结果)和远程版本(他们的)。完成后保存合并后的版本,再次运行 git mergetool -t meld 直到出现“没有文件需要合并”,然后转到步骤 3 和 4。

C
Community

请参阅 How Conflicts Are Presented 或 Git 中的 git merge 文档以了解什么是合并冲突标记。

此外,How to Resolve Conflicts 部分解释了如何解决冲突:

看到冲突后,您可以做两件事: 决定不合并。您需要的唯一清理是将索引文件重置为 HEAD 提交以反转 2. 并清理 2. 和 3. 所做的工作树更改; git merge --abort 可用于此。解决冲突。 Git 将标记工作树中的冲突。将文件编辑成形状并将它们添加到索引中。使用 git commit 来达成交易。您可以使用多种工具来解决冲突: 使用合并工具。 git mergetool 启动一个图形化的合并工具,它将帮助你完成合并。看看差异。 git diff 将显示三向差异,突出显示 HEAD 和 MERGE_HEAD 版本的更改。查看每个分支的差异。 git log --merge -p 将首先显示 HEAD 版本的差异,然后是 MERGE_HEAD 版本。看看原件。 git show :1:filename 显示共同祖先, git show :2:filename 显示 HEAD 版本, git show :3:filename 显示 MERGE_HEAD 版本。

您还可以在Pro Git书籍部分Basic Merge Conflicts中了解合并冲突标记以及如何解决它们。

P
Peter Mortensen

对于想要半手动解决合并冲突的 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

完成合并。

P
Peter Mortensen

奖金:

在谈到之前答案中的拉/取/合并时,我想分享一个有趣且富有成效的技巧,

git pull --rebase

上面这个命令是我 Git 生活中最有用的命令,它节省了很多时间。

在将您新提交的更改推送到远程服务器之前,请尝试 git pull --rebase 而不是 git pull 和手动 merge,它会自动同步最新的远程服务器更改(使用 fetch + merge)并将您的本地最新提交放在顶部在 Git 日志中。无需担心手动拉/合并。

如果发生冲突,只需使用

git mergetool
git add conflict_file
git rebase --continue

在以下位置查找详细信息:What does “git pull –rebase” do?

P
Peter Mortensen

简单地说,如果您很清楚其中一个存储库中的更改并不重要,并且想要解决所有更改以支持另一个存储库,请使用:

git checkout . --ours

解决有利于您的存储库的更改,或

git checkout . --theirs

解决有利于其他或主存储库的更改。

否则您将不得不使用 GUI 合并工具逐个浏览文件,例如合并工具是 p4merge,或者写下您已经安装的任何人的名字

git mergetool -t p4merge

完成一个文件后,您必须保存并关闭,以便打开下一个文件。

混帐结帐。 --他们解决了我的问题谢谢

如果您更喜欢手动解决冲突,请尝试在 Visual Studio Code 中打开该文件夹,它会在每个文件中标记带有冲突和颜色冲突行的文件

P
Peter Mortensen

分为三个步骤:

通过命令 git status 查找哪些文件导致冲突检查文件,您会在其中找到标记为 <<<<<<

为我工作!谢谢!

如果在 rebase 期间这样做,您必须注意。您应该使用 git rebase --continue 而不是 git commit

P
Peter Mortensen

请按照以下步骤修复 Git 中的合并冲突:

检查 Git 状态: git status 获取补丁集: git fetch (从 Git 提交中签出正确的补丁) 签出本地分支(在我的示例中为 temp1): git checkout -b temp1 从 master 中提取最近的内容: git pull - -rebase origin master 启动mergetool并检查冲突并修复它们...并使用当前分支检查远程分支中的更改: git mergetool 再次检查状态: git status 删除mergetool本地创建的不需要的文件,通常是mergetool创建带有 *.orig 扩展名的额外文件。请删除该文件,因为它只是重复的并在本地修复更改并添加正确版本的文件。 git add #your_changed_correct_files 再次检查状态: git status 将更改提交到相同的提交 id(这避免了新的单独补丁集): git commit --amend 推送到主分支: git push (到您的 Git 存储库)

P
Peter Mortensen

CoolAJ86 的回答几乎概括了一切。如果您在同一段代码中对两个分支进行了更改,则必须进行手动合并。在任何文本编辑器中打开冲突文件,您应该会看到以下结构。

(Code not in Conflict)
>>>>>>>>>>>
(first alternative for conflict starts here)
Multiple code lines here
===========
(second alternative for conflict starts here)
Multiple code lines here too    
<<<<<<<<<<<
(Code not in conflict here)

以您希望新代码的方式选择一个替代方案或两者的组合,同时删除等号和尖括号。

git commit -a -m "commit message"
git push origin master
C
Community

正如其他人所详述的那样,您可以通过多种方式修复合并冲突。

我认为真正的关键是了解本地和远程存储库的变化是如何流动的。关键是理解跟踪分支。我发现我认为跟踪分支是我的本地、实际文件目录和定义为源的远程目录之间的“中间缺失的部分”。

我个人已经养成了两件事来帮助避免这种情况的习惯。

代替:

git add .
git commit -m"some msg"

这有两个缺点 -

a) 添加所有新的/更改的文件,其中可能包括一些不需要的更改。 b) 您没有先查看文件列表。

所以我这样做:

git add file,file2,file3...
git commit # Then type the files in the editor and save-quit.

这样,您可以更仔细地考虑添加哪些文件,并且您还可以查看列表并在使用消息编辑器时进行更多思考。我发现当我使用全屏编辑器而不是 -m 选项时,它还改进了我的提交消息。

[更新 - 随着时间的流逝,我已经切换到:

git status # Make sure I know whats going on
git add .
git commit # Then use the editor

]

另外(并且与您的情况更相关),我尽量避免:

git pull

或者

git pull origin master.

因为 pull 意味着合并,如果您在本地有不想合并的更改,您很容易以合并代码和/或不应该合并的代码的合并冲突结束。

相反,我尝试做

git checkout master
git fetch   
git rebase --hard origin/master # or whatever branch I want.

您可能还会发现这很有帮助:

git branch, fork, fetch, merge, rebase and clone, what are the differences?

嘿,我有点明白你的回答。但是由于我是 github 合并冲突的新手,所以我认为缺少一些东西。当您执行 git checkout mastergit fetchgit rebase --hard origin/master 时,您的本地修改会发生什么

我相信你应该添加更多关于做什么的细节。另一个让我困惑的例子,你在回答中提到:我们做 git add .,它会保存我们的本地修改以便我们可以跟进 git checkout master 吗?或者他们是两个不同的场景?

@MichaelDurrant $ git rebase --hard origin/master b5a30cc159ba8dd error: unknown option hard' 用法: git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] 或: git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>] 或: git rebase --continue | --中止 | --跳过 | --edit-todo `

H
Henry

如果您想从分支 test 合并到 master,您可以按照以下步骤操作:

第一步:去分行

git checkout test

第2步:

git pull --rebase origin master

第三步:如果有冲突,到这些文件去修改。

第 4 步:添加这些更改

git add #your_changes_files

第 5 步:

git rebase --continue

步骤 6:如果仍然存在冲突,请再次返回步骤 3。如果没有冲突,请执行以下操作:

git push origin +test

第7步:然后test和master之间就没有冲突了。您可以直接使用合并。

C
Conchylicultor

使用耐心

对于大的合并冲突,使用 patience 为我提供了很好的结果。它将尝试匹配块而不是单个行。

例如,如果您更改程序的缩进,默认的 Git 合并策略有时会匹配属于不同函数的单括号 {。使用 patience 可以避免这种情况:

git merge -s recursive -X patience other-branch

从文档中:

With this option, merge-recursive spends a little extra time to avoid 
mismerges that sometimes occur due to unimportant matching lines 
(e.g., braces from distinct functions). Use this when the branches to 
be merged have diverged wildly.

与共同祖先的比较

如果您有合并冲突并想看看其他人在修改他们的分支时的想法,有时将他们的分支直接与共同的祖先(而不是我们的分支)进行比较更容易。为此,您可以使用 merge-base

git diff $(git merge-base <our-branch> <their-branch>) <their-branch>

通常,您只想查看特定文件的更改:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch> <file>

就我而言,这并不能很好地解决合并冲突,因为由于某种原因,它在 C# 项目中保留了重复的配置行。虽然它比我以前拥有的 ENTIRE FILE IS DIFFERENT 更友好

s
stites
git log --merge -p [[--] path]

似乎并不总是对我有用,并且通常最终显示两个分支之间不同的每个提交,即使使用 -- 将路径与命令分开也会发生这种情况。

我要解决此问题的方法是打开两个命令行并一次运行

git log ..$MERGED_IN_BRANCH --pretty=full -p [path]

而在另一个

git log $MERGED_IN_BRANCH.. --pretty=full -p [path]

$MERGED_IN_BRANCH 替换为我合并的分支,将 [path] 替换为有冲突的文件。此命令将以补丁形式记录 (..) 两次提交之间的所有提交。如果您像上面的命令一样将一侧留空,git 将自动使用 HEAD (在这种情况下您要合并到的分支)。

这将允许您查看两个分支在分歧后进入文件的提交。它通常使解决冲突变得容易得多。

m
maxwell

截至 2016 年 12 月 12 日,您可以在 github.com 上合并分支并解决冲突

因此,如果您不想使用旧答案中提供的命令行或任何第 3 方工具,请使用 GitHub 的本机工具。

This blog post 详细解释,但基本情况是,通过 UI '合并'两个分支后,您现在将看到一个“解决冲突”选项,该选项将带您进入允许您处理这些合并冲突的编辑器。

https://i.stack.imgur.com/1YX5P.gif

这不是在询问 github,因此我否决了我认为非常糟糕的答案。

@mschuett 是对的,问题是“如何解决 git 中的冲突”,而不是“如何解决 github 中的冲突”。这是有区别的,已经有太多人认为 git 和 github 是同一个东西,所以任何传播这种感觉的东西都是错误的。

P
Peter Mortensen

合并冲突可能发生在不同的情况下:

运行 git fetch 然后运行 git merge

当运行 git fetch 然后 git rebase

运行 git pull 时(实际上等于上述条件之一)

运行 git stash pop 时

当您应用 git 补丁时(导出到要传输的文件的提交,例如,通过电子邮件)

您需要安装与 Git 兼容的合并工具来解决冲突。我个人使用 KDiff3,我发现它很好用。您可以在此处下载其 Windows 版本:

https://sourceforge.net/projects/kdiff3/files/

顺便说一句,如果你安装了 Git Extensions,它的设置向导中有一个选项可以安装 Kdiff3。

然后设置 Git 配置以使用 KDiff3 作为其合并工具:

$ git config --global --add merge.tool kdiff3
$ git config --global --add mergetool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add mergetool.kdiff3.trustExitCode false

$ git config --global --add diff.guitool kdiff3
$ git config --global --add difftool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add difftool.kdiff3.trustExitCode false

(记得用KDiff3 EXE文件的实际路径替换路径。)

然后每次遇到合并冲突时,只需运行以下命令:

$ git mergetool

然后它打开 Kdiff3,并首先尝试自动解决合并冲突。大多数冲突会自发解决,您需要手动修复其余冲突。

这是 Kdiff3 的样子:

https://i.stack.imgur.com/Xw3nw.png

然后一旦你完成,保存文件,它会转到下一个有冲突的文件,你再次做同样的事情,直到所有的冲突都得到解决。

要检查所有内容是否合并成功,只需再次运行 mergetool 命令。你应该得到这个结果:

$ git mergetool
No files need merging

我对这个问题的回答应该像这个一样向用户提示 ((git mergetool)) 。讲述 IDE 相关提示是不相关的。

P
Peter Mortensen

我总是按照以下步骤来避免冲突。

git checkout master(来到master分支)

git pull (更新你的主人以获得最新的代码)

git checkout -b mybranch (签出一个新的分支并开始在该分支上工作,以便您的主干始终保持在主干的顶部。)

混帐添加。和 git commit 和 git push (在您更改后的本地分支上)

git checkout master(回到你的主人那里)

现在,您可以通过在必要时对您的分支执行 git checkout 来执行相同的操作并维护所需的多个本地分支并同时工作。

P
Peter Mortensen

适用于 Visual Studio 代码的 GitLens

您可以为 Visual Studio Code 尝试 GitLens。主要特点是:

3. 轻松解决冲突

我已经喜欢这个功能了:

https://i.stack.imgur.com/4YBdY.png

2. 当前线责。

https://i.stack.imgur.com/LuqoC.png

3. 天沟责备

https://i.stack.imgur.com/giS9K.png

4.状态栏责备

https://i.stack.imgur.com/ZO7pm.png

并且有很多特点。您可以检查它们here

我用过的最好的工具之一,我仍然在我的所有项目中使用它!

s
stevec

我明白什么是合并冲突,但是当我看到 git diff 的输出时,起初对我来说似乎是无稽之谈:

git diff
++<<<<<<< HEAD
 + display full last name boolean in star table
++=======
+ users viewer.id/star.id, and conversation uses user.id
+
++>>>>>>> feat/rspec-tests-for-cancancan

但是 here 帮助了我:

<<<<<<< 和 ======= 之间的所有内容都是一个文件中的内容,并且

======= 和 >>>>>> 之间的所有内容都是另一个文件中的内容

因此,从字面上看,您所要做的就是打开具有合并冲突的文件,然后从任一分支中删除这些行(或者只是使它们相同),合并将立即成功。问题解决了!

P
Peter Mortensen

这个答案是为像我这样喜欢在编辑器中做所有事情的 Vim 用户添加一个替代方案。

TL;博士

https://i.stack.imgur.com/iW2iC.gif

Tpope 为 Vim 开发了这个很棒的插件,名为 fugitive。安装后,您可以运行 :Gstatus 检查有冲突的文件,运行 :Gdiff 以三向合并打开 Git。

一旦进入三路合并,fugitive 将让您以下列方式获取您正在合并的任何分支的更改:

:diffget //2,从原始(HEAD)分支获取更改:

:diffget //3,从合并分支获取更改:

完成文件合并后,在合并的缓冲区中键入 :Gwrite

Vimcasts 发布了a great video,详细解释了这些步骤。

P
Peter Mortensen
git fetch <br>
git checkout **your branch**<br>
git rebase master<br>

在此步骤中,您将尝试使用首选 IDE 修复冲突。

您可以按照this link查看如何修复文件中的冲突。

git add<br>
git rebase --continue<br>
git commit --amend<br>
git push origin HEAD:refs/drafts/master  (push like a drafts)<br>

现在一切都很好,您将在 Gerrit 中找到您的提交。

P
Peter Mortensen

我正在使用 Microsoft 的 Visual Studio Code 来解决冲突。使用起来非常简单。我在工作区中保持我的项目打开。它检测并突出显示冲突。此外,它提供了 GUI 选项来选择我想从 HEAD 保留或传入的任何更改。

https://i.stack.imgur.com/RXgnQ.png

“接受两个更改”功能似乎在许多其他提到的工具中都缺乏,而且我倾向于经常使用。

y
yairchu

解决冲突的一种更安全的方法是使用 git-mediate(这里建议的常见解决方案很容易出错,恕我直言)。

有关如何使用它的快速介绍,请参阅 this post

P
Peter Mortensen

对于那些使用 Visual Studio 的人(在我的例子中是 Visual Studio 2015

在 Visual Studio 中关闭您的项目。尤其是在大型项目中,Visual Studio 在使用 UI 进行合并时往往会崩溃。在命令提示符下进行合并。 git checkout target_branch git merge source_branch 然后在 Visual Studio 中打开项目并转到 Team Explorer → Branch。现在有一条消息显示 Merge is pending 并且冲突文件列在消息下方。单击冲突文件,您将可以选择合并、比较、获取源和获取目标。 Visual Studio 中的合并工具非常易于使用。

我在一个非常大的项目上使用 VS Code 2017,不需要关闭该项目。它处理得很好:)

P
Peter Mortensen

如果您使用 IntelliJ IDEA 作为 IDE,请尝试通过以下方式将父级合并到您的分支:

git checkout <localbranch>
git merge origin/<remotebranch>

它将显示所有冲突,如下所示:

A_MBPro:test anu$ git merge origin/ Auto-merging src/test/java/com/.../TestClass.java CONFLICT (content): Merge conflict in src/test/java/com/.../TestClass.java

现在请注意,文件 TestClass.java 在 IntelliJ IDEA 中显示为红色。

git status 还会显示:

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   src/test/java/com/.../TestClass.java

在 IntelliJ IDEA 中打开文件。它将有部分

  <<<<<<< HEAD
    public void testMethod() {
    }
    =======
    public void testMethod() { ...
    }
    >>>>>>> origin/<remotebranch>

其中 HEAD 是本地分支上的更改,而 origin/ 是远程分支上的更改。在这里保留您需要的东西并删除您不需要的东西。之后,应该执行正常步骤。那是

   git add TestClass.java
   git commit -m "commit message"
   git push