Git 合并强制覆盖

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40517129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 04:37:52  来源:igfitidea点击:

Git merge with force overwrite

gitgithubmerge

提问by OpenStack

I have a branch called demowhich I need to merge with masterbranch. I can get the desired result with following commands:

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

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

My only concern is, if there are any merge issues, I want to tell gitto overwrite changes in masterbranch without giving me merge prompt. So basically changes in demobranch should automatically overwrite changes in masterbranch.

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

I looked around there are multiple options but I don't want to take chances with merging.

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

回答by torek

Not really related to this answer, but I'd ditch git pull, which just runs git fetchfollowed by git merge. You are doing three merges, which is going to make your Git run three fetch operations, when one fetch is all you will need. Hence:

与这个答案并没有真正的关系,但我会放弃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

Controlling the trickiest merge

控制最棘手的合并

The most interesting part here is git merge -X theirs. As root545 noted, the -Xoptions are passed on to the merge strategy, and both the default recursivestrategy and the alternative resolvestrategy take -X oursor -X theirs(one or the other, but not both). To understand what they do, though, you need to know how Git finds, and treats, merge conflicts.

这里最有趣的部分是git merge -X theirs. 正如root545 指出的那样-X选项被传递给合并策略,默认recursive策略和替代resolve策略都采用-X oursor -X theirs(一个或另一个,但不是两个)。但是,要了解它们的作用,您需要知道 Git 如何查找和处理合并冲突

A merge conflict can occur within some file1when the baseversion differs from both the current(also called local, HEAD, or --ours) version andthe other (also called remote or --theirs) version of that same file. That is, the merge has identified three revisions (three commits): base, ours, and theirs. The "base" version is from the merge basebetween our commit and their commit, as found in the commit graph (for much more on this, see other StackOverflow postings). Git has then found two sets of changes: "what we did" and "what they did". These changes are (in general) found on a line-by-line, purely textualbasis. Git has no real understanding of file contents; it is merely comparing each line of text.

基本版本与同一文件的当前(也称为本地、HEAD 或)版本另一个(也称为远程或)版本不同时,某些文件1 中可能会发生合并冲突。也就是说,合并确定了三个修订版(三个提交):base、ours 和 theirs。“基础”版本来自我们的提交和他们的提交之间的合并基础,如提交图中所示(有关更多信息,请参阅其他 StackOverflow 帖子)。Git 然后发现了两组变化:“我们做了什么”和“他们做了什么”。这些更改(通常)是逐行、纯文本的--ours--theirs基础。Git 对文件内容没有真正的理解;它只是比较每一行文本。

These changes are what you see in git diffoutput, and as always, they have contextas well. It's possible that things we changed are on different lines from things they changed, so that the changes seem like they would not collide, but the context has also changed (e.g., due to our change being close to the top or bottom of the file, so that the file runs out in our version, but in theirs, they have also added more text at the top or bottom).

这些更改是您在git diff输出中看到的内容,并且与往常一样,它们也有上下文。我们更改的内容可能与它们更改的内容位于不同的行上,因此更改看起来不会发生冲突,但上下文也发生了变化(例如,由于我们的更改靠近文件的顶部或底部,以便文件在我们的版本中用完,但在他们的版本中,他们还在顶部或底部添加了更多文本)。

If the changes happen on differentlines—for instance, we change colorto colouron line 17 and they change fredto barneyon line 71—then there is no conflict: Git simply takes bothchanges. If the changes happen on the same lines, but are identicalchanges, Git takes one copyof the change. Only if the changes are on the same lines, but are different changes, or that special case of interfering context, do you get a modify/modify conflict.

如果更改发生在不同的行上——例如,我们在第 17 行更改colorcolour,它们在第 71 行更改fredbarney——那么就不存在冲突:Git 只是同时接受这两个更改。如果更改发生在相同的行上,但是是相同的更改,Git 会获取更改的一份副本。仅当更改在同一行上,但更改不同,或者干扰上下文的特殊情况时,您才会遇到修改/修改冲突。

