简体   繁体   English

Git 强制覆盖合并

[英]Git merge with force overwrite

I have a branch called demo which I need to merge with master branch.我有一个名为demo的分支,我需要将其与master分支合并。 I can get the desired result with following commands:我可以通过以下命令获得所需的结果:

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 git to overwrite changes in master branch without giving me merge prompt.我唯一担心的是,如果有任何合并问题,我想告诉git在不给我合并提示的情况下覆盖master分支中的更改。 So basically changes in demo branch should automatically overwrite changes in master branch.所以基本上demo分支中的更改应该自动覆盖master分支中的更改。

I looked around there are multiple options but I don't want to take chances with merging.我环顾四周有多种选择,但我不想冒险合并。

Not really related to this answer, but I'd ditch git pull , which just runs git fetch followed by git merge .与这个答案并没有真正相关,但我会放弃git pullgit pull运行git fetch然后运行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.您正在执行三个合并,这将使您的 Git 运行三个提取操作,当您只需要一个提取操作时。 Hence:因此:

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 .这里最有趣的部分是git merge -X theirs As root545 noted , the -X options are passed on to the merge strategy, and both the default recursive strategy and the alternative resolve strategy take -X ours or -X theirs (one or the other, but not both).正如root545 指出的那样-X选项被传递给合并策略,并且默认recursive策略和替代resolve策略都采用-X ours-X theirs (一个或另一个,但不是两个)。 To understand what they do, though, you need to know how Git finds, and treats, merge conflicts .但是,要了解它们的作用,您需要知道 Git 如何查找和处理合并冲突

A merge conflict can occur within some file 1 when the base version differs from both the current (also called local, HEAD, or --ours ) version and the other (also called remote or --theirs ) version of that same file.基本版本与同一文件的当前(也称为本地、HEAD 或--ours )版本另一个(也称为远程或--theirs )版本不同时,某些文件1 中可能会发生合并冲突。 That is, the merge has identified three revisions (three commits): base, ours, and theirs.也就是说,合并确定了三个修订版(三个提交):base、ours 和 theirs。 The "base" version is from the merge base between our commit and their commit, as found in the commit graph (for much more on this, see other StackOverflow postings). “基础”版本来自我们的提交和他们的提交之间的合并基础,如提交图中所示(有关更多信息,请参阅其他 StackOverflow 帖子)。 Git has then found two sets of changes: "what we did" and "what they did". Git 然后发现了两组变化:“我们做了什么”和“他们做了什么”。 These changes are (in general) found on a line-by-line, purely textual basis.这些更改(通常)是在逐行、纯文本的基础上发现的。 Git has no real understanding of file contents; Git 对文件内容没有真正的理解; it is merely comparing each line of text.它只是比较每一行文本。

These changes are what you see in git diff output, and as always, they have context as well.这些更改是您在git diff输出中看到的,并且与往常一样,它们也有上下文 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 (eg, 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).我们更改的内容可能与它们更改的内容位于不同的行上,因此更改看起来不会发生冲突,但上下文也发生了变化(例如,由于我们的更改靠近文件的顶部或底部,以便文件在我们的版本中用完,但在他们的版本中,他们还在顶部或底部添加了更多文本)。

If the changes happen on different lines—for instance, we change color to colour on line 17 and they change fred to barney on line 71—then there is no conflict: Git simply takes both changes.如果变动对不同发生线路-例如,我们改变color ,以colour在第17行,他们改变fredbarney线71则是没有冲突的:简单的Git需要改变。 If the changes happen on the same lines, but are identical changes, Git takes one copy of the change.如果更改发生在相同的行上,但是是相同的更改,Git 会获取更改的一份副本 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.仅当更改在同一行上,但更改不同,或者干扰上下文的特殊情况时,您才会遇到修改/修改冲突。

