将Git中的初始提交移动到另一个分支

7

我想要迁移到GitFlow工作流,并且我希望重写仓库的历史记录,以便所有内容都符合新的仓库。

目前看起来是这样的:

Master: A - B - C - D - E - F - - - - - - - - - L
                             \                 /
Release:                      \           J - K
                               \         /     \
Development:                    G - H - I       M

我希望它看起来像这样:
Master:  A - - - - - - - - - - - - - - - - - - - L
          \                                     /
Release:   \                               J - K
            \                             /     \
Development: B - C - D - E - F - G - H - I       M

我在这里尝试寻找答案,并找到了一个答案,但是它似乎只适用于创建新分支,而不是使用已经存在的分支。
非常感谢您的帮助。

2
假设左侧是较早的,右侧是当前的,这两个图表代表相同的历史记录。提交不记录分支;分支只是指向单个提交的指针。 - Fred Foo
请查看cherry-pick。https://dev59.com/7Wox5IYBdhLWcg3wOx79 - Donal
2个回答

11
在 Git 中,正如 larsmans 在 他的评论 中指出的那样,分支只是指向特定提交的指针/引用。像您在图表左侧所做的那样,使用分支名称标记代码行可能会令人困惑。
例如,过去可能是真的,提交 G、H 和 I 仅属于 development 分支的祖先。然而,在您的 repo 的当前状态下,它们属于所有三个分支(master、development 和 release)的祖先。
想到那三个提交(GHI)在某种程度上仍然与development分支更相关,而不是masterrelease,这已经没有任何意义了,因为您的存储库不记得过去分支引用指向的位置(尽管该信息在本地存储在称为reflog的东西中)。您的Git存储库只知道分支引用在当前指向哪里。
因此,当您绘制图形来描述存储库的状态时,如果一个分支指向一个提交,则使用相应的分支名称标记提交本身更有意义。我在下面的所有图表中都这样做了。

原始状态

A - B - C - D - E - F - - - - - - - - - L [master]
                     \                 /
                      G - H - I - J - K [release]
                                       \
                                        M [development]

期望状态

A - - - - - - - - - - - - - - - - - - - L' [master]
 \                                     /
  B - C - D - E - F - G - H - I - J - K [release]
                                       \
                                        M [development]

最终陷入这种状态,您应该执行以下三个步骤。
程序
1 - 检查您的主分支(master
git checkout master

之后,HEAD 指向 master
A - B - C - D - E - F - - - - - - - - - L [HEAD -> master]
                     \                 /
                      G - H - I - J - K [release]
                                       \
                                        M [development]

2-执行master的硬重置以提交A。
git reset --hard <commit_ID_of_A>

因为在您的仓库中没有任何引用可以访问到L,所以它从历史记录图中“消失了”,然后您只剩下了。
A [HEAD -> master]
 \
  B - C - D - E - F - G - H - I - J - K [release]
                                       \
                                        M [development]

3 - 将release分支真正合并到master分支中

在这个阶段,如果你仅仅运行以下命令:

git merge release

因为master的尖端是release尖端的祖先,所以会进行快进合并,你最终只会得到:
A - B - C - D - E - F - G - H - I - J - K [HEAD -> master,release]
                                         \
                                          M [development]

这不是你想要的。因此,在此需要使用--no-ff选项来强制执行真正的合并:
git merge --no-ff release

在执行这个最后的命令之后,您的代码库应该处于所需状态:
A - - - - - - - - - - - - - - - - - - - L' [HEAD -> master]
 \                                     /
  B - C - D - E - F - G - H - I - J - K [release]
                                       \
                                        M [development]

请注意,我将新提交命名为L'而不是L,因为这两个提交具有不同的父级: L的父级是FK,而新提交L'的父级是AK

1
这应该可以满足您的需求(虽然我不确定您的发布分支)。
git checkout master
git reset --hard commit_A # the commit id for A

git merge --no-ff release

1
最后一个命令应该是 git merge --no-ff release,而不是git merge --no-ff commit_L;在我的回答中可以看到原因。 - jub0bs
@ryenus,我需要在我的回答中删除任何提到你的引用吗?还是保持现状? - jub0bs
@Jubobs,我猜以后你可以整理一下以便澄清,这样有类似需求的人就能通过更简洁和清晰的阅读解决他们的问题了。顺便说一句,你很好地用那些图表说明了硬重置然后无快进合并的原理,干得漂亮! - ryenus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接