我有一个提交图,看起来像下面的那个.标记*为的提交代表许多提交.
A*
|
B---------
| |
C* D* <- old feature branch
| |
E---------
|
F*
|
G <- master
Run Code Online (Sandbox Code Playgroud)
合并提交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.
Run Code Online (Sandbox Code Playgroud)
理想情况下,我们会采用 C* 中的所有更改,将它们应用于 master 并解决所有冲突。
不,理想情况下,您会倒带时间,按照当时的方式进行合并(但这次是正确的),然后重新应用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!
Run Code Online (Sandbox Code Playgroud)
如果您设法在 rebase 期间处理所有冲突,您最终将在 branch 中获得您最初想要的内容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/
Run Code Online (Sandbox Code Playgroud)
现在,当您输入newrepos并执行 a 时git status,您将在分支上master并准确地看到master和之间的所有更改correct-master,就像您应用了补丁一样。它将捕获已删除的文件、新文件、更改的文件、更改的权限、更改的符号链接等。
理想情况下,如果一切顺利,它将准确显示C. 使用你最喜欢的变体,git add最后一个 nice git commit(或几个,如果你喜欢),你就完成了。历史没有被改写。
您可以尝试选择:
git checkout master
git cherry-pick B..[last_commit_of_C*]
Run Code Online (Sandbox Code Playgroud)
Git 可能会要求您确认樱桃选择,因为提交位于祖先中。