The -X ours and -X theirs options tell Git how to resolve this conflict, by picking just one of the two changes: ours, or theirs. -X ours-X theirs选项告诉 Git 如何解决这个冲突,通过选择两个更改之一:我们的,或者他们的。 Since you said you are merging demo (theirs) into master (ours) and want the changes from demo , you would want -X theirs .由于您说要将demo (他们的)合并到master (我们的)并希望从demo进行更改,因此您需要-X theirs

Blindly applying -X , however, is dangerous.然而,盲目地应用-X是危险的。 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:基本版本可能会声明一个未使用的变量:

int i;

In our version, we delete the unused variable to make a compiler warning go away—and in their version, they add a loop some lines later, using i as the loop counter.在我们的版本中,我们删除了未使用的变量以使编译器警告消失——在他们的版本中,他们在几行之后添加了一个循环,使用i作为循环计数器。 If we combine the two changes, the resulting code no longer compiles.如果我们结合这两个更改,生成的代码将不再编译。 The -X option is no help here since the changes are on different lines . -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 before committing, by adding --no-commit to the git merge command.或者您可以提交之前通过将--no-commit添加到git merge命令来完成。 We'll leave the details for all of this to other postings.我们会将所有这些的详细信息留给其他帖子。


1 You can also get conflicts with respect to "file-wide" operations, eg, perhaps we fix the spelling of a word in a file (so that we have a change), and they delete the entire file (so that they have a delete). 1您也可能会遇到与“文件范围”操作相关的冲突,例如,也许我们修复了文件中单词的拼写(以便我们进行更改),然后他们删除整个文件(以便他们有一个删除)。 Git will not resolve these conflicts on its own, regardless of -X arguments.无论-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/demo into the local demo (yours uses git pull which, if your Git is very old, will fail to update origin/demo but will produce the same end result).第一个是将origin/demo引入本地demo (您使用git pull ,如果您的 Git 很旧,将无法更新origin/demo但会产生相同的最终结果)。 The second is to bring origin/master into master .二是将origin/master带入master

It's not clear to me who is updating demo and/or master .我不清楚谁在更新demo和/或master If you write your own code on your own demo branch, and others are writing code and pushing it to the demo branch on origin , then this first-step merge can have conflicts, or produce a real merge.如果您在自己的demo分支上编写自己的代码,其他人正在编写代码并将其推送到origin上的demo分支,那么此第一步合并可能会发生冲突,或者产生真正的合并。 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).通常情况下,最好使用 rebase 而不是 merge 来组合工作(不可否认,这是一个品味和意见的问题)。 If so, you might want to use git rebase instead.如果是这样,您可能想改用git rebase On the other hand, if you never do any of your own commits on demo , you don't even need a demo branch.另一方面,如果你从来没有在demo上做任何你自己的提交,你甚至不需要demo分支。 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 demo to match the updated origin/demo if 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).或者,如果你想自动化很多,但能够仔细检查当你和其他人都提交时,你可能想要使用git merge --ff-only origin/demo :这将快速 -如果可能,转发您的demo以匹配更新的origin/demo如果没有,则完全失败(此时您可以检查两组更改,并根据需要选择真正的合并或变基)。

This same logic applies to master , although you are doing the merge on master , so you definitely do need a master .这个逻辑同样适用于master ,虽然你正在做合并master ,所以你绝对需要一个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 .但是,如果合并不能作为快进非合并完成,则更有可能您希望合并失败,因此这可能也应该是git merge --ff-only origin/master

