还原提交中的提交之一?

时间:2018-09-04 17:56:29

标签: git github

我有一个250 files changed的拉取请求,我只更改了其中的5〜10。

这是一个包含4个提交的目录,其中一个是revert的{​​{1}}和另一个分支,而这个分支包含〜240个merge

看起来像这样

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中的所有文件并选择我的更改?

2 个答案:

答案 0 :(得分:3)

更新-我分两个阶段编写了原始答案,因此有些混乱。信息保持不变,但我要对其进行清理...


取决于您如何squash进行提交,您有两种非常相似的情况之一。粗略地说:

1)如果您从一个分支压缩到另一个分支(例如,被git merge --aquash压缩),则您将拥有一个类似

的图形
x -- AB!MCD -- E <--(branch_for_pr)

A -- B -- !M -- C -- D <--(work_branch)

其中!M恢复了一些先前的合并,而AB!MCDAB!MC,和D

2)如果您将提交“压缩”在分支上,例如git rebase -i,图形更像

x -- AB!MCD -- E <--(branch_for_pr)

A -- B -- !M -- C -- D <--(branch_for_pr@{2})

此处branch_for_pr@{2}是引用日志条目。该工具显示的日志条目不如当前的ref明显,因此看起来A .. D似乎“消失了”,但是(至少在发生壁球的本地克隆上)他们希望不是。 (的确,reflog条目最终会过期-默认情况下大约3个月后,或者您明确将其过期。在reflog条目过期之后,gc可以删除旧的提交,除非与此同时,您已经完成了使它们“可访问”的操作。此外,reflog也不会在pushfetch上共享。)

您将使用以下命令找到reflog条目

git reflog branch_for_pr

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

此条目的其余部分假定实际分支指向D。那么...如何进行?

最简单的方法是还原!M上的branch_for_pr。这看起来似乎违反直觉,但是您几乎可以还原任何内容。它不一定是HEAD的祖先。因此,您需要一个可解析为!M的表达式-它可以是其提交ID,或者在本示例中为work_branch~2之类。

git checkout branch_for_pr
git revert work_branch~2

要了解的一些背景知识:

提交只是具有少量元数据的项目的快照。元数据包括一个“父”列表,该列表将快照相对于其他快照的历史记录进行放置。许多git命令都对提交的 patch 进行操作-即,该提交与其父级(或合并时,其父级之一)之间的区别。提交的元数据不包含任何特殊关系来“由此提交还原的提交”或“被压缩为该提交的提交”;该信息实际上丢失了。

如上所述,“还原”只是一种以某种方式组装与其父项相关的提交的简便方法,该提交受另一提交与其父级的关系的支配。 git并不表示该特定提交是通过还原另一个提交(而不是其他提交)而生成的。

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

因此,这些事情可能会改变您对尝试做的事情的思考方式,并影响您解决此问题的方式。对于“重新进行合并”的提议解决方案,还有一个更直接的问题是,git对于合并的还原有点奇怪。还原合并后,重新合并就不那么容易了。您要么必须从新的提交中重新生成分支(以使重新合并成为可能),要么只需还原还原-我建议您直接在最终分支上进行还原。

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

答案 1 :(得分:2)

您不能从南瓜中拉出一个提交。您如愿以偿,它们被压缩为一个。

幸运的是,Git花费了数周时间才能丢弃任何东西。您未压缩的分支可能仍然存在。希望您的存储库看起来像这样。

A - B - C - D [master]
            |\
            | E [feature]
            \
             F - G - H - I

feature是您的分支。 F - G - H - I是您未压缩的原始提交。 EF - G - H - I压在一起。我们想将feature重新放到I上。

I未被分支或标签引用。我们可以使用reflog找到它。这是每次HEAD移动时的历史记录。每次签出,重新设置基准并重置。您正在寻找类似的东西。

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

7fd34b9是I,这是压扁之前分支的提交ID。 c6a7e90是E,即您压缩后的提交。然后,您可以git reset --hard 7fd34b9feature放回原位。

可以在Git书中找到有关Maintenance and Data RecoveryReset Demystified的更多信息。


这就是为什么不压缩整个要素分支的原因。重要的细节都丢失了历史和审阅者。你为什么改变那条线?这可能是四个混合原因之一。 OTOH,您可以充分了解未压缩的分支eash的“压缩”视图; Github将为您的PR提供一个,也可以执行git diff master。但是,您不能反其道而行之,也不能从压缩的分支中获得未压缩的更改。重要信息丢失。

应该保留挤压以消除无趣的更改,例如拼写错误和“我想在三个提交之前以不同的方式进行更改”。

相关问题