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

5289

我该如何将最近的 N 次提交压缩成一个提交记录?


8
相关:Git - 推送前合并多个提交记录 - user456814
3
要将多个 Git 提交压缩成一个,请参考此链接 - https://dev59.com/CnI-5IYBdhLWcg3w0cKG#9254257。 - goelakash
3
挤压操作后需要进行强制推送(force push)。该网址(https://dev59.com/NWkv5IYBdhLWcg3w3Ug0)提示需要合并才能推送至Github。 - vikramvi
3
除了已发布的答案外,GUI客户端可以轻松实现这一点。我可以在GitKraken中只用四个点击压缩数十个提交。 - Aaron Franke
我尝试的所有答案都搞砸了子模块。这个答案没有。 - ridilculous
为什么没有像 git fold --from abc --to efg 这样的命令? - user27182
46个回答

65
如果您使用TortoiseGit,您可以使用 合并为一个提交 功能:

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

合并提交

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


3
据我所知,这对于合并提交将不起作用。 - Thorkil Holm-Jacobsen
4
尽管没有其他人评论这个问题,但这个方法也适用于不在HEAD的提交。比如,我的需求是在推送之前将一些进行中的提交压缩成一个更加合理的描述。效果非常好。当然,我仍然希望学习如何通过命令来完成这个操作。 - Charles Roberto Canato
1
太棒了!只需点击几下鼠标,我就可以在归档之前合并旧存储库的200个提交!谢谢。这真的很有用,可以使分支树变得干净,并轻松地一次性审查代码更改。 - sanpat
您可以通过 GitHub Desktop 的 GUI 同样选择 n 个提交并将它们压缩成一个。https://desktop.github.com/ - Jirik

65

许多解答都基于git rebase命令,但据我的经验,这对于刚开始使用Git的人来说有点复杂和高级。

假设你想压缩最近的3个提交记录。则按照以下步骤进行:

  • 记录当前提交记录 ID:使用git log -1 --oneline命令并记下现在状态的提交ID(以防万一您使用了错误的git reset操作)
  • 回退3个提交记录:使用git reset --soft HEAD~3,您将会回退3个提交记录(并且会忘记之前已经做过这三次提交)
  • 新建一个提交记录:现在只需运行git commit -m <NEW_SINGLE_MESSAGE>命令,它将自动将这三次提交记录合并为一个,并使用指定的消息。

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


9
在第二步中使用“--soft”非常重要,否则您将会回滚到三个提交之前的状态。我认为这一点应该得到强调。 - Dercsár
5
同样重要的是,当您想要推送已压缩的提交时,您需要使用--force。 - Dercsár
1
如果你和我一样非常紧张,你可以在执行 git reset --soft HEAD~3 命令之前创建一个新的分支作为备份。这样,你就有了一个精确、易于使用的起始副本。即使在最后进行强制推送之后也是如此。 - NateH06

63

根据我找到的这篇文章,我发现这种方法对我的使用情况更简单。

我的“dev”分支比“origin/dev”超前了96次提交(所以这些提交尚未推送到远程)。

在推送更改之前,我想将这些提交压缩成一个。我更倾向于将分支重置为“origin/dev”的状态(这将使来自96次提交的所有更改保持未暂存状态),然后一次性提交更改:

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

3
正是我所需要的。我会压缩我的特性分支中的提交,然后将那个提交使用 "git cherry-pick" 命令应用到主分支上。 - David Victor
4
这不会覆盖之前的提交记录! - IgorGanapolsky
5
这并不是真正的压缩(挑选单个提交来压缩)。这更像是一次性提交你所有的更改。 - IgorGanapolsky
21
是的,这样它就会将你所有的提交压缩成一个。恭喜! - trudolf
作为对我的评论的延续。当我创建一个合并分支,然后将特性分支合并到其中时,压缩工作正常。这需要更多的工作,但仍然比手动挑选所有内容要少。 - Jared
显示剩余3条评论

61

Anomies答案很好,但我对此感到不安,因此决定添加一些截图。

步骤 0:git log

使用git log查看当前所在位置。最重要的是找到第一个您不想合并的提交哈希值。只需:

输入图片说明

步骤 1:git rebase

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

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

第二步:选取/压缩您想要的内容

在我的情况下,我想将提交时间最早的所有内容压缩成一个。排序顺序是从先到后,与git log完全相反。在我的情况下,我想要:

enter image description here

第三步:调整消息

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

enter image description here

就是这样。一旦保存(:wq),您就完成了。使用git log查看它。


4
很希望能够看到最终结果,例如 git log - Timothy L.J. Stewart
@Axalix 你删除了所有的代码行吗?这样会导致你失去提交记录。 - a3y3

46

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

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

那么你已经准备好提交所有的更改了。


这是一个不错的替代方案,可以实现类似的最终结果。我本来想用rebase来做,但我觉得这种方式更好。我总是忘记git merge的存在。 - Felipe Romero
我曾尝试其他解决方案,但由于某种原因它们都没有起作用。而这个方法却行得通。 - Brian Schermerhorn
谢谢你!这帮了我大忙了。我已经绝望地想修复任何问题了... - Correcter
这个像魔法一样好用。但我认为有一个前提,你需要确保feature_branch在master分支的后面有0。 - GLP
将操作分成一个暂存分支的技巧不错!这样可以更轻松地对比干净的分支。 - colm.anseo
Felipe,你可以在master上进行rebase(不使用-i选项),然后使用这个 :) - cgte

