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

mar*_*son 3294 git squash git-squash

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

Chr*_*sen 3505

没有git rebase或你可以相当容易地做到这一点git merge --squash.在这个例子中,我们将压缩最后3次提交.

如果要从头开始编写新的提交消息,这就足够了:

git reset --soft HEAD~3 &&
git commit
Run Code Online (Sandbox Code Playgroud)

如果你想用现有提交消息的串联开始编辑新的提交消息(即类似于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})"
Run Code Online (Sandbox Code Playgroud)

这两种方法都以相同的方式将最后三次提交压缩成一个新的提交.软复位只是将HEAD重新指向您不想压缩的最后一次提交.软复位不会触及索引和工作树,使索引处于新提交所需的状态(即,它已经具有您将要"扔掉"的提交的所有更改).

  • 哈!我喜欢这种方法.这是一个接近问题精神的人.遗憾的是它需要这么多伏都教.应该将这样的东西添加到其中一个基本命令中.可能是`git rebase --squash-recent`,甚至是`git commit --amend-many`. (139认同)
  • 这种类型要求我"推-f",否则它很可爱,谢谢. (92认同)
  • @ 2rs2ts git push -f sound危险.注意只能压制本地提交.永远不要触摸推送提交! (33认同)
  • 我之后还需要使用`git push --force`以便它接受提交 (15认同)
  • @ABB:如果你的分支有一个"上游"集合,那么你可以使用`branch @ {upstream}`(或者只是`@ {upstream }`作为当前分支;在这两种情况下,最后一部分可以是缩写为"@ {u}";参见[gitrevisions](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html).这可能与*你的*"最后推送提交"不同(例如,如果其他人推送了在你最近的推送之上构建的东西然后你拿到了​​它),但似乎它可能接近你想要的. (12认同)
  • 我想提出这个问题,但我不能让自己成为那个改变"1337"的投票数的人...... (4认同)
  • 感谢您提供的解决方案不需要为每个提交手动键入squash/fixup,这与其他地方的所有交互式rebase建议不同. (4认同)
  • 尝试习惯“git push --force-with-lease”而不是“git push -f”! (4认同)
  • 如果其中一个提交将父改变回分支怎么办? (3认同)
  • 尝试推送时出现错误 error: failed to Push some refs to 'git@github.com:....' 提示:更新被拒绝,因为当前分支的提示落后了。我在这里找到了如何解决这个问题:http://stackoverflow.com/questions/5667884/how-to-squash-commits-in-git-after-they-have-been-pushed (3认同)
  • 我认为比那些强迫推动的人更好的是只做一个新的功能分支.所以像```git checkout -b feature-name-squashed```,按照这些指示,然后推动分支的新压扁版本.如果执行此操作,您将可以访问该功能的完整提交日志(在功能名称上),如果您需要它们. (3认同)
  • 我认为这是目前最好的方法。但请注意我们的警告:如果您有未暂存或未提交的更改,Git 不会阻止您执行这些操作,并且您未提交的更改将合并到压缩的提交中。这可能是您想要的,也可能不是您想要的。 (3认同)
  • 在进行软复位时,自动确定目标提交ID的最佳方法是什么,即最后一次推送提交?例如,我不想查找和计算`3`. (2认同)
  • `git log --one-line`或类似内容将显示提交ID和消息列表,每行一个.这个解决方案非常有用. (2认同)
  • 确保您的工作副本没有其他更改(`git stash`它们或其他东西)。否则,您也有机会将它们提交到压缩的提交中,这可能不是您打算要做的。 (2认同)
  • 就要解决的冲突数量而言, git reset --soft HEAD~3 绝对更好。我们的测试用例是 HEAD~6,但其中一个提交是合并提交,因此我们有 45 个提交,而 rebase -i HEAD~6 给我们带来了很多冲突,最终导致构建失败。当我们使用 Reset --soft 时,它给我们解决了 0 个冲突。 (2认同)
  • `git push -f` 似乎不会改变 upsteam 存储库的提交日志。 (2认同)
  • @ChrisJohnsen如何保存更改,提交消息后输入? (2认同)
  • 在重写历史之后,必须要`git push -f`.重写历史记录可能会很糟糕,当然,如果您要将其用于共享存储库.但这是一个与这个答案无关的独立主题(这很棒). (2认同)
  • 如果您已经推送了要压缩的提交,并且希望避免强制推送,请在您所在的提交处创建一个新分支并推送它: git checkout -b new-branch-name && git push -你 (2认同)
  • 这种方法和“真正的”rebase 之间的一个值得注意的区别是原始提交的作者在这里丢失了。 (2认同)
  • 不确定这是在哪个版本中添加的,但您可以使用这个衬垫来可靠地重用最新的提交消息和作者:`git reset --soft {base-commit} && git commit --reuse=HEAD@{1}` (2认同)
  • 我不小心做了两次`git reset --soft HEAD~3`。请注意它们堆叠。 (2认同)
  • 对于那些对`HEAD..HEAD @ {1}`感到好奇的人,`r1..r2`指定从`r2`可以访问的提交范围,除了那些可以从`r1`和'<refname> @ { <n>}`指定该引用的第n个优先值。因此,这里的HEAD..HEAD @ {1}表示当前HEAD与重置之前HEAD之间的所有提交。 (2认同)
  • 如果我当前的分支已经从“otherbranch”分支出来,并且我想在将当前分支合并到“otherbranch”之前压缩我在当前分支上所做的所有操作,我可以执行“git reset --soft otherbranch”,而不必弄清楚如何许多提交之前那是 (2认同)
  • 这对我有用,而“git rebase -i”则不起作用。我试图压缩一些中间有几个合并提交的工作,并且我一直遇到冲突(我认为这是不可能的,但我猜测这是因为合并提交被删除了) )。试过这个,瞧!没有抱怨,第一次工作。强烈推荐。:) (2认同)

Ano*_*mie 1873

使用git rebase -i <after-this-commit>和替换用"南瓜"或"修正"的第二和随后提交"取",如在所描述的手动.

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

  • 我发现这个回复太简洁了,无法明确理解.一个例子会有所帮助. (306认同)
  • 我认为,这可以更好地回答这个问题http://stackoverflow.com/a/5201642/295797 (241认同)
  • 什么是`<after-this-commit>`的意思? (81认同)
  • 这个`rebase -i`方法和`reset --soft`之间的区别是,'rebase -i`允许我保留提交作者,而`reset --soft`允许我重新发送.有时我需要压缩提交请求,同时维护作者信息.有时候我需要在自己的提交中重置软件.无论如何,支持这两个伟大的答案. (47认同)
  • `<after-this-commit>`是提交X + 1,即您想要压缩的最早提交的父级. (35认同)
  • `使用git rebase -i <after-this-commit>并在第二次和后续提交中用"squash"或"fixup"替换"pick",如手册中所述.uhhhh ... wut? (14认同)
  • 如果您已经推送了提交,则需要按-f强制将远程分支移动到新的提交.但是,这会让那些在旧提交之上工作的人感到不安. (11认同)
  • 由于某些原因,我总是最终搞砸了rebase,重置--soft在大多数情况下似乎更直观. (4认同)
  • 对 `&lt;after-this-commit&gt;` 的解释不必要地复杂。如果有一个更简单的解释(所选择的单词几乎已经是不言自明的,但是*给出的*解释过于复杂),这个答案将是完美的。 (4认同)
  • 有没有办法在不使用交互模式的情况下使用git rebase进行压缩? (3认同)
  • @Cheeso,[本文](https://www.atlassian.com/git/tutorials/rewriting-history#git-rebase-i) 有助于解释交互式变基期间使用的“squash”和“fixup”指定。具体来说,“squash”和“fixup”名称告诉 Git 如何组合提交消息。 (3认同)
  • 我觉得你真正的意思是“&lt;before-this-commit&gt;”,但你将这样的参数描述为过去的提交。 (3认同)
  • @Geynen 谢谢,该链接提供了**唯一**完全有意义的描述。现在我什至可以告诉人们“&lt;after-this-commit&gt;”,正是这个意思。它是**非包容性的**,并且允许您在该提交之后*挑选*和*挤压*提交,只要它们都不是初始提交。如果您想包含初始提交,则需要使用“git reset”方法。 (3认同)
  • 它应该是`&lt;after-and-include-this-commit&gt;` (2认同)
  • 这是一个实际的示例:https://feeding.cloud.geek.nz/posts/combining-multiple-commits-into-one/ (2认同)
  • 压扁后你应该怎么做才能推动它? (2认同)
  • 请注意,您可以在交互变基时重新排序提交 - 例如,如果您提交了 A、B,然后是 C,则可以通过在出现提示时交换 B 和 C 行的顺序(并将 C 更改为“),将提交 C 压缩到 A 上”壁球”)。如果您自尝试压缩的提交以来已经提交了更多工作,则很有用。 (2认同)
  • `git reset --soft $(git merge-base HEAD master) &amp;&amp; git commit --reuse-message=HEAD@{1}` (2认同)

Mar*_*air 702

你可以使用git merge --squash它,这比它更优雅git rebase -i.假设你是主人并且想要将最后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
Run Code Online (Sandbox Code Playgroud)

文档git merge--squash更详细地描述了该选项.


更新:这个方法的唯一真正优势git reset --soft HEAD~12 && git commit在于克里斯·约翰森在他的回答中提出的更简单的方法是,你得到的提交消息预填充了你正在压缩的每个提交消息.

  • @Mark Amery:有很多原因我说这更优雅.例如,它不涉及不必要地生成编辑器,然后在"待办事项"文件中搜索和替换字符串.使用`git merge --squash`也更容易在脚本中使用.从本质上讲,理由是你根本不需要`git rebase -i`的"互动性". (75认同)
  • 你说这比'git rebase -i`更"优雅",但你没有给出理由.试探性地说明这一点,因为在我看来事实上情况正好相反,这是一个黑客攻击; 为了强制`git merge`做一个'git rebase`专门设计的东西,你不是要执行超过必要的命令吗? (15认同)
  • 另一个优点是,与rebasing相比,`git merge --squash`在移动/删除/重命名时不太可能产生合并冲突,尤其是当你从本地分支合并时.(免责声明:根据一种经验,如果在一般情况下不是这样,请纠正我!) (11认同)
  • @BT:破坏你的提交?:(我不确定你是什么意思.你提交的任何东西都可以轻松地从git的reflog中恢复.如果你有未提交的工作,但文件已经上演,你仍然可以得到他们的内容回来了,[虽然这将是更多的工作](http://stackoverflow.com/a/7376959/223092).但是,如果你的工作甚至没有上演,我恐怕没有什么可以做的;这就是为什么答案在前面说:"首先检查git状态是否干净(因为git reset --hard将丢弃分阶段和未分阶段的更改)". (8认同)
  • 尽管我很欣赏为这样的重大更改提供详细提交消息的优势,但与 Chris 的方法相比,这种方法也有一个真正的“缺点”:执行 **硬** 重置(`git reset --hard`)更多文件。例如,如果您使用 Unity3D,您会喜欢更少的文件被触及。 (2认同)
  • 在硬复位方面我总是非常不情愿 - 我使用时态标签代替`HEAD @ {1}`只是为了安全起见,例如当您的工作流程因断电而中断一小时. (2认同)
  • 太棒了..这破坏了我的承诺。-1 (2认同)
  • 仅供参考:如果您执行“git merge --squash HEAD@{1}”并收到“错误:未知开关'c”,您可能正在 powershell 控制台中运行。继续的最简单方法可能是通过“cmd”暂时移动到普通命令 shell,然后执行“git merge --squash HEAD@{1}”,然后通过“exit”离开命令 shell 返回到 powershell。(我没有费心去弄清楚如何通过 powershell 运行 `git merge --squash HEAD@{1}`。) (2认同)

nob*_*bar 205

我建议git reset尽可能避免- 特别是对于Git-novices.除非你真的需要基于一些提交自动化一个进程,否则有一种不那么奇特的方式......

  1. 将待压缩的提交放在工作分支上(如果它们还没有) - 使用gitk进行此操作
  2. 检查目标分支(例如'master')
  3. git merge --squash (working branch name)
  4. git commit

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

  • 如果你扩展(1)那将是很好的. (11认同)
  • 这是最安全的方法:没有重置软/硬(!!),或使用reflog! (3认同)
  • @Adam:基本上,这意味着使用 `gitk` 的 GUI 界面来标记您要压缩的代码行,并标记要压缩到的基础。在正常情况下,这两个标签都已经存在,因此可以跳过步骤(1)。 (3认同)
  • 请注意,此方法不会将工作分支标记为完全合并,因此删除它需要强制删除.:( (3认同)
  • 对于(1),我发现`git branch your-feature && git reset --hard HEAD~N`是最方便的方法.但是,它确实再次涉及git重置,这个答案试图避免. (2认同)
  • @Adam:这个答案中有一个假设,您已经有一个与目标分支分歧的工作分支,并且您希望从目标的分歧点压缩工作分支上的所有提交,并将它们应用到单个压缩(非合并)提交中的目标分支。如果您的更改已经在目标分支上提交,那么这个答案没有帮助,因为如果您遵循它,它只会在您想要压缩的分支之上添加一个新的提交到您的目标(在这种情况下,您' d 需要变基以重写目标分支上的历史记录以删除提交)。 (2认同)

Xys*_*Xys 133

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

git reset --soft HEAD~2

git commit -m "new commit message"

git push -f

2 表示最后两次提交将被压缩。你可以用任何数字替换它

  • 我认为,实际上应该“鼓励”用“强制”推动,因为这种方法的影响得到了很好的传达——强制推动与工作的变基和同步齐头并进,所以在我看来,让更多的人知道更好关于这一行动的效果,而不是人们害怕使用的通俗命令。 (19认同)
  • 同意 Matheus 的观点,强制推送功能分支很好,应该通过 rebase 来鼓励。无论如何,直接推送到 main 应该始终受到限制。 (11认同)
  • 如果目标是将这个新提交添加到 master 作为正在进行的 pr 的一部分,您可以使用“git reset --soft $(git merge-base feature master)”,然后使用“git commit”。 (5认同)
  • @FXQuantTrader:如果每个人都强制推动,情况恰恰相反。几乎总是需要用“--force”来推动。这样做可以使您与团队的其他成员和不同的远程位置保持良好的联系,因为您知道正在发生什么。你也知道历史的哪一部分已经稳定下来。无需隐藏这一点。 (3认同)
  • `--force` 不好。更喜欢 `--force-with-lease` ;·) (3认同)
  • 不应该鼓励这种解决方案。在“push”中使用“-f(强制)”选项是一种危险的做法,特别是如果您要推送到共享存储库(即公共历史记录),这将使贡献者的生活变得困难 (2认同)

Eth*_*anB 128

根据Chris Johnsen的回答,

从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'
Run Code Online (Sandbox Code Playgroud)

...或使用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"
Run Code Online (Sandbox Code Playgroud)


~/.gitconfig现在应该包含这个别名:

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


用法:

git squash N
Run Code Online (Sandbox Code Playgroud)

...自动压缩最后一次N提交,包括在内.

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

  • 有意思,但我更愿意自己输入压缩的提交消息,作为我的多次提交的描述性摘要,而不是为我自动输入.所以我宁愿指定`git squash -m"新摘要."`并且自动确定`N`作为未提交的提交数. (6认同)
  • 这很可爱.就个人而言,我想要一个使用第一次压缩提交的提交消息的版本.对于像空白调整这样的事情会有好处. (3认同)
  • @ABB,这听起来像是一个单独的问题。(我不认为这正是OP所要求的;我从来没有觉得我的 git squash 工作流程需要它。) (2认同)
  • @ABB你可以使用`git commit --amend`来进一步更改消息,但是这个别名可以让你在提交消息中有一个良好的开端. (2认同)

br3*_*3nt 104

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

git rebase -i HEAD~3
Run Code Online (Sandbox Code Playgroud)

这很方便,因为即使您在没有跟踪信息/远程仓库的本地分支上也能正常工作.

该命令将打开交互式rebase编辑器,然后允许您按照正常情况重新排序,压缩,重写等.


使用交互式rebase编辑器:

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

最新的提交HEAD首先显示在第1行.以a开头的行#是注释/文档.

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

我更喜欢使用该命令,fixup因为这会将提交的更改"压缩"到上面一行的提交中,并丢弃提交的消息.

正如第1行的提交一样HEAD,在大多数情况下,你会将其保留为pick.你不能使用squashfixup因为没有其他提交来压缩提交.

交互式rebase编辑器

  • 您是否必须选择最上面的一个并压榨其余的?您应该编辑答案以更详细地解释如何使用交互式rebase编辑器 (4认同)
  • @蒂莫,正确。最旧的在顶部,最新的在底部。这就是为什么你需要“选择”第一行。当您在一行上选择“squash”或“fixup”时,它会将更改放入上一行的提交中。 (4认同)
  • 是的,在第1行中保留“ pick”。如果在第1行中选择“ squash”或“ fixup”作为提交,则git将显示一条消息,指出“错误:如果没有先前的提交,则无法进行“修复”。然后,它将为您提供修复的选项:“您可以使用'git rebase --edit-todo'进行修复,然后运行'git rebase --continue'。” 或者,您也可以中止然后重新开始:“或者,您可以使用'git rebase --abort'中止该基础。”。 (2认同)
  • 当您知道想要压缩一定数量的提交或至少查看可以通过输入任意数字压缩的提交时,这感觉像是最好的答案。一般我都用这个。 (2认同)

Mat*_*s M 55

如果您使用TortoiseGit,您可以使用以下功能Combine to one commit:

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

结合提交

此函数自动执行所有必需的单个git步骤.不幸的是只适用于Windows.

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

tru*_*olf 46

基于这篇文章,我发现这个方法对我的用例更容易.

我的'dev'分支在96个提交之前超过了'origin/dev'(所以这些提交还没有推到远程).

我想在推动改变之前将这些提交压缩成一个.我倾向于将分支重置为'origin/dev'状态(这将保留96个提交中的所有更改未分级),然后立即提交更改:

git reset origin/dev
git add --all
git commit -m 'my commit message'
Run Code Online (Sandbox Code Playgroud)

  • 是的,因此它将你所有的提交压缩成一个.恭喜! (15认同)
  • 这不会挤压之前的提交! (4认同)
  • 正是我所需要的。压缩来自我的功能分支的提交,然后我 git Cherry pick 将该提交放入我的 master 中。 (3认同)
  • @trudolf这不是真正的压榨(指个人对压榨的压榨)。这更多是一次提交所有更改。 (3认同)

aab*_*iro 42

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

git rebase -i HEAD~(n number of commits back to review)
Run Code Online (Sandbox Code Playgroud)

这将打开文本编辑器,如果您希望将这些提交合并在一起,则必须使用'squash'切换每个提交前面的'pick'.例如,如果您要将所有提交合并为一个,那么'pick'是您做的第一个提交,所有未来的提交(放在第一个提交之下)应设置为'squash'.如果使用vim,请在插入模式下使用:x来保存并退出编辑器.

然后继续改变:

git rebase -i HEAD~1
Run Code Online (Sandbox Code Playgroud)

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

  • 还请解释 `--continue` 和 vim `:x` 的作用。 (2认同)
  • 当您在分支上进行提交时,变基将分块进行,在您的文件中“git add”正确的配置后,您可以使用“git rebase --continue”移动到下一个提交并开始合并。```:x``` 是一个在使用 vim 时保存文件更改的命令,请参阅[this](http://vim.wikia.com/wiki/Saving_a_file) (2认同)

Jak*_*han 41

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

 git rebase -i HEAD~n
Run Code Online (Sandbox Code Playgroud)

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

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....
Run Code Online (Sandbox Code Playgroud)

更新如下,

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....
Run Code Online (Sandbox Code Playgroud)

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

祝好运!!


Mar*_*oma 32

Anomies答案很好,但我对此感到不安全,所以我决定添加一些屏幕截图.

第0步:git log

看看你在哪里git log.最重要的是,找到你不想压缩的第一次提交的提交哈希.所以只有:

在此输入图像描述

第1步:git rebase

git rebase -i [your hash]在我的情况下执行:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
Run Code Online (Sandbox Code Playgroud)

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

在我的情况下,我想在第一次提交的时候压缩所有内容.排序是从头到尾,所以完全是另一种方式git log.在我的情况下,我想:

在此输入图像描述

第3步:调整消息

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

在此输入图像描述

而已.一旦你保存了这个(:wq),你就完成了.看看吧git log.

  • 很高兴看到最终结果,例如`git log` (2认同)

ana*_*ana 31

这是执行后将遵循的另一个可视化示例: git rebase -i HEAD~3

这里有一个直观的例子,说明在为最后三个提交执行 git rebase 后会发生什么

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


Sau*_*ahu 30

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

  • 转到git窗口
  • 手动选择要合并为一个的所有提交。
  • 右键单击>>Squash Commits编辑压缩的提交消息
  • 点击左侧分支名称 > 右键 > 推送 >Force Push

在此输入图像描述


ras*_*hok 29

1)识别提交短哈希

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....
Run Code Online (Sandbox Code Playgroud)

这里甚至git log --oneline还可以用来获得短哈希.

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

# git rebase -i deab3412 
Run Code Online (Sandbox Code Playgroud)

3)这打开了一个nano合并编辑器.它看起来像下面

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....
Run Code Online (Sandbox Code Playgroud)

4)重命名字picksquash其存在之前abcd1234.重命名后应该如下所示.

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....
Run Code Online (Sandbox Code Playgroud)

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

6)然后nano编辑器再次打开以更新注释,必要时更新它.

7)现在它成功压扁,您可以通过检查日志来验证它.

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....
Run Code Online (Sandbox Code Playgroud)

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

# git push origin +master
Run Code Online (Sandbox Code Playgroud)

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


rnw*_*ser 28

方法 1(如果您有很多提交)

git rebase -i master 然后按键盘“i”进行编辑

你会看到这样的:

pick etc1
pick etc2
pick etc2
Run Code Online (Sandbox Code Playgroud)

将单词 pick 替换为'f'并按esc y :wq

pick etc1 //this commit will the one commit
f etc2
f etc2
Run Code Online (Sandbox Code Playgroud)

然后按这个命令

git push origin +head
Run Code Online (Sandbox Code Playgroud)

方法2如果你的提交很少,你可以这样做来删除一个提交,你需要做同样的事情来删除你的第二个提交,依此类推

git reset --soft HEAD^1 // or git reset --soft head~1
git commit --amend //then press `:wq` 
git push -f
Run Code Online (Sandbox Code Playgroud)

方法 3如果您已经有一个提交并且不想再提交另一次提交

git add files...
git commit --amend  //then press `:wq`
git push origin +head
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,这个答案假设您已将“vi”设置为 git 中的默认编辑器。 (2认同)

San*_*mar 27

如果你在一个feature-branch从Golden Repository()克隆的远程分支(被叫)上golden_repo_name,那么这就是将你的提交压缩为一个的技巧:

  1. 查看黄金回购

    git checkout golden_repo_name
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从中创建一个新分支(黄金回购),如下所示

    git checkout -b dev-branch
    
    Run Code Online (Sandbox Code Playgroud)
  3. 壁球与您已经拥有的当地分支合并

    git merge --squash feature-branch
    
    Run Code Online (Sandbox Code Playgroud)
  4. 提交你的更改(这将是dev-branch中唯一的提交)

    git commit -m "My feature complete"
    
    Run Code Online (Sandbox Code Playgroud)
  5. 将分支推送到本地存储库

    git push origin dev-branch
    
    Run Code Online (Sandbox Code Playgroud)

  • 由于我只是压缩了约 100 个提交(用于通过 git-svn 同步 svn 分支),这比交互式变基要快得多! (2认同)
  • 往下读,我看到@Chris 的评论,这就是我以前所做的(rebase --soft...) - 太糟糕了,stackoverflow 不再将数百个赞成票的答案放在顶部...... (2认同)
  • 同意你的观点@sage,希望他们将来能这么做 (2认同)