The -X oursand -X theirsoptions tell Git how to resolve this conflict, by picking just one of the two changes: ours, or theirs. Since you said you are merging demo(theirs) into master(ours) and want the changes from demo, you would want -X theirs.

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

Blindly applying -X, however, is dangerous. Just because our changes did not conflict on a line-by-line basis does not mean our changes do not actually conflict! One classic example occurs in languages with variable declarations. The base version might declare an unused variable:

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

int i;

In our version, we delete the unused variable to make a compiler warning go away—and in theirversion, they add a loop some lines later, using ias the loop counter. If we combine the two changes, the resulting code no longer compiles. The -Xoption is no help here since the changes are on different lines.

在我们的版本中,我们删除了未使用的变量以使编译器警告消失——在他们的版本中,他们在几行之后添加了一个循环,i用作循环计数器。如果我们结合这两个更改,生成的代码将不再编译。该-X选项在这里没有帮助,因为更改位于不同的行上

If you have an automated test suite, the most important thing to do is to run the tests after merging. You can do this after committing, and fix things up later if needed; or you can do it beforecommitting, by adding --no-committo the git mergecommand. We'll leave the details for all of this to other postings.

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



1You can also get conflicts with respect to "file-wide" operations, e.g., perhaps we fix the spelling of a word in a file (so that we have a change), and they deletethe entire file (so that they have a delete). Git will not resolve these conflicts on its own, regardless of -Xarguments.

1您也可能会遇到与“文件范围”操作相关的冲突,例如,也许我们修复了文件中单词的拼写(以便我们进行更改),然后他们删除整个文件(以便他们有一个删除)。无论-X参数如何,Git 都不会自行解决这些冲突。



Doing fewer merges and/or smarter merges and/or using rebase

进行更少的合并和/或更智能的合并和/或使用 rebase

There are three merges in both of our command sequences. The first is to bring origin/demointo the local demo(yours uses git pullwhich, if your Git is very old, will fail to update origin/demobut will produce the same end result). The second is to bring origin/masterinto master.

我们的两个命令序列中都有三个合并。第一个是origin/demo引入本地demo(你的使用git pull,如果你的 Git 很旧,将无法更新origin/demo但会产生相同的最终结果)。二是origin/master带入master

It's not clear to me who is updating demoand/or master. If you write your own code on your own demobranch, andothers are writing code and pushing it to the demobranch on origin, then this first-step merge can have conflicts, or produce a real merge. More often than not, it's better to use rebase, rather than merge, to combine work (admittedly, this is a matter of taste and opinion). If so, you might want to use git rebaseinstead. On the other hand, if you never do any of your own commits on demo, you don't even needa demobranch. Alternatively, if you want to automate a lot of this, but be able to check carefully when there are commits that both you and others, made, you might want to use git merge --ff-only origin/demo: this will fast-forward your demoto match the updated origin/demoif possible, and simply outright fail if not (at which point you can inspect the two sets of changes, and choose a real merge or a rebase as appropriate).

我不清楚谁在更新demo和/或master. 如果你在自己的demo分支上编写自己的代码,其他人正在编写代码并将其推送到 上的demo分支origin,那么这个第一步合并可能会发生冲突,或者产生真正的合并。通常情况下,最好使用 rebase 而不是 merge 来组合工作(不可否认,这是一个品味和意见的问题)。如果是这样,您可能想git rebase改用。在另一方面,如果你从来没有做任何自己提交的对demo,你甚至都不需要一个demo分支。或者,如果您想自动化很多工作,但能够仔细检查您和其他人何时进行的提交,您可能需要使用git merge --ff-only origin/demo:如果可能的话,这将使您快速demo匹配更新的内容,origin/demo如果没有,则完全失败(此时您可以检查两组更改,并根据需要选择真正的合并或变基)。

