从多个git rebase中恢复“旧提交”

时间:2010-04-22 13:02:29

标签: git git-rebase

我知道this问题,但不知道如何将其映射到我目前的情况。 (Rebase是可怕的,撤销rebase是双重可怕的!)

我从我的主人的几个不同的功能分支开始:

master    x-x-x-x-x-x-x-x-x-x
             \       \    \
FeatureA      1-2-3   \    \
FeatureB               A-B  \
FeatureC                     X-Y-Z

我想将它们合并在一起并检查它们是否有效,然后再合并到主机顶部,所以我做了一个:

git checkout FeatureB
git rebase FeatureA
git mergetool //etc
git rebase --continue

然后

git checkout FeatureC
git rebase FeatureB
git mergetool //hack hack
git rebase --continue

让我留下了

master    x-x-x-x-x-x-x-x-x-x
             \
FeatureA      1-2-3 
                   \
FeatureB            A'-B'
                         \ 
FeatureC                  X'-Y'-Z'

然后我纠正了一些没有正确编译的位,并将整个功能设置为可接受的状态:

master    x-x-x-x-x-x-x-x-x-x
             \
FeatureA      1-2-3 
                   \
FeatureB            A'-B'
                         \ 
FeatureC                  X'-Y'-Z'-W

我的问题是我的同事告诉我,我们还没有为FeatureA做好准备。

我有什么方法可以保留我的所有工作,但也可以恢复到我可以将FeatureC重新设置为功能B的情况吗?

3 个答案:

答案 0 :(得分:5)

根据评论,这是我对答案的理解:

当您执行rebase时,当前分支上的提交被“撤消”,然后“重新应用”,但实际上,它们未被撤消,它们被“记住”*,并重新应用新ID,例如,如果我查看git reflog show FeatureB,我会得到类似的结果:

7832f89 FeatureB@{0} rebase finished: refs/heads/FeatureB onto f4df3
efd3fed FeatureB@{1} commit: B
f3f3d43 FeatureB@{2} commit: A
2f32fed FeatureB@{3} branch: Created from HEAD

正如@Jefromi所说,原始文件仍然存在(reflog中A和B提交的SHA与git log中的提交不同,它们对应于A'和B')。

同样,git reflog show FeatureC看起来像这样

32873ef FeatureC@{0} commit: W
17dafb3 FeatureC@{1} rebase finished: refs/heads/FeatureC onto 89289fe
893eb78 FeatureC@{2} commit: Z
a78b873 FeatureC@{3} commit: Y
e78b873 FeatureC@{4} commit: X
378cbe3 FeatureC@{5} branch: Created from HEAD

同样,原始的Z,Y和X提交仍然存在

所以,我的问题的解决方案是从master的HEAD创建一个新的分支FeaturesBC(例如),然后挑选提交的FeatureB {2& 1},然后是FeatureC {4,3,2}和(可能)W:

git checkout master
git checkout -b FeaturesBC
git cherry-pick f3f3d43 
git cherry-pick efd3fed 
//etc...

(它似乎有效,我不得不重新做一些相同的合并,但它并不太糟糕)

编辑,来自Jefromi:

可能没有必要采摘樱桃。您还可以简单地重新创建分支在rebase之前的分支:

git branch FeatureB-old efd3fed
git branch FeatureC-old 893eb78

或者,如果你想抛弃FeatureB和FeatureC的重新定位,回到原来的位置:

git branch -f FeatureB efd3fed
git branch -f FeatureC 893eb78

最后,请注意,如果您愿意,可以使用reflog中提供的其他表示法 - 例如,FeatureC@{2}而不是893eb78。这意味着“FeatureC的第二个先前位置”。但是,请注意在查看reflog之后立即使用它,因为只要再次更新分支(移动它,提交它...),FeatureC@{2}将引用17dafb3。

@Jefromi评论了我的问题:

  

您可能应该从master或featureC创建一个新分支(比如说,名为featuresABC),并将每个分支合并到其中,使功能分支保持不变。保留各个功能分支的独立历史是很好的。

<子> *确切地说,旧的提交对象只是保留在存储库中。他们最终会被修剪,因为你不想要一个充满旧悬挂的回购;这将在第一次git gc运行且提交至少两周(由gc.pruneExpire配置)时发生。

答案 1 :(得分:1)

如果所有其他方法都失败了,您可以从master和git cherry-pick所有B或C的提交重新启动以重新创建这些分支。我希望其他人已经写过一个脚本,如果这是唯一的解决方案......

答案 2 :(得分:1)

您可以使用git rebase --onto <old-merge-base from B> A C将从C到A的所有内容重新绑定到主节点上。它将离开你:

master    x-x-x-x-x-x-x-x-x-x
             \       \
FeatureA      1-2-3   \
                       \
FeatureB                A'-B'
                            \ 
FeatureC                     X'-Y'-Z'-W

要找到要重新绑定的点,可以使用git的reflog和git merge-base的组合 - 但是你也可以重新绑定到A的合并基础,以获得类似于以下内容的历史记录: / p>

master    x-x-x-x-x-x-x-x-x-x
            |\ 
FeatureA    | 1-2-3
             \
FeatureB       A'-B'
                    \ 
FeatureC             X'-Y'-Z'-W

git rebase --onto $(git merge-base A master) A C