git 如何重新合并已经合并的分支?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42583073/
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-19 12:38:55  来源:igfitidea点击:

How to re-merge an already merged branch?

gitmerge

提问by John M

I have a commit graph that looks something like the one below. Commits marked with *represent lots of commits.

我有一个类似于下面的提交图。标记*为 的提交代表大量提交。

   A*
   |
   B---------
   |        |
   C*       D*    <- old feature branch
   |        |
   E---------
   |
   F*
   |
   G      <- master

The merge commit E was done incorrectly and some changes (not all) in C* have been lost. How can I redo that merge to reintroduce the changes into the current master?

合并提交 E 执行不正确,并且 C* 中的某些更改(并非全部)已丢失。我如何重做合并以将更改重新引入当前母版?

Everything has already been pushed (open source project), so changing history is not an option.

一切都已经被推送(开源项目),所以改变历史不是一种选择。

I tried creating a patch from the commits C* and apply that to the master, but because someof the changes from C* have been merged correctly and because the project evolved since that commit, about 80% of the patch fails.

我尝试从 C* 提交中创建一个补丁并将其应用到 master,但由于C* 的一些更改已正确合并,并且项目自该提交以来一直在发展,因此大约 80% 的补丁失败了。

Ideally, we would take all the changes in C*, apply them to master and resolve all conflicts. But because the branches have already been merged, git doesn't detect any changes and won't allow to merge again.

理想情况下,我们会采用 C* 中的所有更改,将它们应用于 master 并解决所有冲突。但是由于分支已经合并,git 不会检测到任何更改,也不允许再次合并。

$ git checkout 5bc5295   # C
HEAD is now at 5bc5295... cleanup

$ git checkout -b "missing-commits"
Switched to a new branch 'missing-commits'

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git merge missing-commits
Already up-to-date.

采纳答案by AnoE

Ideally, we would take all the changes in C*, apply them to master and resolve all conflicts.

理想情况下,我们会采用 C* 中的所有更改,将它们应用于 master 并解决所有冲突。

No, ideally you would rewind time, do the merge as it was back then (but correctly, this time), then reapply the F*changes and end up with a correct master.

不,理想情况下,您应该倒回时间,按照当时的方式进行合并(但这次是正确的),然后重新应用F*更改并最终得到正确的master.

You can do it like this:

你可以这样做:

git checkout missing-commits
git checkout -b correct-merge
git merge D    # do it right, this time around!
git checkout master
git checkout -b correct-master
git rebase --onto correct-merge wrong-merge correct-master # have fun with the mother of all rebases!

If you manage to handle all the conflicts during the rebase, you will end up with exactly what you wanted, originally, in the branch correct-master.

如果您设法在 rebase 期间处理所有冲突,您最终将在 branch 中获得您最初想要的内容correct-master

Since you do not want to change history, you could then create a big patch and apply that to your current master, but I like this approach more (assuming you did all your work in your working directory yourrepos):

由于您不想更改历史记录,您可以创建一个大补丁并将其应用到您当前的master,但我更喜欢这种方法(假设您在工作目录中完成了所有工作yourrepos):

cd yourrepos ; git checkout correct-master ; cd ..
cp -a yourrepos newrepos
rm -rf newrepos/.git
cd yourrepos ; git checkout master ; cd ..
cp -a yourrepos/.git newrepos/

Now, when you enter newreposand do a git status, you will be on branch masterand will see precisely all changes between masterand correct-master, as if you had applied a patch. It will catch deleted files, new files, changed files, changed permissions, changed symlinks and so on.

现在,当您输入newrepos并执行 a 时git status,您将在分支上master并准确地看到master和之间的所有更改correct-master,就像您应用了补丁一样。它将捕获已删除的文件、新文件、更改的文件、更改的权限、更改的符号链接等。

Ideally, if everything went right, it will show exactly the missing commits from C. Use your favourite variant of git addand finally a nice git commit(or several, if you prefer), and you're done. No history has been rewritten.

理想情况下,如果一切顺利,它将准确显示C. 使用你最喜欢的变体,git add最后一个 nice git commit(或几个,如果你喜欢),你就完成了。历史没有被改写。

回答by Frodon

You can try by a cherry-pick:

您可以通过挑选来尝试:

git checkout master
git cherry-pick B..[last_commit_of_C*]

Git may ask you to confirm the cherry-pick since the commits are in the ancestors.

由于提交是在祖先中,Git 可能会要求您确认挑选。

回答by jthill

Git stores snapshots and detects changes on the fly, so the way to work with the difference between a bad commit and a good one is to record the good as a descendant the bad—pretty much the same as anything, come to think of it. Use git reset --softto tell git the correct ancestry:

Git 存储快照并动态检测更改,因此处理错误提交和良好提交之间差异的方法是将好的作为后代记录坏的 - 几乎与任何事情相同,想想看。使用git reset --soft通知Git正确的祖先:

git checkout badmerge^1    # generate the right result 
git merge badmerge^2

... Fix conflicts ...
git commit

git reset --soft badmerge  # as an improvement on the wrong result
git commit

git checkout master        # merge the difference now that git sees it
git merge HEAD@{1} -m "applying corrections to a bad merge"

回答by Vampire

Try instead of creating plain patches and applying them to use git format-patchand git am. This should give you the normal conflict state situation where you then can use a merge tool too resolve the conflicts, unlike with git applywhere the application just fails.

尝试而不是创建简单的补丁并将它们应用到 usegit format-patchgit am。这应该为您提供正常的冲突状态情况,然后您可以使用合并工具也解决冲突,这与git apply应用程序刚刚失败的情况不同。