Ari*_*zon 20

真正方便的是:
找到你要压缩的提交哈希,比方说d43e15.

现在用

git reset d43e15
git commit -am 'new commit name'
Run Code Online (Sandbox Code Playgroud)

  • 这个。为什么没有更多人使用这个?这比重新定位和压缩单个提交要快得多。 (2认同)

Aya*_*yan 20

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

git reset --soft HEAD~10 && git commit -m "squashed commit"
Run Code Online (Sandbox Code Playgroud)

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

git push -f
Run Code Online (Sandbox Code Playgroud)


Pra*_*hwa 20

最简单的方法是使用 GitHub Desktop。只需选择历史记录中的所有提交,右键单击并选择“Squash x commits”:

GitHub 桌面壁球

  • @Siwei 如果它有效的话,它有多“专业”并不重要 (2认同)

Cas*_*bel 17

这是超级愚蠢的kludgy,但是以一种很酷的方式,所以我只是把它扔进戒指:

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
Run Code Online (Sandbox Code Playgroud)

翻译:为git提供一个新的"编辑器",如果要编辑的文件名是git-rebase-todo(交互式rebase提示),除了第一个"pick"改为"squash",否则会产生vim - 这样当你被提示时编辑压缩的提交消息,你得到vim.(显然我在分支foo上压缩了最后五次提交,但是你可以随意更改它.)

