Git:如何基于特定的提交?


154

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

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

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

代替

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

我该如何实现?


4
git checkout B跑步前您尝试过做git rebase吗?
2011年

不,对您有帮助吗?我想只有rebase命令的引用才是重要的。
Ondra参观Žižka

Answers:


98

您可以通过在所需的提交上创建一个临时分支,然后以其简单形式使用rebase来避免使用--onto参数:

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

5
我更喜欢这种类似于RISC的方法:)尝试一下。谢谢。
Ondra参观Žižka

10
我不知道为什么在稍微不同的情况下它对我不起作用。我希望跳过pep8并基于mastergit rebase temp(在组中时)放弃“当前分支组是最新的。”。
Alois Mahdal 2014年

4
该解决方案不适用于该主题已重新基于master的情况,但是您希望将其基于祖先重新掌握。在这种情况下,必须使用git rebase --onto <target> <from> <to>以便指定<from>提交。
mirzmaster

如果要基于分支所基于的同一提交,这是迄今为止最简单的选择。
Ash Ash

1
我似乎可以工作,但是GitLab却说了别的话。如果我落后10提交,提前5提交,我的期望是落后8提交,获得2提交后提前5提交。但不是这一点,增加了更多的提交给那些5
ROMANIA_engineer

67

您甚至可以采用直接方法:

git checkout topic
git rebase <commitB>

6
对我来说,这实际上并没有达到预期目的。据我所知,它试图重订到的“最后的共同祖先” topiccommitB
丹·伦斯基

2
@DanLenski,这不是rebase的工作方式。引用文档后It works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn. 我现在再次尝试了,似乎工作得很好。
r0hitsharma 2015年

1
超级简单,可行!我现在有:commitB_from_master-> topicCommit1-> topicCommit2。
Martin Konicek '16

它对我不起作用。在此之前,GitLab说“ n承诺”。现在,它说“ m承诺” m > n
ROMANIA_engineer19年

48

使用“ onto”选项:

git rebase --onto master^ D^ D

2
D并且D^将是“主题”的最后一次提交和倒数第二次提交的哈希?
Ondra参观Žižka

39
语法就像git rebase --onto <new-parent> <old-parent>。请参阅将git父指针设置为其他父对象。在你的情况,<新的父母>是B和<老父母>是A.
JSZ

7
我总是使用3个参数:设计基准,重新确定基准的提交的开始和结束。
亚当·迪米特鲁克

14
这对我git rebase --onto <commit-ID> master

4
@jsz的评论是正确的,与Simon South的评论相反,这是相反的:git rebase --onto master <commit-ID-of-old-parent>对于OP git rebase --onto B A
华丽的

19

上面jsz的评论为我节省了很多痛苦,所以这是基于它的逐步使用方法,我一直在使用该方法在所有其他提交的基础上重新放置/移动任何提交:

  1. 找到要重新建立基础(移动)的分支的上一个分支点-称为旧父节点。在上面的例子中是A
  2. 查找您想将分支移至其上的提交-称为新父级。在例子中是B
  3. 您需要在分支机构(移动的分支机构)上:
  4. 应用您的基准: git rebase --onto <new parent> <old parent>

在上面的示例中,它很简单:

   git checkout topic
   git rebase --onto B A

6
这应该是正确的答案。除了我使用之外git rebase --onto B master,请参阅我的答案以获得更详尽的说明。
扎克·莫里斯

这对我来说效果不佳。我选择了2个连续的提交(来自master的最后一个提交在当前分支中,而来自master的第一个提交不在当前分支中)。我从后面100个开始-前面10个,而不是后面有99个-前面10个,现在我后面有105个-前面13个。
ROMANIA_engineer19年

很抱歉听到这没有用。听起来您的分支分歧很大-我建议先挤压一下,然后再尝试使用这么多差异为分支重新建立基础。
Nestor Milyaev '19年

11

主题解决方案

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

移动整个特性分支,你不能选择XYZ,或feature作为<Target>,因为这些都是组内提交移动。

<Upstream>之所以特别是因为它可以表示两种不同的含义。如果提交是签出分支的祖先,那么它将用作切入点。在我提供的例子,这将是任何不是CDmaster<Upstream>直到已检出分支的头部为止的所有提交都是将被移动的提交。

但是,如果<Upstream>不是祖先,那么git会从指定的提交中备份链,直到找到带有已签出分支的公共祖先为止(如果找不到祖先,则中止)。在我们的例子中,一<Upstream>BCD,或master都将导致提交B作为切点。<Upstream>本身是一个可选命令,如果未指定,则git会查看已签出分支的父级,等效于enter master

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

有趣的例子和结果

使用此起点:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    将申请提交BCXYZ提交D并最终跳过B并且C因为已经被应用于它们。

  • git rebase --onto C X feature
    将应用提交YZ提交C,有效删除提交X


4

一个更简单的解决方案是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创建的新分支上创建新的分支引用。


3

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

$ 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".

1
同样在这里,当我使用2个最流行的答案时(即r0hitsharma和Dymitruk),几个文件有冲突
Oliver

3

由于重新定基是如此基础,因此这是Nestor Milyaev的答案的扩展。将Adam Dymitruk的答案中的jszSimon South的评论结合起来,将产生此命令,该命令可在分支上使用,无论它是从分支的commit 还是从分支分支:topicmasterAC

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>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

因此,最后一个命令是我通常使用的命令。


-2

还有另一种方法,或者您希望返回到多个提交。

这是一个返回到n提交次数的示例:

git branch topic master~n

为了这个问题,也可以这样做:

git branch topic master~1

该命令在上可以完美运行git version 2.7.4。尚未在其他任何版本上对其进行测试。


您是否误解为关于分支的问题?这实际上是一个关于变基的问题。
NetherGranite
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.