我想要重基到一个特定的提交,而不是另一个分支的HEAD:

A --- B --- C          master
 \
  \-- D                topic

to

A --- B --- C          master
       \
        \-- D          topic

而不是

A --- B --- C          master
             \
              \-- D    topic

我怎样才能做到呢?


当前回答

主题的解决方案

回答已发布问题的正确命令可能是以下任何一个(假设分支主题已经签出):

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

如果topic没有签出,你只需将topic附加到命令(除了最后一个),如下所示:

git rebase --onto B master topic

或者,先用以下方法检出分支:

git checkout topic

将提交的任何字符串改为目标提交

我们所需要的命令的基本形式,摘自文档,是:

git rebase --onto <Target> [<Upstream> [<Branch>]]

<分支>是可选的,它所做的只是在执行其余命令之前检出指定的分支。如果您已经签出了想要重基的分支,那么您不需要这个。注意,你必须指定<Upstream>才能指定<Branch>,否则git会认为你指定了<Upstream>。

<Target>是我们要附加提交字符串的提交。在提供分支名称时,您只是指定了该分支的头提交。<目标>可以是任何不包含在被移动的提交字符串中的提交。例如:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

要移动整个特性分支,您不能选择X、Y、Z或<Target>的特性,因为这些都是在被移动的组内提交的。

<Upstream>是特殊的,因为它可以表示两种不同的东西。如果它是检出分支的祖先提交,则它作为切点。在我提供的示例中,这将是任何不是C、D或master的东西。所有在<Upstream>之后直到检出分支头部的提交都将被移动。

但是,如果<Upstream>不是一个祖先,那么git将从指定的提交开始备份链,直到if与签出的分支找到一个共同的祖先(如果找不到,则中止)。在我们的例子中,B、C、D或master的<Upstream>都将导致提交B作为切点。<Upstream>本身是一个可选命令,如果没有指定它,那么git会查看签出分支的父类,这相当于输入master。

现在git已经选择了它将切割和移动的提交,它将应用它们以<Target>,跳过任何已经应用到Target的提交。

有趣的例子和结果

以此为出发点:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature

git rebase - to D A特性 将应用提交B, C, X, Y, Z来提交D,并最终跳过B和C,因为它们已经被应用了。 git rebase - to C X特性 是否应用提交Y和Z来提交C,有效地删除提交X

其他回答

如果您希望返回到不止一次提交,还有另一种方法。

下面是一个返回到n次提交的例子:

git branch topic master~n

为了解决这个问题,还可以这样做:

git branch topic master~1

该命令在git 2.7.4版本上运行良好。还没在其他版本上测试过。

使用"onto"选项:

git rebase --onto master^ D^ D

OR

git rebase --onto <commitB> <commitA> <commitD>

最后3个参数的意思是: destination (new-parent,这里是commitB) Start-after (current-parent,第一个提交被移动的父节点), 和end-inclusive(要移动的最后一个提交)。

一个更简单的解决方案是git rebase <SHA1 of B> topic。不管你的头在哪里,这都是有效的。

我们可以从git rebase文档中确认这种行为

<upstream>要比较的上游分支。可能是任何有效的 提交,而不仅仅是一个现有的分支名称。默认为配置的 当前分支的上游。

你可能会想,如果我在上面的命令中也提到topic的SHA1会发生什么?

git rebase <SHA1 of B> <SHA1 from topic>

这也可以工作,但rebase不会使Topic指向这样创建的新分支,HEAD将处于分离状态。因此,从这里开始,您必须手动删除旧的Topic,并在rebase创建的新分支上创建一个新的分支引用。

添加到答案中使用——onto:

我从来没有把它背下来,所以我写了这个小助手脚本: Git:将一个分支(子)从一个基基重设为另一个基基,留下另一个基基的提交。

用法:

moveBranch <branch> from <previous-base> to <new-base>

简而言之:

git rebase --onto "$3" "$2" "$1"

除此之外,还有一个类似的解决方案,那就是选择一系列的提交:

git co <new-base> 
git cherry-pick <previous-base>..<branch>
git branch -f branch

两者的效果差不多。请注意,此语法跳过<previous-branch>本身的提交,因此它会优选下一个和后续的提交,包括<branch>的提交。

你可以通过在commit上创建一个临时分支来避免使用——onto参数,然后以简单的形式使用rebase:

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp