Git:如何重新定义特定的提交?

时间:2011-10-12 17:27:21

标签: git version-control rebase git-rebase

我想重新定义一个特定的提交,而不是另一个分支的HEAD:

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

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

而不是

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

我怎样才能做到这一点?

10 个答案:

答案 0 :(得分:74)

你可以通过在你喜欢的提交上设置一个临时分支来避免使用--onto参数,然后以简单的形式使用rebase:

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

答案 1 :(得分:54)

你甚至可以直接采取行动:

git checkout topic
git rebase <commitB>

答案 2 :(得分:44)

使用“上”选项:

git rebase --onto master^ D^ D

答案 3 :(得分:10)

上面的jsz评论为我节省了大量的痛苦,所以这里有一个基于它的逐步收件人,我一直在使用它来修改/移动任何其他提交之上的任何提交:

  1. 找到要重新分配(移动)的分支的前一个分支点 - 将其称为旧父级。在上面的例子中, A
  2. 查找要将分支移动到其上的提交 - 将其称为新父级。在例如 B
  3. 的例子中
  4. 你需要在你的分支上(你移动的那个):
  5. 申请您的rebase:git rebase --onto <new parent> <old parent>
  6. 在上面的例子中,它简单如下:

       git checkout topic
       git rebase --onto B A
    

答案 4 :(得分:2)

我使用了上述解决方案的混合物:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

我发现阅读和理解起来要容易得多。接受的解决方案导致我发生合并冲突(懒得手工修复):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

答案 5 :(得分:1)

由于重新定级是如此基本,因此这里是Nestor Milyaev's answer的扩展。结合来自jsz'sSimon South'sAdam Dymitruk's answer注释产生此命令,该命令可在topic分支上工作,无论它是否从master分支的提交{{1} }或A

C

请注意,最后一个参数是必需的(否则,它倒回分支以提交git checkout topic git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name> )。

示例:

B
# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>

所以最后一个命令是我通常使用的命令。

答案 6 :(得分:1)

主题解决方案

回答发布的问题的正确命令可以是以下任意命令(假设分支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>]]

<Branch>是可选的,它所做的就是在执行其余命令之前检出指定的分支。如果您已经签出要重新设置基准的分支,则不需要此分支。请注意,您必须指定<Upstream>才能指定<Branch>,否则git会认为您正在指定<Upstream>

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

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

要移动整个功能分支,您不能选择XYZfeature作为<Target>,因为所有这些都是提交在要移动的组中。

<Upstream>之所以特别,是因为它可能意味着两种不同的含义。如果它是已签出分支的祖先的提交,则它将用作切入点。在我提供的示例中,这将不是CDmaster之外的任何东西。在<Upstream>之后直到已检出分支的头部的所有提交都是将被移动的提交。

但是,如果<Upstream>不是祖先,那么git从指定的提交中备份链,直到找到带有已检出分支的公共祖先为止(如果找不到,则中止)。在我们的情况下,<Upstream>BCD的{​​{1}}都将以提交master作为切入点。 B本身是可选命令,如果未指定,则git会查看已签出分支的父级,等效于输入<Upstream>

现在git已经选择了要剪切和移动的提交,它将它们应用到master上,跳过已经应用于目标的任何提交。

有趣的例子和结果

使用此起点:

<Target>
  • A --- B --- C --- D --- E master \ \-- X --- Y --- Z feature
    将应用提交git rebase --onto D A featureBCXY提交Z并最终跳过D和{ {1}},因为它们已经被应用。

  • B
    将应用提交Cgit rebase --onto C X feature提交Y,有效删除提交Z

答案 7 :(得分:0)

还有另一种方法,或者如果您希望移回多个提交,则不可以。

以下是返回到n提交数量的示例:

git branch topic master~n

出于这个问题,也可以这样做:

git branch topic master~1

该命令在git version 2.7.4上可以正常使用。尚未在其他任何版本上对其进行测试。

答案 8 :(得分:0)

一个更简单的解决方案是git rebase <SHA1 of B> topic。无论您的HEAD身在何处,它都可以工作。

我们可以通过git rebase doc

确认此行为
  

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


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

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

这也将起作用,但是重新设置基准将不会使Topic指向如此创建的新分支,并且HEAD将处于分离状态。因此,您必须从此处手动删除旧的Topic,并在由rebase创建的新分支上创建新的分支引用。

答案 9 :(得分:0)

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

我从来没有背过它,所以我写了这个小帮手脚本:
Git: Rebase a (sub)branch from one base to another, leaving the other base's commits.

用法:

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

简而言之:

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

除此之外,还有一个可用于类似目的的解决方案是cherry-pick连续提交:

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

相同的效果越多越好。请注意,此语法跳过 <previous-branch> 处的提交,因此它会挑选下一个和后续的提交,包括 <branch> 处的提交。