如何使用 git rebase 压缩围绕合并的提交?
How to use git rebase to squash commits around a merge?
围绕与 git 的合并变基的最简单方法是什么?
在我的一个分支中,我一直在推测地玩弄一堆不同的东西,有大量失败和部分失败的尝试。现在我已经可以正常工作了,我想回去压缩一堆猜测和检查提交,使用交互式变基。
复杂的是,在这个过程中,我合并了另一个分支。我想按原样保留该合并分支(不重写任何提交),并将合并提交保留在我分支中的相同相对位置。 (因为我的分支中的功能有一些 before/after 依赖性。)我尝试直接 git rebase -i
,但我合并的分支从我上次分歧的点开始有相当多的提交,当它们出现在交互式 rebase 文件中时,它们使事情变得复杂。
图表可能会有所帮助。我现在拥有的:
#-#-#-#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
我想要的:
#-#-#-#-----*-------*-*----*------* My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
(“#”是我想保持不变的提交,SHA1 方面,两个合并提交的文件系统内容应该相同。)
我还没有推送任何我想变基到远程服务器的提交。 (虽然我合并的分支在远程服务器上是。)
您可以采用手动方法,只需在从 MyBranch 到 TheMergedBranch 的第一个分支提交之间对 MyBranch 进行交互式变基,以压缩您的内容。然后在 TheMergedBranch 中合并。然后使用上游和提交从原始 MyBranch 中选择的上游和提交来进行交互式变基 - 到您的新分支。
是正确的——记住 rebase 只是 copying 提交——但是执行起来有点棘手。您需要保存两个特定的提交 ID,甚至可能使用另一个分支名称。
我实际上会用一个新的分支名称和 git cherry-pick
以及一个新的 git merge
,我自己来做到这一点。这是方法,使用您的图表,稍微注释,以及一些实际的 Git 命令。你有:
A-#-#-B-*-*-*-*-*-*-C-M-D-*-*-*-*-*-*-E My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
你想要:
A-#-#-B-----*-------*-m----*------* My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
您可以从:
开始
git checkout -b rebased B
这会让你得到一个指向提交 B
的新分支名称。现在您可以:
git cherry-pick -n B..C
(或使用原始 ID)复制 B
之后的所有 *
提交,包括 C
,然后 git rebase -i B
并挤压一些以获得你的两个*
提交。
现在您可以合并了;所以 git merge M^2
与来自 The merged branch
的提交 M
的第二个父级合并。如果失败(或者如果你想修改它,添加 --no-commit
现在你在它停止的地方),你可以通过直接从提交 M
检查文件来修复合并,假设你想要相同的合并你在那里的分辨率。
(如果您启用了 git rerere
,此时大部分情况会自动发生。)
提交或合并完成后,您将获得新合并提交的 ID m
。
现在您已准备好从 D
到 E
之间挑选提交,所以:
git cherry-pick D^..E
(我们在这里需要 D^
来包含 D
— 或者您可以使用提交 M
的原始 SHA-1 ID,原始合并)。然后 git rebase -i m
仅对 D
-through-E
的新副本进行变基,而不备份新合并 m
.
当你全部完成后,你就有了你想要的图表。分支的名称是 rebased
而不是 My branch
,1,并且您有分支 My branch
指向提交 E
。所以 git checkout My branch
然后 git reset --hard rebased
将旧名称指向新的 branch-tip-commit,之后你可以删除名称 rebased
.
1显然这不是实际名称,因为在分支名称中有 space 是不好的。
不要为此使用变基,使用移植物。请记住,提交是 full-content 个快照,您想要的结果是 content-identical 与现有提交的提交,您只想重新连接亲子关系。这就是移植物的用途。
首先,在沙盒存储库中执行此操作,这样如果您不喜欢正在发生的事情,就可以放弃并擦除它:
git clone -s . "${other=`mktemp -dt`}"
cd "$other"
设置你想要的亲子关系
echo > .git/info/grafts $(git rev-parse M B M^2)
echo >>.git/info/grafts $(git rev-parse E M)
(我想你还有一两个你想要的提交,只需列出你真正想要 parents 的提交来代替你已经拥有的提交,git的复习行走将跟随你的脚步)
然后
git filter-branch -- --all
如果您喜欢结果,请将它们推回去。
围绕与 git 的合并变基的最简单方法是什么?
在我的一个分支中,我一直在推测地玩弄一堆不同的东西,有大量失败和部分失败的尝试。现在我已经可以正常工作了,我想回去压缩一堆猜测和检查提交,使用交互式变基。
复杂的是,在这个过程中,我合并了另一个分支。我想按原样保留该合并分支(不重写任何提交),并将合并提交保留在我分支中的相同相对位置。 (因为我的分支中的功能有一些 before/after 依赖性。)我尝试直接 git rebase -i
,但我合并的分支从我上次分歧的点开始有相当多的提交,当它们出现在交互式 rebase 文件中时,它们使事情变得复杂。
图表可能会有所帮助。我现在拥有的:
#-#-#-#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
我想要的:
#-#-#-#-----*-------*-*----*------* My branch
\ /
#-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
(“#”是我想保持不变的提交,SHA1 方面,两个合并提交的文件系统内容应该相同。)
我还没有推送任何我想变基到远程服务器的提交。 (虽然我合并的分支在远程服务器上是。)
您可以采用手动方法,只需在从 MyBranch 到 TheMergedBranch 的第一个分支提交之间对 MyBranch 进行交互式变基,以压缩您的内容。然后在 TheMergedBranch 中合并。然后使用上游和提交从原始 MyBranch 中选择的上游和提交来进行交互式变基 - 到您的新分支。
我实际上会用一个新的分支名称和 git cherry-pick
以及一个新的 git merge
,我自己来做到这一点。这是方法,使用您的图表,稍微注释,以及一些实际的 Git 命令。你有:
A-#-#-B-*-*-*-*-*-*-C-M-D-*-*-*-*-*-*-E My branch \ / #-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
你想要:
A-#-#-B-----*-------*-m----*------* My branch \ / #-#-#-#-#-#-#-#-#-#-#-#-# The merged branch
您可以从:
开始git checkout -b rebased B
这会让你得到一个指向提交 B
的新分支名称。现在您可以:
git cherry-pick -n B..C
(或使用原始 ID)复制 B
之后的所有 *
提交,包括 C
,然后 git rebase -i B
并挤压一些以获得你的两个*
提交。
现在您可以合并了;所以 git merge M^2
与来自 The merged branch
的提交 M
的第二个父级合并。如果失败(或者如果你想修改它,添加 --no-commit
现在你在它停止的地方),你可以通过直接从提交 M
检查文件来修复合并,假设你想要相同的合并你在那里的分辨率。
(如果您启用了 git rerere
,此时大部分情况会自动发生。)
提交或合并完成后,您将获得新合并提交的 ID m
。
现在您已准备好从 D
到 E
之间挑选提交,所以:
git cherry-pick D^..E
(我们在这里需要 D^
来包含 D
— 或者您可以使用提交 M
的原始 SHA-1 ID,原始合并)。然后 git rebase -i m
仅对 D
-through-E
的新副本进行变基,而不备份新合并 m
.
当你全部完成后,你就有了你想要的图表。分支的名称是 rebased
而不是 My branch
,1,并且您有分支 My branch
指向提交 E
。所以 git checkout My branch
然后 git reset --hard rebased
将旧名称指向新的 branch-tip-commit,之后你可以删除名称 rebased
.
1显然这不是实际名称,因为在分支名称中有 space 是不好的。
不要为此使用变基,使用移植物。请记住,提交是 full-content 个快照,您想要的结果是 content-identical 与现有提交的提交,您只想重新连接亲子关系。这就是移植物的用途。
首先,在沙盒存储库中执行此操作,这样如果您不喜欢正在发生的事情,就可以放弃并擦除它:
git clone -s . "${other=`mktemp -dt`}"
cd "$other"
设置你想要的亲子关系
echo > .git/info/grafts $(git rev-parse M B M^2)
echo >>.git/info/grafts $(git rev-parse E M)
(我想你还有一两个你想要的提交,只需列出你真正想要 parents 的提交来代替你已经拥有的提交,git的复习行走将跟随你的脚步)
然后
git filter-branch -- --all
如果您喜欢结果,请将它们推回去。