This same logic applies to master, although you are doing the merge onmaster, so you definitely do need a master. It is, however, even likelier that you would want the merge to fail if it cannot be done as a fast-forward non-merge, so this probably also should be git merge --ff-only origin/master.

这个逻辑同样适用于master,即使你正在做的合并master,所以你绝对需要master。但是,如果合并不能作为快进非合并完成,则更有可能希望合并失败,因此这可能也应该是git merge --ff-only origin/master.

Let's say that you never do your own commits on demo. In this case we can ditch the name demoentirely:

假设您从未对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

If you aredoing your own demobranch commits, this is not helpful; you might as well keep the existing merge (but maybe add --ff-onlydepending on what behavior you want), or switch it to doing a rebase. Note that all three methods may fail: merge may fail with a conflict, merge with --ff-onlymay not be able to fast-forward, and rebase may fail with a conflict (rebase works by, in essence, cherry-pickingcommits, which uses the merge machinery and hence can get a merge conflict).

如果你正在做自己的demo分支提交,这没有帮助;您不妨保留现有的合并(但可能会--ff-only根据您想要的行为进行添加),或者将其切换为进行变基。请注意,所有三种方法都可能失败:merge 可能因冲突而失败,merge with--ff-only可能无法快进,rebase 可能因冲突而失败(rebase 本质上是通过挑选提交工作的,它使用合并机器,因此可能会发生合并冲突)。

回答by Niall Mccormack

I had a similar issue, where I needed to effectively replace any file that had changes / conflicts with a different branch.

我有一个类似的问题,我需要有效地替换任何具有不同分支更改/冲突的文件。

The solution I found was to use git merge -s ours branch.

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

Note that the option is -sand not -X. -sdenotes the use of oursas a top level merge strategy, -Xwould be applying the oursoption to the recursivemerge strategy, which is not what I (or we) want in this case.

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

Steps, where oldbranchis the branch you want to overwrite with newbranch.

Steps,oldbranch你想用newbranch.

  • git checkout newbranchchecks out the branch you want to keep
  • git merge -s ours oldbranchmerges in the old branch, but keeps all of our files.
  • git checkout oldbranchchecks out the branch that you want to overwrite
  • get merge newbranchmerges in the new branch, overwriting the old branch
  • git checkout newbranch签出您要保留的分支
  • git merge -s ours oldbranch在旧分支中合并,但保留我们所有的文件。
  • git checkout oldbranch签出要覆盖的分支
  • get merge newbranch合并到新分支,覆盖旧分支

回答by William Entriken

This merge approach will add one commit on top of masterwhich pastes in whatever is in feature, without complaining about conflicts or other crap.

这种合并方法将添加一个提交,在master其上粘贴任何内容feature,而不会抱怨冲突或其他废话。

enter image description here

在此处输入图片说明

Before you touch anything

在你触摸任何东西之前

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

Now prepare master

现在准备大师

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

Get featureall dressed up

整装feature待发

git checkout feature
git merge --strategy=ours master

Go for the kill

去杀戮

git checkout master
git merge --no-ff feature

回答by manuj

You can try "ours" option in git merge,

您可以在 git merge 中尝试“ours”选项,

git merge branch -X ours

This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side.

git merge branch -X 我们的

此选项通过支持我们的版本强制自动解决冲突的大块头。来自另一棵树的与我们这边不冲突的变化会反映到合并结果中。对于二进制文件,所有内容都取自我们这边。

回答by Matt

When I tried using -X theirsand other related command switches I kept getting a merge commit. I probably wasn't understanding it correctly. One easy to understand alternative is just to delete the branch then track it again.

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

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

This isn't exactly a "merge", but this is what I was looking for when I came across this question. In my case I wanted to pull changes from a remote branch that were force pushed.

这不完全是“合并”,但这正是我遇到这个问题时所寻找的。就我而言,我想从强制推送的远程分支中提取更改。