使用强制覆盖进行Git合并

229

我有一个名为 demo 的分支,需要将其合并到 master 分支。以下命令可以实现此目的:

git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master

我唯一关心的是,如果有任何合并问题,我想告诉git在不给出合并提示的情况下覆盖master分支中的更改。因此,demo分支中的更改应自动覆盖master分支中的更改。

我查看了周围,有多种选项,但我不想冒合并风险。


6
将本地代码强制推送到远程仓库的master分支,覆盖原有内容。命令为:git push -f origin master - MD XF
12
也许我错了,但是在使用merge命令时应该使用-f选项而不是在push命令中使用。 - OpenStack
你可以尝试两种方法,看哪一种适合你。 - MD XF
1
请查看以下链接以获取强制覆盖的解决方案:https://dev59.com/cm445IYBdhLWcg3w7unD#42454737 - Manohar Reddy Poreddy
https://git-scm.com/docs/merge-strategies - chharvey
似乎有点不可靠,特别是对于新手程序员来说,他们可以轻松地找到这个答案,但并不完全理解使用-f标志的含义,并可能引起问题。尽管下面有非常好的答案。 - Clomez
7个回答

206

虽然并不与这个回答直接相关,但我建议放弃使用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 的工作原理可以理解为“樱桃拣选”提交,这使用了合并机制,因此可能会出现合并冲突)。


89

我曾经遇到过类似的问题,需要将任何有更改/冲突的文件有效地替换为不同的分支。

我找到的解决方案是使用git merge -s ours branch

请注意,选项是-s而不是-X-s表示使用ours作为顶级合并策略,而-X将应用ours选项到recursive合并策略,这不是我(或我们)在这种情况下想要的。

步骤如下,其中oldbranch是您想要用newbranch覆盖的分支。

  • git checkout newbranch检出您想要保留的分支
  • git merge -s ours oldbranch合并旧分支,但保留所有我们的文件。
  • git checkout oldbranch检出您想要覆盖的分支
  • get merge newbranch合并新分支,覆盖旧分支

1
它对我没用。它解决了冲突(解决了有冲突的文件),但文件没有合并。也无法合并。 - c-an
1
如果有人卡在提示“请输入合并说明以解释为什么需要此合并”的地方,请输入您的消息,然后按键盘上的ESC键,输入:wq并按ENTER退出提示。 - topherPedersen
确实是我正在寻找的,谢谢。 - Gbox4

65

这种合并方法会在master分支上添加一个提交记录,将feature分支的所有内容粘贴进去,不会出现冲突或其他问题。

图片描述

在您触碰任何内容之前

git stash
git status # if anything shows up here, move it to your desktop

现在准备就绪

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

特性打扮一新

git checkout feature
git merge --strategy=ours master

全力以赴

git checkout master
git merge --no-ff feature

14
推送(git push)以完成(finish)。 - Kochchy
git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours 。当提交内容无法干净地合并时,这种方法是有效的。但这个方法并不总是适用的,引用原文:来自另一个分支的更改(与我们自己的更改)没有冲突,这些更改会反映在合并结果中。我尝试使用这种方法时失败了,因为我的分支中有干净的合并提交,但这些提交仍然被覆盖了。还有其他方法吗? - NiharGht
这对我来说起到了重要的作用!正是我一直在寻找的东西。(我们曾尝试切换框架,但失败了。我们需要从坏框架之上挑选一些最新的工作,并将我们挑选的分支覆盖主干上的内容。) - ForOhFor

48

这些命令将帮助将demo分支的代码覆盖到master分支

git fetch --all

将您的本地代码库拉取 demo 分支

git pull origin demo

现在切换到master分支。该分支将完全使用demo分支上的代码进行更改。

git checkout master

保持在master分支上,然后运行此命令。

git reset --hard origin/demo

reset指的是你将重置当前分支。

--hard是一个标志,意味着它将在不引发任何合并冲突的情况下进行重置。

origin/demo将被视为强制覆盖当前master分支的代码分支。

上述命令的输出将显示您在origin/demodemo分支上的最后提交消息。 enter image description here

然后,最后将代码强制推送到远程仓库的master分支中。

git push --force

为什么使用远程'origin/demo'分支而不是本地'demo'分支。 - NevetsKuro
@NevetsKuro 你也可以使用本地的。如果最新的提交是通过 "git fetch --all" 和拉取分支 "demo" 获取的,那么 "git reset --hard demo" 和 "git reset --hard origin/demo" 会产生相同的操作。 - Rahul Shyokand
1
它对我的情况完美地起作用了。 - Rodrigo

19

您可以尝试在git合并中使用"ours"选项,

git merge branch -X ours

此选项通过偏向我们自己的版本来强制自动清除冲突代码块。与我们版本不冲突的其他树变更将反映在合并结果中。对于二进制文件,整个内容都从我们这一方拷贝。


3
这样做是不对的,因为原帖作者说他想要首选“演示版”即使他正在合并到“主分支”中。也有一个“-X theirs”的选项,但不清楚这是否符合原帖作者的意愿。 - torek
你没有完整地阅读。你的注释描述了在后端使用“ours”选项时会发生什么。当使用带有“-X”选项的“ours”时,它会放弃其他树所做的一切,声明我们的历史记录包含了所有发生的事情。 - jimasun

7

当我尝试使用-X theirs和其他相关的命令开关时,我一直得到一个合并提交。我可能没有正确理解它。一个易于理解的替代方法就是删除分支,然后再跟踪它。

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

这不完全是一个“合并”,但这正是我在看到这个问题时正在寻找的。在我的情况下,我想从远程分支中拉取强制推送的更改。
您可以使用git reset来完成此操作,而无需删除自己的分支,这很好:
git reset --hard origin/<branch-name>

另一篇SO帖子在这里提供了更详细的信息。


-1
git checkout master
git merge demo
cd /root/of/source/
git checkout --theirs . # this will overwrite everything by img of demo
git add .
git commit -m "bla bla"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接