9

比方说我的本地git log节目:

739b36d3a314483a2d4a14268612cd955c6af9fb a
...
c42fff47a257b72ab3fabaa0bcc2be9cd50d5c89 x
c4149ba120b30955a9285ed721b795cd2b82dd65 y
dce99bcc4b79622d2658208d2371ee490dff7d28 z

我的遥控器git log显示:

c4149ba120b30955a9285ed721b795cd2b82dd65 y
dce99bcc4b79622d2658208d2371ee490dff7d28 z

最简单的方法是什么(假设任意大量的本地提交):

527b5810cfd8f45f18ae807af1fe1e54a0312bce a ... x
c4149ba120b30955a9285ed721b795cd2b82dd65 y
dce99bcc4b79622d2658208d2371ee490dff7d28 z
4

3 回答 3

18

有时,您可能不想使用交互式变基

如果 A 到 X 之间的中间提交数量相对较少,则可以通过使用交互式变基来解决问题:

git rebase -i origin/master

但是,以我个人的经验,使用基于大量提交的交互式变基是很慢的。我一次对大约一百个提交运行了交互式 rebase(在使用 Git Bash 的 Windows 机器上),msysgit 需要很长时间才能生成交互式 rebase 提交编辑器,该编辑器允许您选择要运行的操作在哪个提交上,因为,嗯,列表最终非常大。

在这种情况下,您有几个解决方法。

替代#1:git reset

混合和软重置可用于修改您的工作树或暂存区域(分别)以聚合/收集两个提交 A 和 Y 之间的所有更改,之后您可以一次提交所有修改作为单个提交。

我将仅举一个软重置的示例,因为它已经为您准备好了所有内容,而如果您使用混合重置,则无论如何您都必须进行修改:

# You don't need to create the temp branch A if you
# copy the commit sha A down somewhere so that you can remember it.
git branch temp A

git reset --soft Y
git commit -m "Squash commits A through X"

# Verify that this new commit is equivalent to the final state at A
git diff A

备选方案#2:使用补丁

另一种选择是简单地使用补丁。只需生成 A 到 Y 之间差异的差异补丁,然后将补丁作为新提交应用到 Y 之上:

git diff y a > squash.patch
git checkout -b squash-branch y
git apply squash.patch
git commit -m "Squash commits A through X"

# Verify that this new commit is equivalent to the final state at A
git diff A

正如@ABB 在评论中指出的那样,如果涉及二进制文件,这将无法正常工作。git diff --binary除了文本文件之外,还可用于输出二进制文件的差异,但我不确定这些差异是否也可以用作补丁。

于 2014-03-04T02:48:18.183 回答
7

一种选择是git rebase -i @{u}。我经常使用它,所以我将它命名为(因为它适用于您可以自由变基git freebase的提交)。

如果您不熟悉,@{u}是 的快捷方式@{upstream},或“当前分支的上游”。

于 2014-03-04T02:47:02.547 回答
3

“最简单”总是有点棘手。交互式变基可以让你压扁一切,并且在某种程度上是“容易的”。

另一种看起来有点复杂的“简单”方法是使用“壁球合并”(这根本不是真正的合并,但确实使用与 相同的底层代码git merge,因此使用相同的命令完成)。假设您在devel上游为origin/devel. 首先,我们将重命名develdevel-full以表明它是具有完整提交序列的那个。然后我们将创建一个新的develtrackingorigin/devel和 "squash-merge" devel-full

git branch -m devel devel-full
git checkout --track origin/devel
git merge --squash devel-full
git commit

您必须单独git commit禁止--squash通常git merge进行的提交。

然而,第三种简单(?)但有点可怕的方法是查看提示版本并提交它。同样,假设devel像以前一样,我们将“完全开发”分支名称移开并创建一个新的本地分支以进行新的提交。不过,这一次git merge --squash我们之前使用了两个命令,而不是git commit

git branch -m devel devel-full
git checkout --track origin/devel
git rm -rf .                      # assumes you're in the top directory
git checkout devel-full -- .
git commit

计划(在索引/暂存区域中)要删除的git rm -rf .每个文件,然后git checkout devel-full -- .告诉 git 用devel-full. 所以这意味着“为下一次提交制作树,看起来与”尖端的树完全一样devel-full

(remove-and-re-create 方法适用于不适用的一种情况merge --squash:具体而言,它适用于用另一个分支的尖端“替换”一个分支的尖端,即使两个分支不相关因此不合并 -能。否则merge --squash会短一步,而且绝对不会看起来那么吓人,至少!)

这两种其他“简单”(?)方式都为您提供了具有完整开发历史的分支。如果你想要它,太好了!如果没有,您必须将其删除。

于 2014-03-04T03:03:18.330 回答