我如何将最后的 N 次提交压缩在一起?

git rebase squash git-squash

如何将我最后的 N 个提交压缩为一个提交?

相关:Git - combining multiple commits before pushing

要压缩到第一次提交,请参阅此 - stackoverflow.com/questions/1657017/…

壁球后需要强制推stackoverflow.com/questions/10298291/…

除了发布的答案之外,GUI 客户端还可以轻松做到这一点。只需单击四次,我就可以在 GitKraken 中压缩数十个提交。

i
iwasrobbed

无需 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 --squash-recent,甚至是 git commit --amend-many

@ABB:如果您的分支有“上游”集,那么您可以使用 branch@{upstream} (或仅 @{upstream} 用于当前分支;在这两种情况下,最后一部分都可以缩写为 @{u};请参阅gitrevisions)。这可能与您的“上次推送的提交”不同(例如,如果其他人推送了构建在您最近推送之上的内容,然后您获取了该内容),但似乎它可能接近您想要的。

这有点要求我push -f,否则它很可爱,谢谢。

@2rs2ts git push -f 听起来很危险。注意只压缩本地提交。永远不要触摸推送的提交!

之后我还需要使用 git push --force 以便它接受提交

J
J4cK

使用 git rebase -i <after-this-commit> 并将第二次和后续提交中的“pick”替换为“squash”或“fixup”,如 the manual 中所述。

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

<after-this-commit> 是什么意思?

<after-this-commit> 是提交 X+1,即您要压缩的最早提交的父级。

如果您已经推送了提交,则需要推送 -f 以强制将远程分支移动到新提交。不过,这会让任何在旧提交之上工作的人感到不安。

这种 rebase -i 方法与 reset --soft 的区别在于,rebase -i 允许我保留提交作者,而 reset --soft 允许我重新提交。有时我需要压缩拉取请求的提交,同时维护作者信息。有时我需要在自己的提交上重置软。无论如何都对这两个很好的答案表示赞成。

Use git rebase -i <after-this-commit> and replace "pick" on the second and subsequent commits with "squash" or "fixup", as described in the manual. 呃呃呃呃呃呃呃?

E
ErikE

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

警告:首先确保您提交您的工作 - 检查 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

documentation for git merge 更详细地描述了 --squash 选项。

更新:与 Chris Johnsen 在 his answer 中建议的更简单的 git reset --soft HEAD~12 && git commit 相比,此方法的唯一真正优势是,您可以在提交消息中预先填充您要压缩的每条提交消息。

@Mark Amery:我说这更优雅的原因有很多。例如,它不涉及不必要地生成编辑器,然后在“待办事项”文件中搜索和替换字符串。使用 git merge --squash 也更易于在脚本中使用。本质上,原因是您根本不需要 git rebase -i 的“交互性”。

尽管我很欣赏这样的重大更改具有详细提交消息的优势,但与 Chris 相比,此方法还有一个真正的缺点:进行 hard 重置({ 1}) 涉及更多文件。例如,如果您使用 Unity3D,您会喜欢更少的文件被触摸。

另一个优点是,与变基相比,git merge --squash 在面对移动/删除/重命名时不太可能产生合并冲突,尤其是当您从本地分支合并时。 (免责声明:仅基于一次经验,如果在一般情况下这不是真的,请纠正我!)

当涉及到硬重置时,我总是非常不情愿 - 我会使用临时标签而不是 HEAD@{1} 只是为了安全起见,例如当您的工作流程因停电等而中断一个小时时。

@BT:破坏了你的承诺? :( 我不确定你的意思。你提交的任何内容都可以很容易地从 git 的 reflog 中恢复。如果你有未提交的工作,但文件是暂存的,你应该仍然能够得到他们的内容回来了,although that will be more work。但是,如果您的工作甚至没有上演,恐怕没有什么可以做的;这就是为什么答案预先说:“首先检查 git status 是否干净(因为 git reset --hard 将丢弃分阶段和非分阶段的更改)”。

B
Brent Bradburn

我建议尽可能避免使用 git reset ——尤其是对于 Git 新手。除非您真的需要基于提交的 number 次自动化流程,否则还有一种不那么奇特的方式......

将要被压缩的提交放在工作分支上(如果它们还没有的话)——为此使用 gitk 检查目标分支(例如“master”) git merge --squash (工作分支名称) git commit

提交消息将基于壁球预先填充。

这是最安全的方法:不使用重置软/硬(!!),或使用 reflog!

如果您在 (1) 上进行扩展,那就太好了。

@Adam:基本上,这意味着使用 gitk 的 GUI 界面来标记要压缩的代码行,并标记要压缩到的基础。在正常情况下,这两个标签都已经存在,因此可以跳过步骤(1)。

请注意,此方法不会将工作分支标记为完全合并,因此删除它需要强制删除。 :(

对于 (1),我发现 git branch your-feature && git reset --hard HEAD~N 是最方便的方式。但是,它确实再次涉及 git reset ,这个答案试图避免。

m
muya_

感谢 this handy blog post,我发现您可以使用此命令来压缩最后 3 次提交:

git rebase -i HEAD~3

这很方便,因为即使您在没有跟踪信息/远程仓库的本地分支上也可以使用。

该命令将打开交互式 rebase 编辑器,然后您可以按照正常方式重新排序、压缩、改写等。

使用交互式变基编辑器:

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

最近的提交 HEAD 首先显示在第 1 行。以 # 开头的行是评论/文档。

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

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

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

您还可以更改提交的顺序。这使您可以压缩或修复按时间顺序不相邻的提交。

https://i.stack.imgur.com/JYUt2.png

一个实用的日常示例

我最近提交了一个新功能。从那时起,我已经提交了两个错误修复。但是现在我在我提交的新功能中发现了一个错误(或者可能只是一个拼写错误)。多么烦人!我不希望新的提交污染我的提交历史!

我要做的第一件事是修复错误并使用注释 squash this into my new feature! 进行新的提交。

然后我运行 git loggitk 并获取新功能的提交 SHA(在本例中为 1ff9460)。

接下来,我使用 git rebase -i 1ff9460~ 调出交互式变基编辑器。提交 SHA 后的 ~ 告诉编辑器将该提交包含在编辑器中。

接下来,我将包含修复 (fe7f1e0) 的提交移动到功能提交下方,并将 pick 更改为 fixup

关闭编辑器时,修复将被压缩到功能提交中,我的提交历史看起来很干净!

当所有提交都是本地的时,这很有效,但是如果您尝试更改已推送到远程的任何提交,您真的会给签出同一分支的其他开发人员带来问题!

https://i.stack.imgur.com/vzlVd.png

你必须选择最上面的一个,然后把剩下的压扁吗?您应该编辑您的答案以更详细地解释如何使用交互式变基编辑器

是的,在第 1 行保留 pick。如果您在第 1 行的提交中选择 squashfixup,git 将显示一条消息“错误:在没有先前提交的情况下无法 'fixup'”。然后它会给你修复它的选项:“你可以用'git rebase --edit-todo'修复它,然后运行'git rebase --continue'。”或者您可以中止并重新开始:“或者您可以使用 'git rebase --abort' 中止 rebase。”。

我一直在使用这个命令。我建议添加一个名为 gr3 的别名:alias gr3='git rebase -i HEAD~3'

@Timo,正确。最旧的在顶部,最新的在底部。这就是您需要 pick 第一行的原因。当您在一行中选择 squashfixup 时,它会将更改放入上一行的提交中。

当您知道要压缩一定数量的提交或至少看到可以通过输入任意数字压缩的提交时,这感觉就像是最好的答案。一般来说,我使用这个 .

X
Xys

2020 年没有变基的简单解决方案:

git reset --soft HEAD~2 
git commit -m "new commit message"
git push -f

2 意味着最后两次提交将被压缩。您可以用任何数字替换它

不应该鼓励这种解决方案。在 push 中使用 -f (force) 选项是一种危险的做法,尤其是当您推送到共享存储库(即公共历史记录)时,这会使贡献者的生活变得困难

如果目标是将此新提交添加到 master 作为正在进行的 pr 的一部分,您可以使用 git reset --soft $(git merge-base feature master),然后使用 git commit

@FXQuantTrader:如果每个人都强制推动,情况恰恰相反。几乎总是需要使用 --force 进行推送。这样做可以使您与团队的其他成员和不同的远程位置保持一致,因为您知道发生了什么。你也知道历史的哪一部分已经稳定了。没必要隐瞒。

我认为实际上应该鼓励使用 force 推送,因为这种方法的影响非常好——强制推送与 rebase 和工作同步齐头并进,所以它更好,在我的拙见,更多的人知道这个动作的效果,而不是成为人们害怕使用的公开命令。

同意 Matheus 的观点,强制推送到特性分支很好,应该鼓励使用 rebase。无论如何,直接推送到 main 应该始终受到限制。

C
Community

基于 Chris Johnsen's answer

从 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手动修改它。 (或者,编辑别名以符合您的口味。)

有趣,但我更愿意自己键入压缩的提交消息,作为我多次提交的描述性摘要,而不是为我自动输入它。所以我宁愿指定 git squash -m "New summary." 并将 N 自动确定为未推送提交的数量。

@ABB,这听起来像是一个单独的问题。 (我不认为这正是 OP 所要求的;我从来没有觉得在我的 git squash 工作流程中需要它。)

这很甜蜜。就我个人而言,我想要一个使用来自第一个压在一起的提交的提交消息的版本。对于空格调整之类的东西会很好。

@funroll 同意。只是删除最后一次提交消息对我来说是一个非常普遍的需求。我们应该能够设计...

@ABB,您可以使用 git commit --amend 进一步更改消息,但此别名可让您对提交消息中的内容有一个良好的开端。

a
aabiro

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

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

例子:

git rebase -i HEAD~2

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

p, 选择 = 使用提交

s, squash = 使用提交,但融合到之前的提交中

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

然后继续变基:

git add .

git rebase --continue

有关重写提交历史记录的此方法和其他方法的更多信息,请参阅this helpful post

还请解释 --continue 和 vim :x 的作用。

在您使用 git add 文件中的正确配置之后,您使用 git rebase --continue 移动到下一个提交并开始合并,rebase 将在通过您的分支上的提交时以块的形式发生。 :x 是使用 vim 时保存文件更改的命令,请参阅 this

M
Mike Pennington

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

 git rebase -i HEAD~n

n(=4 here) 是最后一次提交的次数。然后你有以下选项,

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

像下面这样更新 pick 一个提交,squash 其他提交到最新的,

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

详情请点击Link

有关 git rebase -interactive here 上的 SO 的更多详细信息

M
Matthias M

如果您使用 TortoiseGit,您可以使用函数 Combine to one commit

打开 TortoiseGit 上下文菜单 选择显示日志 在日志视图中标记相关提交 从上下文菜单中选择合并到一个提交

https://i.stack.imgur.com/IPL9i.png

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

据我所知,这不适用于合并提交。

虽然它没有被任何其他人评论,但这甚至适用于不在 HEAD 的提交。例如,我需要在推送之前用更合理的描述来压缩我所做的一些 WIP 提交。工作得很漂亮。当然,我还是希望能通过命令来学习。

这太棒了!只需单击几下鼠标即可完成所有操作,我可以在归档之前合并 200 个旧仓库的提交!谢谢。使分支树干净并立即轻松查看代码更改非常有用。

t
trudolf

根据 this article,我发现这种方法更适合我的用例。

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

在推动更改之前,我想将这些提交压缩为一个。我更喜欢将分支重置为 'origin/dev' 的状态(这将使 96 次提交的所有更改都未暂存),然后立即提交更改:

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

正是我需要的。从我的功能分支中压缩提交,然后我 git cherry 选择该提交到我的 master 中。

这不会压缩以前的提交!

你能详细说明一下@igorGanapolsky 吗?

@trudolf这并不是真正的挤压(挑选个人提交挤压)。这更像是一次提交所有更改。

是的,因此它将您的所有提交压缩为一个。恭喜!

a
ana

这是执行后的另一个直观示例:git rebase -i HEAD~3

https://i.stack.imgur.com/rybJi.gif

来源:https://www.git-tower.com/learn/git/faq/git-squash/

M
Martin Thoma

Anomies answer 很好,但我对此感到不安全,所以我决定添加几个屏幕截图。

步骤 0:git 日志

使用 git log 查看您的位置。最重要的是,找到您想要压缩的第一个提交的提交哈希。所以只有:

https://i.stack.imgur.com/LOn7X.png

第一步:git rebase

执行 git rebase -i [your hash],在我的例子中:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

第2步:挑选/挤压你想要的东西

就我而言,我想在第一次提交时压缩所有内容。顺序是从头到尾,因此与 git log 中的顺序完全相反。就我而言,我想要:

https://i.stack.imgur.com/Bjgxk.png

第 3 步:调整消息

如果您只选择了一个提交并压缩了其余的提交,您可以调整一个提交消息:

https://i.stack.imgur.com/75aIZ.png

而已。保存此 (:wq) 后,您就完成了。用 git log 查看它。

很高兴看到最终结果,例如 git log

@Axalix 您是否删除了所有行?这就是你失去提交的方式。

W
Wolfson

我认为最简单的方法是基于 master 创建一个新分支并执行merge --squash 功能分支。

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

然后你就可以提交所有的更改了。

这是实现类似最终结果的不错选择。我开始寻找如何使用 rebase 来实现它,但我选择了这种方式更好。我一直忘记 git merge 的存在

我试图做其他解决方案,但由于 w/e 原因,它们不起作用。这个做到了。

谢谢你,兄弟!它帮助了我。我已经迫不及待想要解决任何问题了...

这就像魅力一样。但我认为有一个假设,你需要确保 feature_branch 在 master 分支后面有 0 。

将操作拆分为暂存分支的好技术!然后可以更轻松地区分干净的分支。

r
rashok

程序 1

1)识别提交短哈希

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

这里甚至 git log --oneline 也可以用来获取短哈希。

2)如果你想压缩(合并)最后两个提交

# git rebase -i deab3412 

3) 这将打开一个用于合并的 nano 编辑器。它看起来像下面

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4) 将单词 pick 重命名为 abcd1234 之前的 squash。重命名后应该如下所示。

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5) 现在保存并关闭 nano 编辑器。按 ctrl + o 并按 Enter 保存。然后按 ctrl + x 退出编辑器。

6) 然后 nano 编辑器再次打开以更新评论,如有必要进行更新。

7)现在它已经成功压扁了,你可以通过查看日志来验证它。

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8)现在推送回购。注意在分支名称前添加 + 符号。这意味着强制推动。

# git push origin +master

注意:这是基于在 ubuntu shell 上使用 git。如果您使用不同的操作系统(WindowsMac),那么除了编辑器之外,上述命令是相同的。你可能会得到不同的编辑器。

程序 2

首先添加提交所需的文件

git add <files>

然后使用 --fixup 选项提交,OLDCOMMIT 应该是我们需要合并(挤压)这个提交的地方。

git commit --fixup=OLDCOMMIT

现在这会在 HEAD 之上使用 fixup1 <OLDCOMMIT_MSG> 创建一个新提交。

然后执行以下命令将新提交合并(压缩)到 OLDCOMMIT。

git rebase --interactive --autosquash OLDCOMMIT^

这里的 ^ 表示之前对 OLDCOMMIT 的提交。此 rebase 命令在编辑器(vim 或 nano)上打开交互式窗口,我们无需执行任何操作,只需保存并退出即可。因为传递给 this 的选项会自动将最新提交移动到旧提交旁边,并将操作更改为 fixup(相当于 squash)。然后 rebase 继续并完成。

程序 3

如果需要向最后一次提交添加新的更改意味着 --amend 可以与 git-commit 一起使用。

    # git log --pretty=oneline --abbrev-commit
    cdababcd Fix issue B
    deab3412 Fix issue A
    ....
    # git add <files> # New changes
    # git commit --amend
    # git log --pretty=oneline --abbrev-commit
    1d4ab2e1 Fix issue B
    deab3412 Fix issue A
    ....  

此处 --amend 将新更改合并到上次提交 cdababcd 并生成新的提交 ID 1d4ab2e1

结论

第一个过程的优点是压缩多个提交并重新排序。但是如果我们需要将修复合并到非常旧的提交中,这个过程将会很困难。

因此,第二个过程有助于轻松地将提交合并到非常旧的提交。

第三个过程在将新更改压缩到上次提交的情况下很有用。

即使我将提交 ID 重置为最后一次提交的第 6 次,它也只会更新最后两次提交,不知道为什么

