git - 在重新定位之前的壁球

时间:2015-02-05 22:08:55

标签: git rebase git-rebase

我有两个分支:mastertest-branch(分支为master)。我的工作看起来如下:

  1. git checkout master
  2. git checkout -b test-branch
  3. 进行一系列更改并提交
  4. 进行更多更改并执行其他提交
  5. git checkout master
  6. git pull - >其他人做出了改变大师
  7. git checkout test-branch
  8. git rebase -i master
  9. 将交互式控制台中除第一个pick之外的所有内容更改为s
  10. 我必须解决两个合并冲突,一个用于第一个提交,另一个用于第二个提交
  11. 我想做的是在变基之前压缩test-branch上的所有提交,这样我只需要解决一次合并冲突。这可能吗?如果是这样,怎么样?

2 个答案:

答案 0 :(得分:6)

有可能,甚至很容易。 Git就是这样,有很多不同的方法可以做到。

从字面上做你最初的建议:

  

...在重新定位之前压缩测试分支上的所有提交

如果你在分支git merge上运行master之前 ,那么

最简单。 (我知道您没有将git merge列为命令,但您在第6步中确实运行了git merge

  
      
  1. git pull - >其他人做出了改变大师
  2.   

因为git pull只是git fetch后跟git merge。)但它之后仍然很容易做到;我们只需要定位正确的commit-ID。

让我们绘制您在步骤4中提交的提交图:

...<- o <- *            <-- master, origin/master
             \
               A <- B   <-- HEAD=test-branch

此图显示的是有两个标签 1 指向我标记为*的提交,即masterorigin/master。提交*点返回提交o,提交回更多提交:这是分支master的历史。

您创建的分支的标签(现在已开启,因此HEAD=部分)指向提交B。提交B然后指向提交A,其指向提交*。这是分支test-branch的历史记录:您在*时创建了它,然后添加了A,然后添加了B

此时有两种方法可以轻松压缩提交AB

  1. git rebase -i master

    这为您提供了一个交互式编辑会话,您可以在其中选择&#34;第一次提交,然后&#34;壁球&#34;第二个,它将收集两个提交消息,并让您以通常的方式编辑结果。然后它进行(单个)新提交,其树是commit B

  2. git reset --soft master; git commit

    为rebase打开一个交互式编辑会话:它只是保持staging-area-and tree不会提交B({{1} ({1}})的一部分,将标签--soft移回指向直接提交git reset --softtest-branch *部分git reset部分,并像往常一样进行新的提交(git reset --soft)。

    缺点是您必须撰写新的提交消息,但您可以通过多种方式从提交git commitA恢复提交消息。例如,您可以使用B-c标记-C(您必须标识提交git commitA,例如,使用B@{1}@{1}^或其他一些reflog说明符)。或者,在执行@{yesterday}之前,您可以使用git reset --soft并将日志消息保存在文件中,或者其他任何内容。

    (第二种方法闪耀,而不是只有两次提交壁球,你有42左右。)

  3. 这两种方法都做同样的事情:他们添加提交(让我们称之为git log),留下AB和{{1我不能正确地绘制出来的灰色背景:

    A

    您的分支的幽灵版本对于大多数正常使用是不可见的,并且最终(默认情况下在30天左右之后)被垃圾收集掉。 (在此之前,它仍然在您的存储库和您的reflog中,以便您可以找到原始提交B AB <-- HEAD=test-branch / ...<- o <- * <-- master, origin/master \ A <- B [ghost version of test-branch] ,以防万一您需要它们。)

    如果您已经完成第6步怎么办?在这种情况下,您仍必须识别提交A。您在撰写本文时可以do it the way jsexpert suggested,或者您可以使用B找到它:

    *

    这是如何运作的。在git merge-base之后(步骤5和6,或多或少),您的提交图现在看起来更像是:

    $ mergebase=$(git merge-base HEAD master)
    # then pick just ONE of the next two
    $ git rebase -i $mergebase
    $ git reset --soft $mergebase; git commit
    

    git checkout master; git fetch; git merge; git checkout test-branch...<- o <- * <- o <-- master, origin/master \ A <- B <-- HEAD=test-branch 指向的新o提交 - 或者它可能是整个提交链 - 是&#34;在方式&#34;中,但是&#34;合并基地&#34; master(你现在在哪里)和origin/master是提交test-branch:两个分支分歧之前最近的共享提交。

    然后我们只是在该提交中定位master*。当我们完成并拥有一个新的rebase提交时,它看起来像这样:

    reset --soft

    一旦你被压扁AB提交,你就可以 AB <-- HEAD=test-branch / ...<- o <- * <- o <-- master, origin/master \ A <- B [ghost version of test-branch] AB方式进行提交。

    请注意,另一个答案是完全相同的事情,它只是通过计算提交来识别提交git rebase。如果你知道master的提示和&#34;有趣的&#34;之间有两个提交。 commit *test-branch标识与*相同的提交。使用HEAD~2只允许您避免计数。


    1 &#34;参考文献&#34;是实际的一般git术语。在这种情况下,他们是分支名称,我使用的是&#34;标签&#34;将它们与此提交图形成的分支历史区分开来。单词&#34; branch&#34;在git中用来指代至少这两个不同的东西,它会让人感到困惑。

答案 1 :(得分:2)

当然有可能,yoiu只需输入: git rebase -i HEAD~<# of commits to squash>

-i用于交互式rebase。一旦你这样做,你将看到vi,其中包含每次提交下一步的说明。

有关它的详细信息可以在 Rewriting history 找到: