2017-03-03 55 views
1

我有一个类似下面的提交图。标有*的提交表示大量提交。如何重新合并已经合并的分支?

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

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

所有东西都已经被推送(开源项目),所以更改历史记录不是一个选项。

我试图创建一个从提交C *补丁并应用到主,但由于从C *的变化有些已经被正确地合并,因为这个项目,因为演化出提交,的大约80%补丁失败。

理想情况下,我们会将C *中的所有更改应用于掌握并解决所有冲突。但是因为分支已经合并了,所以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. 
+0

你试过git恢复不正确的提交。这将撤消由错误提交引起的更改以及丢失的更改。像git的恢复E. – 2017-03-03 16:08:59

+0

@Eyorther东西怎么会是帮助,因为合并是错误的承诺? – Vampire

回答

1

理想的情况下,我们将采取在C *所有的变化,运用他们掌握并解决所有冲突。

没有,最好你会倒带时间,做了合并,因为它是当时(但正确的,这一次),然后重新应用F*变化,并用正确的master结束。

你可以这样说:

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! 

如果你能处理底垫在所有的冲突,你将最终获得您想要的到底是什么,原来,在该分支correct-master

既然你不想改变历史,然后你可以创建一个大补丁并应用到当前的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/ 

现在,当你进入newrepos,做一个git status,您将在分支master,将看到精确mastercorrect-master之间的所有变化,就好像你在应用补丁程序。它将捕获已删除的文件,新文件,已更改的文件,更改的权限,更改的符号链接等。

理想情况下,如果一切正常,它会显示从C完全丢失的提交。使用你最喜欢的变种git add,最后是一个不错的git commit(或者几个,如果你愿意的话),你就完成了。没有历史被重写。

+0

我不知道我的理解对底垫命令的需要。一旦我拥有了正确的合并分支,我能不能将它合并到master?这与使用rebase有何不同? –

+0

@JohnM,它可以工作或不能工作,但它在语义上没有做正确的事。合并操作是将两件事合并在一起,从共同的祖先中分离出来。这不是你在这里所做的。相反,它是在树上的另一个地方进行一系列的提交,这正是我们在这里所做的。实际的好处是,rebase是这样提交的,因此它可能更容易解决冲突,尽管如果你不幸,并且几乎任何提交都会发生同样的冲突,它可能会变得糟糕透顶。你当然可以尝试两种! – AnoE

+0

谢谢,我可以重新绑定它。我必须做的一个小改变是在错误的合并之后重新启动,而不是缺失的提交:'git rebase - correct correct-merge wrong-merge correct-master'。但我终于明白这是如何工作的,而且非常整齐。 –

0

尝试,而不是建立简单的补丁和应用它们使用git format-patchgit am。这应该给你正常的冲突状态的情况下,然后你可以使用合并工具也解决冲突,不像git apply应用程序失败。

+0

您可以'git的申请-3'用'混帐格式patch'或'混帐show'制作了补丁,来调用合并机械。 ('git的am'使用'git的应用-3'内部)。 – torek

0

您可以通过摘樱桃尝试:

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

的Git可能会要求您确认摘樱桃,因为提交是祖先。

0

的Git存储快照和检测上飞的变化,所以一个坏的区别工作提交的方式和良好的一个是记录良好的后裔坏几乎一样的东西,来想一想。使用git reset --soft告诉git正确的祖先:

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

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 @{1} -m "applying corrections to a bad merge"