使用 Git 恢复损坏的合并并重新应用选定的提交
我们最近遇到一个问题,合并以某种方式导致所有更改导致一个父项在合并提交中被撤消,并且在此之后应用了多个提交。所有这些都已推送到我们的共享源存储库。我希望能够恢复错误的合并并重新应用其他更改集。做到这一点最简单的方法是什么?
ASCII 艺术示例:
A-B-C-D
/ \
P-Q M-X-Y-Z
\ /
1-2-3-4
---time--->
提交 M 包含更改 A 到 D,但所有更改 1 到 4 均已由该提交恢复。
我希望能够恢复回来,例如。更改集 4,并重新应用更改 AD 和 X 到 Z,理想情况下无需手动重做每个更改。
如果这是不可能的,我想听听最好的解决方法 - 例如。也许从 4 分支,再次合并到 D 中,小心不要破坏任何东西,然后手动将 X 重新应用到 Z?
(理想的情况是知道如何使用 TortoiseGit 来做到这一点,尽管只知道命令行就可以让我推断出其余的事情。)
We recently encountered a problem where a merge somehow led to all the changes leading to one parent being undone in the merge commit, and several commits have been applied after that point. All this has been pushed to our shared origin repository. I want to be able to revert the bad merge and reapply the other change sets. What is the easiest way to do this?
ASCII art example:
A-B-C-D
/ \
P-Q M-X-Y-Z
\ /
1-2-3-4
---time--->
The commit M has included changes A to D but all changes 1 to 4 were reverted by that commit.
I would like to be able to revert back, eg. to changeset 4, and reapply changes A-D and X to Z, ideally without manually redoing each change.
If this is not possible, I'd like to hear of the best workarounds - eg. maybe branch from 4, merge in D again being careful not to break anything, then manually reapplying X to Z?
(An ideal situation would be to know how to do this using TortoiseGit, although just knowing the command line should allow me to deduce the rest.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你想要得到的结果的逻辑效果是:
有几种方法。我们假设 master 现在指向
Z
。恢复合并提交(最安全但更混乱)
我们需要首先恢复损坏的合并提交
M
。我们将这样做:接下来,让我们重新应用被否定或可能被否定的提交:
现在我们有这个:
这是最安全的方法,因为它不会触及任何以前的历史记录,因此任何人的上游存储库都不会受到影响。但它也是最混乱的,因为它留下了很多碎屑。唉,这就是草率合并所付出的代价。
扔掉破碎的历史(最危险但最干净)
这需要让每个人都同意你的方法是正确的。您将破坏人们的历史记录,并且如果您这样做,任何拥有受污染的合并提交
M
的人都会遇到问题。但你的历史会看起来更干净。因为您将破坏任何具有受污染提交的团队成员的历史记录,直到他们拉下远程存储库并将其本地主服务器重置到该点为止,所以这是最危险的方法。
首先,我们将 master 回退到 Q,这是最后一次没有问题的提交。
接下来,我们需要以交互方式对损坏的提交序列进行变基。
您将在编辑器中看到一个提交列表,如下所示:
其中之一是损坏的合并提交。删除这一行;保存并关闭。
Git 现在将按照您要求的顺序应用提交,并且您将处于 tmp 状态。如果一切看起来都不错,则重置 master:
现在强制推送到原点:
损坏的历史记录将被删除,master 将指向新的历史记录。
最后,
您应该考虑要求您的团队使用 nvie 的 git-flow 之类的东西来避免未来的混乱并防止出现混乱。
更新:看起来 nvie 放弃了对 git-flow 的支持。然而,Peter van der 进行了分叉并且正在维护一个版本
You want to wind up with something whose logical effect is:
There are a couple of approaches. Let's assume master points to
Z
right now.Revert the merge commit (safest but messier)
We need to revert the broken merge commit
M
first. We'll do that with:Next, let's re-apply the negated or potentially negated commits:
Now we have this:
This is the safest approach because it doesn't touch any previous history, so no one's upstream repos will be affected. But it's also the messiest because it leaves a lot of detritus. Alas, that's the price you pay for a sloppy merge.
Throw away the broken history (most dangerous but cleanest)
This will require getting consensus from everyone that your approach is sound. You will break people's history, and anyone who has the tainted merge commit
M
will experience issues if you do it this way. But your history will look cleaner.Because you will break the history of any team members who have the tainted commit until they pull down the remote repository and until they reset their local masters to that point, this is the most dangerous approach.
First, we rewind master back to
Q
, the last commit without problems.Next, we need to interactively rebase the broken commit sequence.
You'll be presented with a list of commits in your editor that looks like this:
One of these will be the broken merge commit. Delete this line; save and close.
Git will now apply the commits in the order you asked for, and you will be on tmp. If everything looks good, then reset master:
Now force-push to origin:
The broken history will be removed and master will point to a new history.
Finally
You should consider asking your team to use something like nvie's git-flow to avoid future messiness and prevent snafus.
Update: It looks like nvie abandoned support for git-flow. However, Peter van der Does forked and is maintaining a version