在一个被压缩的提交中恢复其中一个提交?

问题描述 投票:1回答:2

我有250 files changed的拉请求,只有5~10我改变了。

这是一个4次提交的壁球,其中一个是revert和另一个分支的merge,这是包含~240 files changed的那个。

看起来像这样

<some commits I made after this>
<squashed commit of:

minor change

working on abcd..

Revert "Merge branch 'settlement-statement' into rents-proration"

This reverts commit 0e44eae, reversing
changes made to a39e7fd.

some more change>

我想只恢复

Revert "Merge branch 'settlement-statement' into rents-proration"

This reverts commit 0e44eae, reversing
changes made to a39e7fd.

我认为合并settlement-statement分支回到我的分支会解决它,但它没有。

如何在不查看files changed中的所有文件并选择我的更改的情况下解决此问题?

git github
2个回答
3
投票

更新 - 我分两个阶段写了原始答案,因此有点令人困惑。信息保持不变,但我正在清理一下......


根据你如何改写提交,你有两个非常相似的情况之一。粗略地说:

1)如果你从一个分支压扁到另一个分支(例如通过squash),你会有一个图表

git merge --aquash

其中x -- AB!MCD -- E <--(branch_for_pr) A -- B -- !M -- C -- D <--(work_branch) 恢复了之前的合并,!MAB!MCDAB!MC的“壁球”。

2)如果你在一个分支上“就地”压缩了提交,例如D,图表更像

git rebase -i

这里x -- AB!MCD -- E <--(branch_for_pr) A -- B -- !M -- C -- D <--(branch_for_pr@{2}) 是一个reflog条目。这些工具不会像当前引用那样明显地显示reflog条目,因此可能看起来好像branch_for_pr@{2}..A“已经消失”,但是(至少在壁球发生的本地克隆上)他们希望不是。 (确实,reflog条目最终会过期 - 默认情况下大约3个月后,或者当你明确地使它们过期时。在reflog条目到期后,D可以删除旧的提交,除非同时你做了一些保持它们“可达”。此外,gcpush不会共享reflog。)

你会发现带有命令的reflog条目

fetch

然后可以在其上放置一个新的分支或标签,直到您知道不再需要它为止,以消除reflog过期将隐藏它的风险。如果你这样做,结果将看起来像第一个图(从上面的(1))。

本条目的其余部分假设实际分支指向git reflog branch_for_pr 。那么......怎么办?

最简单的方法是在D上恢复!M。这看似违反直觉,但你可以恢复任何东西;它不一定是branch_for_pr的祖先。因此,您需要一个解析为HEAD的表达式 - 可以是其提交ID,或者在此示例中类似于!M

work_branch~2

这里要了解几点背景知识:

提交只是具有少量元数据的项目的快照。元数据包括“父”列表,该列表将快照相对于历史记录中的其他快照放置。许多git命令在提交的补丁上运行 - 即该提交与其父级(或者在合并的情况下其父级之一)之间的差异。提交的元数据不包含与“通过此提交还原的提交”或“提交压缩到此提交中”的任何特殊关系;该信息基本上已丢失。

如上所述,“恢复”只是一种简单的方式来组合一个提交,该提交以某种方式与其父级相关,由另一个提交与其父级的关系控制。 git checkout branch_for_pr git revert work_branch~2 没有记住这个特定的提交是通过恢复另一个提​​交而产生的(更不用说其他提交了)。

同样,“壁球”只是指定要应用于git以创建新提交的一组更改的简便方法。结果提交不会“知道”它是一个壁球。

所以这些事情可能会改变你对自己想要做的事情的看法,并影响你如何处理这个问题。然而,对于“重新合并”的提议解决方案来说,更直接的问题是,git对于合并的恢复有点奇怪。一旦你恢复合并,它就会很容易重新合并它。您必须从新提交重新生成分支(以使重新合并成为可能),或者只是直接在最终分支上恢复还原 - 这是我建议的上面做的。

这个想法有很多变化,可能产生“更清洁”的历史;但这是最简单的,可以避免可能混淆的事情。


2
投票

你不能从壁球中拉出一个提交。你实现了愿望,他们被压成了一个。

幸运的是,Git需要几周时间才能扔掉任何东西。你的未分支的分支可能仍在那里。您的存储库希望看起来像这样。

HEAD

A - B - C - D [master] |\ | E [feature] \ F - G - H - I 是你的分支。 feature是您原始的,未撤销的提交。 F - G - H - IE所有被挤压在一起。我们想把F - G - H - I放回feature

I没有被分支或标签所引用。我们可以用I找到它。这是reflog每次搬家的历史。每次结账,退款和重置。你正在寻找这样的东西。

HEAD

7fd34b9是c6a7e90 (HEAD -> master) HEAD@{0}: rebase -i (finish): returning to refs/heads/master c6a7e90 (HEAD -> master) HEAD@{1}: rebase -i (squash): second 40c7031 HEAD@{2}: rebase -i (squash): # This is a combination of 2 commits. 4c79819 HEAD@{3}: rebase -i (start): checkout HEAD^^^ 7fd34b9 HEAD@{4}: rebase -i (finish): returning to refs/heads/master 7fd34b9 HEAD@{5}: rebase -i (start): checkout master ,在你压扁之前你的分支的提交ID。 c6a7e90是I,你压扁后的提交。然后你可以E在你压扁之前把git reset --hard 7fd34b9放回去。

更多信息可以在Git Book中找到关于featureMaintenance and Data Recovery的信息。


这就是为什么不压缩整个功能分支的原因。历史和评论者都失去了重要的细节。你为什么改变那条线?它可能是4个混合在一起的原因之一。 OTOH你可以得到一个“被压扁”的视图,一个未被取消的分支eash足够; Github将为您的PR提供一个,或者您可以做Reset Demystified。但你不能反过来,你不能从一个被压扁的分支得到无限制的变化。重要信息丢失了。

应保留压缩,以消除不正确的更改,如拼写错误修复和“我想做的改变三个提交前不同”。

© www.soinside.com 2019 - 2024. All rights reserved.