Git与强制覆盖合并


100

我有一个分支demo,需要与master分支合并。我可以使用以下命令获得所需的结果:

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

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

我环顾四周,有多种选择,但我不想冒险进行合并。


git push -f origin master
MD XF

4
@MDXF:可能是我错了,但我不应该-fmerge命令中使用option 而不是push命令
OpenStack

您可以尝试两种方法,看看哪种方法对您
MD XF

参见以下链接,了解强制覆盖的解决方案:stackoverflow.com/a/42454737/984471
Manohar Reddy Poreddy

Answers:


98

不是真的与此相关的答案,但我会沟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 版本)其他版本(也称为远程版本)时,某些文件1内可能发生合并冲突。也就是说,合并确定了三个修订版(三个提交):基本版本,我们的版本和他们的版本。“基础”版本来自提交和提交之间的合并基础,如提交图中所示(有关更多信息,请参见其他StackOverflow发布)。然后,Git找到了两组更改:“我们做了什么”和“他们做了什么”。这些更改(通常)逐行(纯文本)--ours--theirs基础。Git对文件内容没有真正的了解;它只是比较文本的每一行。

这些更改是您在git diff输出中看到的,并且一如既往,它们也具有上下文。我们更改的内容可能与更改的内容不在同一行,因此更改似乎不会发生冲突,但是上下文也已更改(例如,由于更改接近文件的顶部或底部,因此该文件在我们的版本中用尽,但在他们的版本中,他们还在顶部或底部添加了更多文本)。

如果更改发生在不同的行上(例如,我们更改colorcolour第17行,而更改fredbarney第71行),则不存在冲突:Git只需接受这两个更改。如果更改发生在同一行,但是是相同的更改,则Git会获取该更改的一个副本。仅当更改是在同一行上,但是是不同的更改,或者是干扰上下文的特殊情况时,您才会获得修改/修改冲突。

-X ours-X theirs选项告诉Git是如何解决这个矛盾,采摘只是其中一个变化:我们的,还是他们。既然您说过您正在将demo(他们的)合并到master(我们的)并希望从中进行更改demo,那么您就想要-X theirs

-X但是,盲目使用是危险的。仅仅因为我们的更改没有逐行冲突并不意味着我们的更改实际上没有冲突!一个经典的例子出现在带有变量声明的语言中。基本版本可能会声明一个未使用的变量:

int i;

在我们的版本中,我们删除了未使用的变量以使编译器警告消失—在它们的版本中,它们在以后的几行中添加了一个循环,i用作循环计数器。如果我们将这两个更改组合在一起,则生成的代码将不再编译。-X由于更改位于不同的行,因此该选项无济于事。

如果您具有自动化测试套件,那么最重要的事情是在合并后运行测试。您可以在提交后执行此操作,然后在需要时进行修复。或者您可以提交之前通过添加--no-commitgit merge命令中来完成此操作。我们会将所有这些详细信息留给其他帖子。


1您也可能会在“文件范围”操作方面发生冲突,例如,也许我们修复了文件中某个单词的拼写(以便我们进行更改),然后删除了整个文件(因此他们拥有了一个删除)。无论有何-X论点,Git都不会自行解决这些冲突。


进行更少的合并和/或更明智的合并和/或使用变基

我们的两个命令序列都有三个合并。首先是origin/demo引入本地demogit pull如果您的Git很旧,您将使用该版本,origin/demo但更新失败,但会产生相同的最终结果)。二是origin/master带入master

我不清楚谁正在更新demo和/或master。如果您在自己的demo分支上编写自己的代码,其他人正在编写代码并将其推送到上的demo分支上origin,则此第一步合并可能会发生冲突,或产生实际的合并。通常,使用rebase而不是合并来结合工作是更好的选择(不可否认,这是一种品味和见解的问题)。如果是这样,您可能要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

如果您正在执行自己的demo分支提交,这将无济于事。您也可以保留现有合并(但可以--ff-only根据所需的行为添加),也可以将其切换为进行基准调整。请注意,这三种方法都可能失败:合并可能会因冲突而失败,与合并--ff-only可能无法快速前进,而重新基准化可能会因冲突而失败(本质上,重新合并是通过使用合并进行的精心挑选的提交来进行的。机械,因此可能会发生合并冲突)。


19

我有一个类似的问题,我需要用其他分支有效地替换所有有更改/冲突的文件。

我发现的解决方案是使用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-

如果有人碰巧卡在提示您“请输入提交消息以说明为什么需要合并”的位置,请执行以下操作:输入消息,然后按键盘上的ESC键,键入:wq并按Enter以退出提示。
topherPedersen

17

这种合并方法将添加一个提交,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

获取feature所有打扮

git checkout feature
git merge --strategy=ours master

去杀人

git checkout master
git merge --no-ff feature

1
git push to finish
Kochchy

git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours。当提交未完全合并时,它就起作用了。但是引用这种来源,这种方法并不总是可行Changes from the other tree that do not conflict with our side are reflected in the merge result。它对我不起作用,因为我在分支中干净地合并了提交,但这些分支被覆盖了。还有其他办法吗?
NiharGht

11

您可以在git merge中尝试“我们的”选项,

git merge分支-X我们的

通过支持我们的版本,此选项可以强制自动解决冲突的块。与其他树不冲突的更改将反映到合并结果中。对于二进制文件,全部内容都是从我们这边获取的。


3
这将是倒退,因为OP表示demo即使他合并到,他也希望该版本成为首选master。也有-X theirs,但尚不清楚这是OP真正想要的。
torek's

您还没有完整阅读。您的注释描述了ours在带有-s选项的后端上使用时的操作。使用时ours-X它放弃一切其他的树也没有,宣告我们的历史包含了所有在它发生了。 来源
jimasun

2

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

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

这并非完全是“合并”,但这是我遇到此问题时要寻找的东西。在我的情况下,我想从远程分支中强制推送更改。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.