我在这个分支和屏幕上有一个分支功能/安装新功能,并有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 merge --squash
达到你想要的效果,但除非你知道自己在做什么,否则一般不应该使用git merge --squash
。 (也就是说,这可能是解决整体问题的错误方法。)
根据经验,在为某些提交运行git merge --squash
之后,您应该删除包含这些提交的分支,因为它们不再适合开发。 (可能存在特定的例外情况。)在这种情况下,这意味着删除已合并的每个分支。
作为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
可以得到的提交是G
,F
,E
,*
,以及在提交*
之前的每次提交。所以从列表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没有,但效果通常是相同的。
由于这就是rebase如何工作,所以记住它是个好主意。更重要的是要记住它不会复制合并提交,所以如果你要求它复制你的提交链,它将省略合并。但是,一般来说,要求Git重新定义包含合并的内容是个坏主意,因为选择要复制的提交往往包括要合并的提交。
请考虑以下简化图:
...--A--B----F <-- master
\ \
\ D <-- feature-B
\
C--E <-- feature-A
请记住,如果他们是更为祖先(父母或祖父母),则提交在左侧,如果他们不是祖先(儿童),则提交到右侧。所以master
增加了一个提交,即F
,因为feature-B
分支。它有两个提交,即B
和F
,因为feature-A
分支。同时feature-A
包含两个提交,C
和E
,不在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
:
A
的快照内容与D
中的快照内容进行比较。实际上,这是自提交A
以来在feature-B中发生的事情。请注意,这包括在B
中发生的事情,这是一个可以从master
的尖端访问的提交(通过查看D
的父级)。A
的快照内容与E
中的快照内容进行比较。实际上,这是自提交A
以来在feature-A中发生的事情。比较A
和E
包括在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
是一个合并提交,因此不能重新设置,不像提交D
或C--E
。
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
。所以假设G
在feature-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
命令,就像之前一样。
提交F
和G
的合并基础是承诺B
。这是因为粗略地说,合并基础是从两个分支提示可以到达的第一个提交。从F
,我们退一步到B
。从G
,我们退回一次到D
和一次E
,然后第二次从D
和E
到B
和C
。我们现在已达成共同点 - 提交B
- 所以B
是合并基础。
所以,和以前一样,Git运行git diff --find-renames B F
和git diff --find-renames B G
,看看两个分支发生了什么。然后Git将这些变化组合在一起,将它们应用于快照B
的内容,并准备新的快照H
。
在这里,git merge --squash
以两种方式离开常规的git merge
:
--no-commit
选项一样,或者好像存在合并冲突一样。所以当你现在运行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-A
或feature-B
进行任何进一步开发都会适得其反,因为由于缺少父链接,它们将更难以合并到master
中。因此,在这一点上删除名称feature-A
和feature-B
可能是合适的:
...--A--B----F--H <-- master (HEAD)
\ \
\ D---G [abandoned]
\ /
C--E [abandoned]
与篮板相比,额外的提交C--E
和D--G
将会在短时间内(也许比rebase更短),甚至一旦名字消失,但最终它们会消失。但请记住,如果其他人拥有这些原始提交的名称,并保存在其他存储库中,那些提交 - 以及这些名称 - 将永远保留在他们的存储库中,除非您说服他们删除它们。如果他们将自己的工作建立在这些提交的基础上,他们可能会遇到麻烦,后来将他们的工作与你压扁的提交H
结合起来。