甚至您也可以重新排列提交顺序。它工作正常。

M
Machavity

如果您在从 Golden Repository (golden_repo_name) 克隆的远程分支(称为 feature-branch)上,那么这里是将您的提交压缩为一个的技术:

签出黄金仓库 git checkout golden_repo_name 从它(黄金仓库)创建一个新分支,如下所示 git checkout -b dev-branch 与您已经拥有的本地分支合并 git merge --squash feature-branch 提交您的更改(这将成为 dev-branch 中唯一的提交) git commit -m "My feature complete" 将分支推送到本地存储库 git push origin dev-branch

因为我只是压缩了大约 100 个提交(用于通过 git-svn 同步 svn 分支),这比交互式变基快得多!

往下读,我看到@Chris 的评论,这就是我过去常做的事情(rebase --soft...)——太糟糕了,stackoverflow 不再将数百个赞成票放在首位......

同意你@sage,希望他们将来某个时候会这样做

这是正确的方法。变基方法很好,但只能用于壁球作为最后的解决方案。

我正在更新所有内容

I
Ivan Kaloyanov

例如,如果您想将最后 3 个提交压缩为分支(远程存储库)中的单个提交,例如:https://bitbucket.org

我所做的是

git reset --soft HEAD~3 git commit git push origin --force

请小心,因为如果您使用 force 则无法检索先前的提交,因为您已将其删除

对我来说,这是一个不错且快速的解决方案。

武力是破坏性的。这不是压缩提交,而是删除最后三个提交并将它们作为第四个(现在是新的)提交添加回来,本质上是重写历史,这可能会破坏其他用户的存储库,直到他们也强制拉取。这也将删除您的团队同时推送的任何其他提交。

A
Ayan

要将最后 10 次提交压缩为 1 次提交:

git reset --soft HEAD~10 && git commit -m "squashed commit"

如果您还想使用压缩提交更新远程分支:

git push -f

--force 当多人在共享分支上工作时很危险,因为它会盲目地使用本地副本远程更新。 --force-with-lease 可能会更好,因为它可以确保远程自您上次获取它以来没有其他人的提交。

P
Pang

真正方便的是:
找到要压缩的提交哈希,例如 d43e15

现在使用

git reset d43e15
git commit -am 'new commit name'

这个。为什么没有更多的人使用它?这比 rebase 和 squashing 单个提交要快得多。

J
Josep Alsina

许多答案都基于 git rebase 命令,但根据我的经验,它对于 git 初学者来说有些复杂和先进。

假设您要压缩最后 3 次提交。然后是以下步骤:

记下当前提交 ID:使用 git log -1 --oneline 并记下当前状态的提交 ID(以防万一你在 git reset 上做错了)

返回 3 次提交:使用 git reset --soft HEAD~3 您将返回 3 次提交(并且有点忘记您之前已经进行了这三个提交)

做一个新的提交:现在只需做 git commit -m 这将自动结合你的消息下的三个提交

如果 git reset 出现问题,您可以通过 git reset --soft <ORIGINAL_COMMIT> 再次返回原始状态

在第 2 步中使用“--soft”很重要,否则您只会恢复到三个提交前的状态。我认为应该强调。

同样重要的是,当您想要推送压扁的提交时,您将需要 --force

S
Saurav Sahu

有没有人提到在 IntelliJ IDEA UI 上做起来很容易:

转到 git 窗口

手动选择要合并为一个的所有提交。

右键单击 > Squash Commits > Edit the squashed commit message

单击左侧的分支名称>右键单击>推送>强制推送

https://i.stack.imgur.com/gVjRD.png

s
slisnychyi

简单的解决方案:

git reset --soft HEAD~5

git commit -m "commit message"

git push origin branch --force-with-lease

不错的尝试,但是这里提到了一个更好的方法,使用 rebase

感谢您的回答。我尝试了很多次变基,但只有你的工作。

W
William Denniss

如果您想将每个提交压缩为单个提交(例如,当第一次公开发布项目时),请尝试:

git checkout --orphan <new-branch>
git commit
C
Community

这是超级笨拙的,但以一种很酷的方式,所以我会把它扔进戒指:

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