44

步骤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) 如果您想要合并最近的两个提交,请执行squash操作。

# git rebase -i deab3412 

3) 这将打开一个 nano 编辑器,用于合并。界面如下所示:

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

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

....
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

  1. 首先添加需要提交的文件。
git add <files>
  1. 然后使用--fixup选项提交,并且OLDCOMMIT应该是我们需要合并(压缩)这个提交的位置。
git commit --fixup=OLDCOMMIT

现在这将在HEAD顶部创建一个新的提交,其中包含fixup1 <OLDCOMMIT_MSG>

  1. 然后执行下面的命令将新的提交合并(压缩)到OLDCOMMIT中。
git rebase --interactive --autosquash OLDCOMMIT^

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

流程3

  1. 如果需要向上一次提交添加新更改,则可以使用--amendgit-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并生成新的提交ID1d4ab2e1

结论

  • 第一种方法的优点是可以压缩多个提交并重新排序。但如果我们需要将修复合并到非常旧的提交中,则此过程将很困难。
  • 因此,第二种方法有助于轻松地将提交合并到非常旧的提交中。
  • 第三个过程在需要将新更改压缩到最后一个提交中时非常有用。

即使我将重置到第6个最后的提交ID,它仅更新最后两个提交,不知道为什么。 - Carlos Liu
即使您可以重新排列提交顺序,它也能正常工作。 - rashok

42
将最后的10次提交压缩为1个单独的提交:
git reset --soft HEAD~10 && git commit -m "squashed commit"

如果你也想要使用压缩的提交来更新远程分支:

git push -f

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

40
如果例如你想要将分支(远程仓库)中的最后3个提交压缩成一个提交,比如在https://bitbucket.org上,你可以按照以下步骤操作:
  1. git reset --soft HEAD~3
  2. git commit
  3. git push origin <branch_name> --force

8
请注意,如果使用强制操作,则无法检索以前的提交记录,因为您已将其删除。 - Albert Ruelan
我觉得这是一个不错且快速的解决方案。 - B. Bohdan
5
力量是具有破坏性的。这并不是压缩提交记录,而是删除最后三个提交记录,然后将它们作为第四个(现在是新的)提交记录添加回去,从本质上重写历史记录,这可能会破坏其他用户的仓库,直到他们也强制拉取更新。这还将删除团队已经推送的任何其他提交记录。 - Osama Shabrez

39
如果你在一个从黄金仓库(golden_repo_name)克隆的远程分支(称为feature-branch)上,那么这里是将你的提交压缩成一个的技术:

  1. 检出黄金仓库

    git checkout golden_repo_name
    
  2. 按以下步骤从golden repo创建一个新分支

  3. git checkout -b dev-branch
    
    将您已经拥有的本地分支进行Squash合并。
    git merge --squash feature-branch
    
    提交你的更改(这将是dev分支中唯一的提交)
    git commit -m "My feature complete"
    
    将分支推送到您的本地代码库。
    git push origin dev-branch
    

2
由于我只是在压缩约100个提交(通过git-svn同步svn分支),因此这比交互式变基要快得多! - sage
2
往下看,我看到@Chris的评论,那是我以前做的事情(rebase --soft...) - 很遗憾stackoverflow不再将得票数高达数百的答案放在最上面了... - sage
2
我同意@sage的观点,希望他们将来能够实现。 - Sandesh Kumar
这是正确的方法。Rebase方法很好,但只应作为最后的解决方案来压缩。 - Axalix
我正在使一切都最新化。 - Jake Sylvestre

30

有人提到过使用IntelliJ IDEA UI做这个非常容易:

  • 进入 git 窗口
  • 手动选择想要合并到一个提交中的所有提交记录。
  • 右键单击 > Squash Commits > 编辑合并后的提交信息
  • 点击左侧分支名称 > 右键单击 > 推送 > 强制推送

输入图像描述


这对于合并提交无效。 - Hugo M. Zuleta
这在Android Studio中也适用。 - Matt
这在Android Studio中也适用。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接