恢复“旧提交”来自多个 git rebase

发布于 2024-08-30 01:19:34 字数 1191 浏览 3 评论 0原文

我知道这个问题,但不确定如何将其映射到我当前的情况。 (Rebase 很可怕,撤销 rebase 更可怕!)

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

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

我想将它们全部合并在一起,并在合并回 master 顶部之前检查它们是否有效,所以我做了:

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

我的问题是我的同事告诉我我们还没有为功能 A 做好准备。

有什么方法可以让我保留所有工作,同时又恢复到可以将功能 C 重新设置为功能 B 的情况吗?

I am aware of this question, but not to sure how to map it to my current situation. (Rebase is scary, undoing rebase is double scary!)

I started out with several different feature branches of my master:

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

I wanted to merge them all together and check they worked before merging back onto the top of master, so I did a:

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

Then

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

Which leaves me with

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

Then I corrected some bits that didn't compile properly, and got the whole feature set to an acceptable state:

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

My problem is that my colleagues tell me that we're not ready for FeatureA.

Is there any way for me to keep all my work, but also revert to a situation where I can just rebase FeatureC on to Feature B?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁对谁错谁最难过 2024-09-06 01:19:34

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

当您进行变基时,当前分支上的提交将被“撤消”,然后“重新应用”,但实际上,它们并没有被撤消,而是被“记住”* ,并重新应用新的 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 所说,原始 ID 仍然存在(A 的 SHA) reflog 中的 和 B 提交与 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 提交仍然存在

所以,我的问题的解决方案是创建一个新分支FeaturesBC离开master的HEAD(例如),然后挑选提交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:

择优挑选可能没有必要。您还可以简单地重新创建分支之前的分支:

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

或者,如果您想丢弃FeatureB和FeatureC的重新基位置,回到它们之前的位置:

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

最后,请注意,如果您愿意,您可以使用另一个引用日志中提供的符号 - 例如,FeatureC@{2} 而不是 893eb78。这意味着“FeatureC 的第二个先前位置”。不过,请注意,仅在查看引用日志后立即使用此选项,因为一旦您再次更新分支(移动它、提交它...),FeatureC@{2} 将引用17dafb3 代替。

正如 @Jefromi 对我的问题的评论:

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

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

This is my understanding of what the answer is, based on comments:

When you do a rebase, the commits on your current branch are 'undone', then 'reapplied', but actually, they are not undone, they are 'remembered'*, and reapplied with new IDs, so for example, if I look in git reflog show FeatureB, I get something like this:

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

So as @Jefromi said, the originals are still there (the SHAs of the A and B commits in the reflog are not the same as the ones in git log, which correspond to A' and B').

Similarly, git reflog show FeatureC looks like this

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

Again, the original Z, Y and X commits are still there

So, the solution to my problem is to create a new branch FeaturesBC off the HEAD of master (for example), then cherry-pick the commits FeatureB{2 & 1}, and then FeatureC{4, 3, 2}, and (possibly) W:

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

(It seems to have worked, I had to re-do some of the same merges, but it wasn't too bad)

Edit, from Jefromi:

Cherry-picking may not have been necessary. You can also simply recreate branches where the branches were before the rebase:

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

Or, if you want to throw away the rebased position of FeatureB and FeatureC, going back to where they were before:

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

Finally, note that if you like you can use the other notation provided in the reflogs - for example, FeatureC@{2} instead of 893eb78. This means "the second previous position of FeatureC". Be careful to only use this immediately after viewing the reflog, though, because as soon as you update the branch again (move it, commit to it...), FeatureC@{2} will refer to 17dafb3 instead.

As @Jefromi commented on my question:

You should probably have created a new branch off of master or featureC (called featuresABC, say), and merged each into it, leaving the feature branches intact. It's good to preserve the independent history of various feature branches.


* To be precise, the old commit objects are simply left in the repository. They will eventually be pruned, since you don't want a repo full of old dangling commits; this will happen the first time git gc is run and the commits are at least two weeks old (configured by gc.pruneExpire).

等风来 2024-09-06 01:19:34

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

If all else fails you can restart from master and git cherry-pick all of B's or C's commits to recreate those branches. I hope someone else already wrote a script if this is the only solution...

妞丶爷亲个 2024-09-06 01:19:34

你可以使用 git rebase --ontoA C 将从 C 到 A 的所有内容重新设置为 master 上的某个点。它会给你留下:

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 的合并基础,具有类似于以下内容的历史记录:(

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)

you can use git rebase --onto <old-merge-base from B> A C to rebase everything from C up to A onto a point on master. it will leave you with:

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

to find the point where you want to rebase onto, you can use a combination of git's reflog and git merge-base – but you can also rebase onto the merge base of A, to have history similar to the following:

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文