不过,我可能会做马克·朗格尔建议的事情.

  • +1:这很有趣,也很有启发性,因为在GIT_EDITOR环境变量中你可以放置比程序名更复杂的内容,这一点对我来说并不是很明显. (7认同)

Wil*_*iss 16

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

git checkout --orphan <new-branch>
git commit
Run Code Online (Sandbox Code Playgroud)


小智 14

我认为最简单的方法是通过从master创建一个新的分支并进行合并 - 对功能分支进行处理.

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch
Run Code Online (Sandbox Code Playgroud)

然后,您已准备好提交所有更改.


Alb*_*lan 12

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

我所做的是

  1. git reset --soft Head〜3 &&
  2. git提交
  3. git push origin(branch_name)--force

  • 请注意,由于使用了force,因此自删除它以来就无法检索以前的提交 (3认同)
  • 武力具有破坏性。这并不是压缩提交,而是删除最后三个提交并将它们作为第四个(现在是新的)提交添加回来,本质上是重写历史记录,这可能会破坏其他用户的存储库,直到他们也强制拉取。这也将删除您的团队同时推送的任何其他提交。 (2认同)

Wil*_*ken 11

?? 警告:“我最近的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)              
Run Code Online (Sandbox Code Playgroud)

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

您打开了一个拉取请求,并在GitHub上看到以下内容:

四次提交:

  • 添加丹尼·基万(Danny Kirwan)
  • 添加克里斯汀完美
  • LA1974
  • 比尔·克林顿

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

那会发生什么呢?您刚刚完成了一次从Fritz到Bill Clinton的提交。因为您忘记了昨天您正在从事该项目的白金汉尼克斯版本。而且git log与您在GitHub上看到的不符。

这个故事所讲的道德

  1. 找到你要得到确切的文件,和git checkout他们
  2. 找到确切的承诺之前要保存在历史记录,以及git reset --soft
  3. 做一个git commit直接从该经线

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

Col*_*inM 10

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

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

  • 我对压缩提交及其令人惊讶的复杂性感到无比沮丧-只是使用最后一条消息并将它们全部压缩为一次提交!为什么这么难????这支班轮为我做到了。衷心感谢您。 (3认同)

Pul*_*sal 10

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

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

  • 记下当前提交 id:使用git log -1 --oneline并记下当前状态的提交 id(以防万一您在 git reset 上做错了)
  • 返回 3 次提交:使用git reset --soft HEAD~3您将返回 3 次提交(并且有点忘记您之前已经进行了这 3 次提交)
  • 做一个新的提交:现在简单地做git commit -m <NEW_SINGLE_MESSAGE>这将自动组合您的消息下的三个提交

如果 git reset 出现问题,您可以通过 git reset --soft <ORIGINAL_COMMIT>

  • 在步骤 #2 中使用“--soft”非常重要,否则您将恢复到三个提交前的状态。我认为应该强调这一点。 (10认同)
  • 同样重要的是,当您想要推送压缩的提交时,您将需要 --force (5认同)
  • 如果你像我一样特别紧张,你总是可以在执行“git reset --soft HEAD~3”之前创建一个新分支作为备份。这样您就可以得到一个与您开始位置完全相同且易于使用的副本。即使你最后用力推动 (2认同)

iro*_*rrl 10

我们对这个答案非常满意,这意味着您不需要计算提交。

\n

如果您在 master 分支上有大量提交并希望将它们全部合并为一个:

\n
    \n
  • 确保您位于 master 分支上并执行git status以确保一切都是干净的
  • \n
  • 在开始工作之前复制提交的提交 SHA
  • \n
  • git重置\xe2\x80\x92soft commitIdSHA
  • \n
\n

[您会注意到此时的所有更改都将显示在 IDE 的源代码控制部分中 - 最好查看它们以检查是否全部存在]

\n
    \n
  • git commit -am “您想要的消息将替换所有其他提交消息”
  • \n
  • git push (会抱怨你落后于提交)所以git push --force
  • \n
\n

就是这样!

\n


aru*_*436 8

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

在此处输入图片说明


Zso*_* Z. 8

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

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
Run Code Online (Sandbox Code Playgroud)


小智 8

我受到克里斯·约翰森的回答的启发,并找到了更好的解决方案。

如果我们想压缩最后 3 个提交,并从头开始编写新的提交消息,这就足够了:

git reset --soft HEAD~3 && git commit
Run Code Online (Sandbox Code Playgroud)

如果我们想压缩最后的许多提交,比如说 162 个提交,那么很难计算第 162 个提交的排名,但是我们可以使用提交 ID,这就足够了:

git reset --soft ceb5ab28ca && git commit
Run Code Online (Sandbox Code Playgroud)

ceb5ab28ca 是第 162 次提交的提交 ID。


Eth*_*han 6

我发现一个更通用的解决方案不是指定“N”次提交,而是指定您想要压缩的分支/提交 ID。这比将提交计数到特定提交更不容易出错——只需直接指定标签,或者如果你真的想要计数,你可以指定 HEAD~N。

在我的工作流程中,我启动了一个分支,我在该分支上的第一次提交总结了目标(即它通常是我将作为功能的“最终”消息推送到公共存储库的内容。)所以当我完成后,所有我想做的是git squash master回到第一条消息然后我准备推送。

我使用别名:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i
Run Code Online (Sandbox Code Playgroud)

这将在执行之前转储被压缩的历史记录 - 如果您想恢复,这使您有机会通过从控制台获取旧的提交 ID 来恢复。(Solaris 用户注意到它使用 GNU sed-i选项,Mac 和 Linux 用户应该可以接受。)


lit*_*hat 6

有问题的是,“最后”的含义可能是模棱两可的。

例如git log --graph输出以下(简体):

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|
Run Code Online (Sandbox Code Playgroud)

然后按时间的最后提交是H0,合并,B0。要压缩它们,您将必须基于提交H1重新建立合并的分支。

问题在于H0包含H1和H2(通常在合并之前和分支之后会有更多提交),而B0则没有。因此,您至少必须管理来自H0,合并,H1,H2,B0的更改。

可以使用rebase,但使用的方式与其他提到的答案不同:

rebase -i HEAD~2

这将为您显示选择选项(如其他答案中所述):

pick B1
pick B0
pick H0
Run Code Online (Sandbox Code Playgroud)

将壁球而不是接球放到H0:

pick B1
pick B0
s H0
Run Code Online (Sandbox Code Playgroud)

保存并退出rebase之后,将在H1之后依次应用提交。这意味着它将要求您再次解决冲突(其中HEAD首先为H1,然后在应用提交时累积提交)。

重置完成后,您可以选择压缩的H0和B0消息:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|
Run Code Online (Sandbox Code Playgroud)

PS:如果您只是对BO进行一些重置:(例如,使用/sf/answers/1308359181/reset --mixed进行了详细说明):

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'
Run Code Online (Sandbox Code Playgroud)

那么您将压倒H0,H1,H2的B0更改(在分支之后和合并之前完全放弃提交更改)。


all*_*jom 6

与这样的工作流程有关的问题的答案呢?

  1. 许多本地提交,混合有来自master的多个合并
  2. 最终推向远程
  3. 公关并由审稿人合并为硕士。(是的,对于开发人员而言,merge --squash进行PR 会更容易,但是团队认为这样做会拖慢过程。)

我在此页面上没有看到这样的工作流程。(可能是我的眼睛。)如果我理解rebase正确,那么多次合并将需要多种冲突解决方案。我什至不想考虑!

因此,这似乎对我们有用。

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. 在本地编辑和提交大量内容,定期合并母版
  5. git checkout new-branch
  6. git merge --squash new-branch-temp //将所有更改置于阶段
  7. git commit 'one message to rule them all'
  8. git push
  9. 审阅者执行PR并合并到母版。


Sam*_*Sam 6

如何使用 Git 将我最后的 X 次提交合并为一次提交?

git rebase -i HEAD~X
Run Code Online (Sandbox Code Playgroud)

将显示以下内容:

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

# ...
Run Code Online (Sandbox Code Playgroud)

对于你想要压缩的提交,用fixup替换pick,所以它变成:

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

# ...
Run Code Online (Sandbox Code Playgroud)

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

验证:检查git log


sli*_*hyi 6

简单的解决办法:

git reset --soft HEAD~5

git commit -m "commit message"

git push origin branch --force-with-lease

  • 感谢您的回答。我尝试了很多次 rebase,但只有你的有效。 (3认同)

Yoa*_*nda 5

git rebase -i HEAD^^
Run Code Online (Sandbox Code Playgroud)

^的数量是X

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


Ign*_*ant 5

除了其他出色的答案,我想补充一下如何git rebase -i总是使我对提交顺序感到困惑-从旧到新,反之亦然?这是我的工作流程:

  1. git rebase -i HEAD~[N],其中N是我要加入的提交数,从最近一次开始。因此git rebase -i HEAD~5意味着“将最后5次提交压缩为新的提交”;
  2. 编辑器弹出,显示我要合并的提交列表。现在,它们以相反的顺序显示:较早的提交位于顶部。将其中的所有提交标记为“ squash”或“ s”,除了第一个/较旧的提交之外:它将用作起点。保存并关闭编辑器;
  3. 编辑器会再次弹出,并带有一条默认消息,提示新提交:将其更改为您的需要,保存并关闭。壁球完成!

资料和其他读物:#1#2


归档时间:

查看次数:

1468360 次

最近记录:

5 年,10 月 前