翻译:为 git 提供一个新的“编辑器”,如果要编辑的文件名是 git-rebase-todo(交互式 rebase 提示),则将除第一个“pick”之外的所有内容都更改为“squash”,否则会生成 vim - 这样当你'被提示编辑压缩的提交消息,你得到 vim. (显然我正在压缩分支 foo 上的最后五个提交,但你可以随意更改它。)

不过,我可能会做Mark Longair suggested

+1:这很有趣且有启发性,因为对我来说,您可以在 GIT_EDITOR 环境变量中放置比程序名称更复杂的任何内容,这一点都不明显。

您可以使用 gawk 简化此操作。 git -c core.editor="gawk -i inplace '{if(NR>1 && \$1==\"pick\"){\$1=\"squash\"} print \$0}'" rebase -i --autosquash HEAD~5

我更喜欢这个带有 GIT_SEQUENCE_EDITOR 的命令,因为我需要 autostash

C
ColinM

简单的单线始终有效,假设您当前位于要压缩的分支上,master 是它源自的分支,并且最新提交包含您希望使用的提交消息和作者:

git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}

我对压缩提交以及它多么愚蠢的复杂感到非常沮丧 - 只需使用最后一条消息并将它们全部压缩到一个提交!为什么这么难????这一个班轮为我做的。从我愤怒的心底感谢你。

W
William Entriken

⚠️ 警告:“我的最后 X 次提交”可能不明确。

  (MASTER)  
Fleetwood Mac            Fritz
      ║                    ║
  Add Danny  Lindsey     Stevie       
    Kirwan  Buckingham    Nicks                                              
      ║         ╚═══╦══════╝     
Add Christine       ║          
   Perfect      Buckingham
      ║           Nicks            
    LA1974══════════╝                                    
      ║                  
      ║                  
    Bill <══════ YOU ARE EDITING HERE
  Clinton        (CHECKED OUT, CURRENT WORKING DIRECTORY)              

https://github.com/fleetwood-mac/band-history 存储库的这个非常简短的历史记录中,您打开了一个拉取请求,以将 Bill Clinton 提交合并到原始 (MASTER) Fleetwood Mac 提交中。

你打开了一个拉取请求,在 GitHub 上你会看到:

四个提交:

添加丹尼·柯万

添加克里斯汀完美

LA1974

比尔·克林顿

认为没有人会关心阅读完整的存储库历史记录。 (实际上有一个存储库,单击上面的链接!)您决定压缩这些提交。所以你去运行 git reset --soft HEAD~4 && git commit。然后您将其git push --force 放到 GitHub 上以清理您的 PR。

会发生什么?您刚刚做出了从 Fritz 到 Bill Clinton 的一次提交。因为你忘记了昨天你正在研究这个项目的白金汉尼克斯版本。 git log 与您在 GitHub 上看到的不匹配。

🐻 故事的寓意

找到您想要访问的确切文件,然后 git checkout 它们找到您想要保留在历史记录中的确切先前提交,然后 git reset --soft 进行直接从 from 到 to 扭曲的 git 提交

这是 100% 最简单的方法。如果您当前的 HEAD 是您想要的正确状态,那么您可以跳过 #1。

这是我知道的唯一允许重写第一个提交历史的方法。

Z
Zsolt Z.

如果您不关心中间提交的提交消息,您可以使用

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
a
arush436

如果您正在使用 GitLab,您只需单击合并请求中的 Squash 选项,如下所示。提交消息将是合并请求的标题。

https://i.stack.imgur.com/iqlxy.jpg

使用 GitLab Enterprise Edition 12.8.6-ee 时,它只是随机获取了压缩提交的提交消息......

S
Sam

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

git rebase -i HEAD~X

将显示以下内容:

pick 1bffc15c My earlier commit
pick 474bf0c2 My recent commit

# ...

对于您要压缩的提交,将 pick 替换为 fixup,因此它变为:

pick 1bffc15c My earlier commit
fixup 474bf0c2 My recent commit

# ...

如果它在 vim 中打开(终端中的默认界面),然后按键盘上的 Esc,输入 :wqEnter 以保存文件。

验证:检查 git log

Y
Yoaz Menda
git rebase -i HEAD^^

其中 ^ 的数量是 X

(在这种情况下,压缩最后两个提交)