Let's say that you never do your own commits on demo .假设您从未对demo自己的提交。 In this case we can ditch the name demo entirely:在这种情况下,我们可以完全放弃名称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 are doing your own demo branch commits, this is not helpful;如果你正在做自己的demo分支提交,这没有帮助; you might as well keep the existing merge (but maybe add --ff-only depending on what behavior you want), or switch it to doing a rebase.您不妨保留现有的合并(但可能添加--ff-only取决于您想要的行为),或将其切换为进行变基。 Note that all three methods may fail: merge may fail with a conflict, merge with --ff-only may not be able to fast-forward, and rebase may fail with a conflict (rebase works by, in essence, cherry-picking commits, which uses the merge machinery and hence can get a merge conflict).请注意,所有三种方法都可能失败:合并可能会因冲突而失败,与--ff-only合并可能无法快进,并且 rebase 可能会因冲突而失败(rebase 本质上是通过挑选提交工作的,它使用合并机制,因此可能会发生合并冲突)。

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 -s and not -X .请注意,该选项是-s而不是-X -s denotes the use of ours as a top level merge strategy, -X would be applying the ours option to the recursive merge strategy, which is not what I (or we) want in this case. -s表示使用ours作为顶级合并策略, -Xours选项应用于recursive合并策略,在这种情况下这不是我(或我们)想要的。

Steps, where oldbranch is the branch you want to overwrite with newbranch .步骤,其中oldbranch是您要使用newbranch覆盖的分支。

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

This merge approach will add one commit on top of master which pastes in whatever is in feature , without complaining about conflicts or other crap.这种合并方法将在master之上添加一个提交,该提交粘贴到feature中的任何内容中,而不会抱怨冲突或其他废话。

在此处输入图片说明

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 feature all dressed up得到所有打扮的feature

git checkout feature
git merge --strategy=ours master

Go for the kill去杀戮

git checkout master
git merge --no-ff feature

You can try "ours" option in git merge,您可以在 git merge 中尝试“ours”选项,

git merge branch -X ours git merge branch -X 我们的

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.对于二进制文件,所有内容都取自我们这边。

These commands will help in overwriting code of demo branch into master这些命令将有助于将demo分支的代码覆盖到master

git fetch --all

Pull Your demo branch on local将您的demo分支拉到本地

git pull origin demo

Now checkout to master branch.现在结帐到master分支。 This branch will be completely changed with the code on demo branch此分支将使用demo分支上的代码完全更改

git checkout master

Stay in the master branch and run this command.留在master分支并运行此命令。

git reset --hard origin/demo

reset means you will be resetting current branch reset意味着您将重置当前分支

--hard is a flag that means it will be reset without raising any merge conflict --hard是一个标志,意味着它将被重置而不会引发任何合并冲突

origin/demo will be the branch that will be considered to be the code that will forcefully overwrite current master branch origin/demo将被视为将强制覆盖当前master分支的代码的分支

The output of the above command will show you your last commit message on origin/demo or demo branch上述命令的输出将显示您在origin/demodemo分支上的最后一次提交消息在此处输入图片说明

Then, in the end, force push the code on the master branch to your remote repo.然后,最后,将master分支上的代码强制推送到您的远程仓库。

git push --force

When I tried using -X theirs and other related command switches I kept getting a merge commit.当我尝试使用-X theirs和其他相关命令开关时,我不断收到合并提交。 I probably wasn't understanding it correctly.我可能没有正确理解它。 One easy to understand alternative is just to delete the branch then track it again.一种易于理解的替代方法是删除分支然后再次跟踪它。

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.就我而言,我想从强制推送的远程分支中提取更改。

I had same issue and I found solution here .我有同样的问题,我在这里找到了解决方案。 Don't forget to read documentation before doing anything.在做任何事情之前不要忘记阅读文档

Let me explain.让我解释。 Consider that we have 2 repositories master and devmaster and you want to replace master with devmaster .考虑到我们有 2 个存储库masterdevmaster并且您想用devmaster替换master Then first command will be as below然后第一个命令如下

git checkout devmaster

Now you switched to devmaster branch.现在你切换到 devmaster 分支。 And you need to to merge with ours ( reference ):您需要与我们的合并( 参考):

git merge -s ours master

Then checkout the code:然后查看代码:

git checkout master

Next stage is, merge devmaster to master :下一阶段是,将devmaster合并到master

git merge devmaster

Final stage is push your code:最后阶段是推送您的代码:

git push

But please read all documentation because it worked for so.但请阅读所有文档,因为它适用于此。 It's not guaranteed that it will work for you also.不能保证它也适用于您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM