Squashing Merged提交Rebase

问题描述 投票:0回答:1

我在这个分支和屏幕上有一个分支功能/安装新功能,并有11个提交。但所有提交都已合并提交。打算做这些提交。

我有一个日志历史记录中的合并提交列表,需要压缩到一个提交。

commit ac174b8dc1dc44e91b56c89c55003942070b9742
Merge: e9048249 e24218ee
Author: sanjay <[email protected]>
Date:   Sun Dec 10 04:48:39 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit e904824938f2e8517d3ad5a45a11ae4595157cf7
Merge: 41e1d616 a3128511
Author: sanjay <[email protected]>
Date:   Fri Dec 8 12:07:53 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit e24218eeb60bcbfa92559cf174d3de40b93a6dbe
Merge: 41e1d616 a3128511
Author: sanjay <[email protected]>
Date:   Fri Dec 8 12:07:53 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit 41e1d61609ea6d3c99d52efb3fb472a18924b2f1
Merge: ddc36e3b bdf8a179
Author: sanjay <[email protected]>
Date:   Fri Dec 8 09:14:59 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit bdf8a17968543fccc3b02ffc59c2117448f586ff
Merge: d9fe3abd 7b630927
Author: sanjay <[email protected]>
Date:   Tue Dec 12 14:53:19 2017 +0530

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit d9fe3abd0062475cfdff911ce58a967076d5aa08
Merge: 27ee100a 63113ae4
Author: sanjay <[email protected]>
Date:   Tue Dec 12 14:52:34 2017 +0530

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit a3128511b3fd3746d4191794e7dcda52232e9458
Merge: ddc36e3b bdf8a179
Author: sanjay <[email protected]>
Date:   Fri Dec 8 09:14:59 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit ddc36e3be2dd55b1ba880c307c8be0237ca52bce
Merge: d9fe3abd 7b630927
Author: sanjay <[email protected]>
Date:   Tue Dec 12 14:53:19 2017 +0530

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit 7b630927be19a773414938a43702fe9cd0e7f854
Merge: 27ee100a 63113ae4
Author: sanjay <[email protected]>
Date:   Fri Dec 8 01:52:01 2017 +0000

    Merge branch 'feature/Install New feature on this branch and screens' of https://github.com/service/dosomething.git into feature/Install New feature on this branch and screens

commit 27ee100ad29e8db7fb10ddc04824ccdc8a53d091
Author: sanjay <[email protected]>
Date:   Fri Dec 1 06:25:13 2017 +0000

    Install New feature on this branch and screens

commit 63113ae404be96f113e1c9eb4f79d0de9fc4a90e
Author: sanjay <[email protected]>
Date:   Fri Dec 1 06:25:13 2017 +0000

    Install New feature on this branch

但我做了一个git rebase -i branchname它显示这样的输出。我无法将其压缩成提交。输出是这样的

noop

# Rebase ac174b8..ac174b8 onto ac174b8 (1 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

如何使用上述提交来处理壁球。

git rebase git-squash
1个回答
0
投票

TL;DR answer

你无法通过git rebase达到你想要的效果。你可以通过git merge --squash达到你想要的效果,但除非你知道自己在做什么,否则一般不应该使用git merge --squash。 (也就是说,这可能是解决整体问题的错误方法。)

根据经验,在为某些提交运行git merge --squash之后,您应该删除包含这些提交的分支,因为它们不再适合开发。 (可能存在特定的例外情况。)在这种情况下,这意味着删除已合并的每个分支。

Things to know about rebase

作为evolutionxbox said in a comment,当你运行你的git rebase -i branchname命令时,你选择了根本不复制提交,将副本放在当前提交ac174b8dc1dc44e91b56c89c55003942070b9742之后。

这可能是一件好事,因为当你选择一些提交要复制,将副本放在其他一些指定的提交之后,Git将复制的提交将省略所有的合并提交。这是因为复制合并提交既不可能,也常常是非生产性的。由于上面列表中的11个提交中有9个是合并,因此无法复制它们。

重要的是要记住git rebase所做的是复制提交,就好像通过使用git cherry-pick命令一样。通常,您将拥有一个Git存储库,其中包含一些提交,您可以并且应该绘制图片 - 这些提交的图形,或者至少是参与rebase的那些提交:

       E--F--G   <-- new-desired-base
      /
...--*
      \
       A--B--C--D   <-- four-commits

这里,只能从名称four-commits访问的四个提交中的每一个都是普通(非合并)提交。提交D的父级是提交C; C的父母是B; B的父母是A;和A的父母是我用星号*标记的提交。

如果你现在运行git checkout four-commits && git rebase new-desired-base,Git将从four-commits指向的提交(即D)开始,选择从new-desired-base指向的提交开始无法访问的提交,即G。从G可以得到的提交是GFE*,以及在提交*之前的每次提交。所以从列表D, C, B, A, *, ...中减去该列表会留下D, C, B, A

Git现在将切换到G确定的提交new-desired-base,并以相反的顺序复制四个提交中的每一个,即A的祖先D曾祖父母,然后是祖父母B,然后是父亲C,最后D本身。每个副本都像git cherry-pick一样完成。如果一切顺利,结果如下:

       E--F--G   <-- new-desired-base
      /       \
...--*         A'-B'-C'-D'
      \
       A--B--C--D   <-- four-commits

其中'(prime)标记表示哪个提交被复制到具有新哈希ID的新提交。

最后,如果一切顺利,Git将从原始链中取出four-commits的名称,并将其粘贴到新链的末尾,在此过程中重新连接HEAD

       E--F--G   <-- new-desired-base
      /       \
...--*         A'-B'-C'-D'   <-- four-commits (HEAD)
      \
       A--B--C--D   [abandoned]

现在没有原始提交D的名称,它似乎完全消失。这需要整个链条,所以A-B-C-D似乎已被A'-B'-C'-D'取代:

       E--F--G   <-- new-desired-base
      /       \
...--*         A'-B'-C'-D'   <-- four-commits (HEAD)

原始提交链仍然在您的存储库中,如果您已将其保存在某处(并且通过一些特殊的隐藏名称,以防您未保存它),通过其哈希ID可检索,通常至少30天以上,如果你改变了对rebase的看法。

请注意,如果其他人在其存储库中具有这些提交 - 即,具有这些哈希ID并且具有他们自己的名称 - 那些提交将永远保留在其存储库中。您必须让他们删除这些提交的名称,然后这些提交最终将远离他们的存储库。


1An交互式rebase确实在每个要复制的提交上运行git cherry-pick。其他一些形式的rebase没有,但效果通常是相同的。


What to consider before proceeding

由于这就是rebase如何工作,所以记住它是个好主意。更重要的是要记住它不会复制合并提交,所以如果你要求它复制你的提交链,它将省略合并。但是,一般来说,要求Git重新定义包含合并的内容是个坏主意,因为选择要复制的提交往往包括要合并的提交。

请考虑以下简化图:

...--A--B----F   <-- master
      \  \
       \  D   <-- feature-B
        \
         C--E   <-- feature-A

请记住,如果他们是更为祖先(父母或祖父母),则提交在左侧,如果他们不是祖先(儿童),则提交到右侧。所以master增加了一个提交,即F,因为feature-B分支。它有两个提交,即BF,因为feature-A分支。同时feature-A包含两个提交,CE,不在master,而feature-B包含一个提交,D,不在master

如果您的目标是在master上进行一次同时包含两个功能的新提交,则可以选择首先合并两个功能分支。您可以使用以下任一方法执

git checkout feature-A && git merge feature-B

要么:

git checkout feature-B && git merge feature-A

合并的结果,如果成功,将是一个新的提交G。这个新提交将基于(如合并基础)commit A

  • Git会将提交A的快照内容与D中的快照内容进行比较。实际上,这是自提交A以来在feature-B中发生的事情。请注意,这包括在B中发生的事情,这是一个可以从master的尖端访问的提交(通过查看D的父级)。
  • Git将分别将提交A的快照内容与E中的快照内容进行比较。实际上,这是自提交A以来在feature-A中发生的事情。比较AE包括在C发生的任何事情,因为E中的快照包括发生在C的任何事情(好吧,减去任何回到A的反转)。

既然Git有两组更改,Git会将它们组合起来,并将更大的更改应用于提交A中的快照。这为它提供了生成新的快照/提交G所需的内容:

...--A--B----F   <-- master
      \  \
       \  D---G
        \    /
         C--E

如果你用git checkout feature-B && git merge feature-A这样做,新的提交G被添加到feature-B分支:

...--A--B----F   <-- master
      \  \
       \  D---G   <-- feature-B (HEAD)
        \    /
         C--E   <-- feature-A

如果你使用git checkout feature-A && git merge feature-B执行此操作,则会将新的提交G添加到feature-A分支中,因此我们可能会更像这样:

...--A--B----F   <-- master
      \  \
       \  D   <-- feature-B
        \  `--_
         C--E--G   <-- feature-A

无论哪种方式,G是一个合并提交,因此不能重新设置,不像提交DC--E

Using git merge --squash

但是,现在可以运行:

git checkout master && git merge --squash <something>

这里的<something>是产生新提交G的哈希ID的任何东西。您可以输入原始哈希ID;或者,如果您进行了合并以便将G提交到feature-B,则可以使用名称feature-B

git checkout master步骤将HEAD附加到master,当然检查master的提示,即提交F。所以假设Gfeature-B上,这看起来像:

...--A--B----F   <-- master (HEAD)
      \  \
       \  D---G   <-- feature-B
        \    /
         C--E   <-- feature-A

git merge --squash步骤执行git merge的动词部分,即git merge将要做的工作:它像以前一样找到合并基础,然后运行两个git diff --find-renames命令,就像之前一样。

提交FG的合并基础是承诺B。这是因为粗略地说,合并基础是从两个分支提示可以到达的第一个提交。从F,我们退一步到B。从G,我们退回一次到D和一次E,然后第二次从DEBC。我们现在已达成共同点 - 提交B - 所以B是合并基础。

所以,和以前一样,Git运行git diff --find-renames B Fgit diff --find-renames B G,看看两个分支发生了什么。然后Git将这些变化组合在一起,将它们应用于快照B的内容,并准备新的快照H

在这里,git merge --squash以两种方式离开常规的git merge

  1. 它会跳过提交,就像您添加了--no-commit选项一样,或者好像存在合并冲突一样。
  2. 当您自己手动进行提交时,它只会在新提交中记录一个父哈希ID。

所以当你现在运行git commit时,你得到:

...--A--B----F--H   <-- master (HEAD)
      \  \
       \  D---G   <-- feature-B
        \    /
         C--E   <-- feature-A

commit H的内容,即快照,与您定期合并的内容相同;但定期合并会将结果记录为:

...--A--B----F--H   <-- master (HEAD)
      \  \     /
       \  D---G   <-- feature-B
        \    /
         C--E   <-- feature-A

由于壁球合并没有记录额外的父母,Git后来不知道H已经拥有G的所有工作。 (通过真正的合并,Git会知道,因为合并基础将提交G。)

这对于进行南瓜合并的人来说意味着它现在对feature-Afeature-B进行任何进一步开发都会适得其反,因为由于缺少父链接,它们将更难以合并到master中。因此,在这一点上删除名称feature-Afeature-B可能是合适的:

...--A--B----F--H   <-- master (HEAD)
      \  \
       \  D---G   [abandoned]
        \    /
         C--E   [abandoned]

与篮板相比,额外的提交C--ED--G将会在短时间内(也许比rebase更短),甚至一旦名字消失,但最终它们会消失。但请记住,如果其他人拥有这些原始提交的名称,并保存在其他存储库中,那些提交 - 以及这些名称 - 将永远保留在他们的存储库中,除非您说服他们删除它们。如果他们将自己的工作建立在这些提交的基础上,他们可能会遇到麻烦,后来将他们的工作与你压扁的提交H结合起来。

© www.soinside.com 2019 - 2024. All rights reserved.