使用 Git 将我的最后一个 X 提交一起压缩

如何使用 Git 将最后的 X 个提交一起压缩为一个提交?

答案

您可以很容易地做到这一点,而无需git rebasegit merge --squash 。在此示例中,我们将压缩最后 3 次提交。

如果您想从头开始编写新的提交消息,则满足以下条件:

git reset --soft HEAD~3 &&
git commit

如果要开始使用现有提交消息的串联来编辑新的提交消息(即类似于 pick / squash / squash /…/ squash git rebase -i指令列表的开头),则需要提取这些消息并将它们传递给git commit

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

这两种方法都以相同的方式将最后三个提交压缩为单个新提交。软重置只是将 HEAD 重新指向您不想挤压的最后一次提交。软复位既不会触及索引也不会影响工作树,从而使索引处于您的新提交所需的状态(即,它已经具有您要 “丢弃” 的提交中的所有更改)。

使用git rebase -i <after-this-commit>并在第二次及以后的提交中将 “pick” 替换为 “squash” 或 “fixup”,如手册所述

在此示例中, <after-this-commit>是 SHA1 哈希,或者是当前分支的 HEAD 的相对位置,从该分支分析提交的 rebase 命令。例如,如果用户过去希望查看当前 HEAD 的 5 个提交,则命令为git rebase -i HEAD~5

您可以为此使用git merge --squash ,它比git rebase -i稍微好一点。假设您在 master 上,并且想要将最后 12 次提交压缩为 1 次。

警告:首先请确保您已完成工作 - 检查git status是否干净(因为git reset --hard将丢弃暂存和未暂存的更改)

然后:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

git merge文档更详细地介绍了--squash选项。


更新:此方法相对于 Chris Johnsen 在其答案中建议的更简单的git reset --soft HEAD~12 && git commit的唯一真正优势是,您得到的提交消息中都包含您要压缩的每个提交消息。

我建议尽可能避免git reset特别是对于 Git-novices。除非您真的需要基于多个提交使流程自动化,否则会有一种不太常见的方式...

  1. 将要压缩的提交放在工作分支上(如果尚未提交)- 为此使用 gitk
  2. 签出目标分支(例如 “master”)
  3. git merge --squash (working branch name)
  4. git commit

提交消息将根据壁球预先填充。

根据克里斯 · 约翰森的回答

从 bash 添加全局 “squash” 别名:(或 Windows 上的 Git Bash)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'

... 或使用 Windows 的命令提示符:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


您的~/.gitconfig现在应包含以下别名:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


用法:

git squash N

... 会自动将最后N提交(包括首尾)压缩在一起。

注意:结果提交消息按顺序是所有压缩的提交的组合。如果您对此不满意,可以随时git commit --amend手动修改它。 (或者,编辑别名以符合您的口味。)

感谢这篇方便的博客文章,我发现您可以使用此命令来压缩最近的 3 次提交:

git rebase -i HEAD~3

这很方便,因为即使您在没有跟踪信息 / 远程回购的本地分支机构中也可以使用。

该命令将打开交互式 rebase 编辑器,该编辑器随后将允许您按常规重新排序,压缩,重新编写单词等。


使用交互式基础编辑器:

交互式基础编辑器显示最后三个提交。当运行命令git rebase -i HEAD~3时,此约束由HEAD~3确定。

最新提交HEAD最初显示在第 1 行。以#开头的行是注释 / 文档。

显示的文档非常清晰。在任何给定的行上,您都可以将命令从pick更改为您选择的命令。

我更喜欢使用命令fixup因为这可以将提交的更改 “压榨” 到上一行的提交中,并丢弃提交的消息。

由于第 1 行的提交为HEAD ,在大多数情况下,您将其保留为pick 。您不能使用squashfixup因为没有其他提交可以将提交压缩到其中。

交互式基础编辑器

如果使用 TortoiseGit,则可以将功能Combine to one commit

  1. 打开 TortoiseGit 上下文菜单
  2. 选择Show Log
  3. 在日志视图中标记相关的提交
  4. 从上下文菜单中选择 “ Combine to one commit

合并提交

此功能自动执行所有必要的单个 git 步骤。不幸的是,仅适用于 Windows。

根据本文,我发现此方法对我的用例更容易。

我的'dev' 分支比'origin / dev' 提前了 96 次提交(因此这些提交尚未推送到远程)。

我想将这些提交压缩为一,然后再进行更改。我更喜欢将分支重置为 “origin / dev” 状态(这将取消暂存 96 次提交中的所有更改),然后立即提交更改:

git reset origin/dev
git add --all
git commit -m 'my commit message'

在分支中,您想合并提交,运行:

git rebase -i HEAD~(n number of commits back to review)

例:

git rebase -i HEAD~1

这将打开文本编辑器,并且如果您希望将这些提交合并在一起,则必须在每个提交前面将 “pick” 切换为 “squash”。从文档:

p,选择 = 使用提交

s,squash = 使用提交,但可以合并到先前的提交中

例如,如果您希望将所有提交合并为一个,则 “pick” 是您进行的第一个提交,所有将来的提交(放置在第一个之后)应设置为 “squash”。如果使用 vim,请在插入模式下使用:x保存并退出编辑器。

然后继续进行变基:

git rebase --continue

有关此方法以及重写提交历史记录的其他方法的更多信息,请参见此有用的帖子

为此,您可以使用以下 git 命令。

git rebase -i HEAD~n

n(此处为 4)是最后提交的次数。然后您有以下选择,

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....

像下面这样更新

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....

有关详细信息,请单击链接

祝好运!!