虽然并不与这个回答直接相关,但我建议放弃使用git pull
命令,因为它会先运行git fetch
,再运行git merge
。这样你将进行三次合并,导致Git要运行三次获取操作,而实际上只需要一次获取即可。所以应该使用以下命令:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
控制最棘手的合并
最有趣的部分在于git merge -X theirs
。正如root545所指出的那样,-X
选项会传递给合并策略,而默认的recursive
策略和替代的resolve
策略都采用-X ours
或-X theirs
(其中之一,而不是两者都有)。 然而,要理解它们的作用,您需要知道Git如何找到和处理合并冲突。
当基础版本与当前版本(也称为本地版本、HEAD或--ours
)以及同一文件的另一远程版本(也称为远程或--theirs
)不同时,某些文件1可能会发生合并冲突。也就是说,合并已经确定了三个修订版本(三个提交):基础版本、我们的版本和他们的版本。 "基础"版本来自我们的提交和他们的提交之间的合并基础,可以在提交图中找到(有关更多信息,请参见其他StackOverflow文章)。然后,Git找到了两组变化:"我们做了什么"和"他们做了什么"。这些更改通常是基于行的、纯文本方式进行的。Git实际上没有对文件内容的真正理解;它只是在比较每一行文本。
这些更改就是您在git diff
输出中看到的内容,并且像往常一样,它们也具有上下文。我们更改的内容可能与他们更改的内容不在同一行,因此更改似乎不会冲突,但上下文也已经更改(例如,由于我们的更改接近文件顶部或底部,因此文件在我们的版本中运行完毕,但在他们的版本中,他们还在顶部或底部添加了更多文本)。
如果更改发生在不同的行上 - 例如,我们在第17行将color
更改为colour
,而他们在第71行将fred
更改为barney
- 那么就没有冲突:Git简单地采用两个更改。 如果更改发生在相同的行上,但是是相同的更改,则Git采用一个更改。只有当更改发生在相同的行上,但是是不同的更改,或者是干扰上下文的特殊情况时,才会出现修改/修改冲突。
-X ours
和-X theirs
选项告诉Git如何解决此冲突,即选择其中之一:我们的或他们的更改。由于您说您正在将demo
(theirs)合并到master
(ours)中,并且希望使用demo
的更改,因此您应该使用-X theirs
。
然而,盲目地应用-X
是危险的。仅仅因为我们的更改在逐行比较方面没有冲
int i;
在我们的版本中,我们删除了未使用的变量以消除编译器警告,并且在他们的版本中,他们稍后添加了一个循环,在几行之后使用 i 作为循环计数器。如果我们将这两个更改组合起来,则生成的代码将不再编译。-X 选项对此毫无帮助,因为更改在不同的行上。
如果您有自动化测试套件,则最重要的是在合并后运行测试。您可以在提交后执行此操作,并在需要时进行修复;或者您可以在提交之前添加 --no-commit 到 git merge 命令中进行操作。关于所有这些细节,我们会在其他文章中详细介绍。
1 您还可能在“文件级”操作方面遇到冲突,例如,我们可能会在文件中修正单词拼写(从而产生更改),而他们则删除整个文件(从而产生删除)。无论 -X 参数如何,Git 都无法自行解决这些冲突。
减少合并、智能合并和/或使用变基
我们的命令序列中都有三次合并。第一次是将 origin/demo 合并到本地 demo(您使用 git pull,如果您的 Git 版本过旧,则无法更新 origin/demo,但将产生相同的结果)。第二次是将 origin/master 合并到 master。
我不清楚是谁在更新 demo 和/或 master。如果您在自己的 demo 分支上编写自己的代码,并且其他人正在编写代码并将其推送到 origin 上的 demo 分支,则此第一步合并可能会产生冲突,或者产生真正的合并。更多情况下,最好使用变基而不是合并来组合工作(尽管这是品味和观点问题)。如果是这样,您可能想使用 git rebase 代替。另一方面,如果您从未在 demo 上提交任何自己的提交,甚至不需要 demo 分支。或者,如果您想自动化大部分操作,但希望在您和其他人都进行了提交时仔细检查,则可以使用 git merge --ff-only origin/demo:如果可能,这将快速转发您的 demo 以匹配已更新的 origin/demo,并在无法转发时直接失败(此时您可以检查两个变更集,并根据需要选择真正的合并或变基)。
这个逻辑同样适用于master
,尽管你在master
上执行合并,所以你肯定需要一个master
。然而,如果无法快进非合并方式完成合并,则更有可能希望合并失败,因此这也应该是git merge --ff-only origin/master
。
假设您从未在demo
上进行自己的提交。在这种情况下,我们可以完全放弃demo
这个名称:
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
如果你正在进行自己的演示分支提交,那么这并没有什么帮助;你可以选择保留现有的合并(但是根据你想要的行为可能需要添加--ff-only
),或者切换到执行rebase。请注意,所有三种方法都有可能失败:合并可能由于冲突而失败,使用 --ff-only
的合并可能无法快进,而rebase可能由于冲突而失败(rebase 的工作原理可以理解为“樱桃拣选”提交,这使用了合并机制,因此可能会出现合并冲突)。
git push -f origin master
。 - MD XFmerge
命令时应该使用-f
选项而不是在push
命令中使用。 - OpenStack