Categories
git git-squash rebase squash

How do I squash my last N commits together?

4721

How do I squash my last N commits together into one commit?

4

2716

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.

In this example, <after-this-commit> is either the SHA1 hash or the relative location from the HEAD of the current branch from which commits are analyzed for the rebase command. For example, if the user wishes to view 5 commits from the current HEAD in the past the command is git rebase -i HEAD~5.

20

  • 135

    What is meant by <after-this-commit>?

    – 2540625

    Nov 4, 2014 at 5:49

  • 63

    <after-this-commit> is commit X+1 i.e. parent of the oldest commit you want to squash.

    – joozek

    Nov 4, 2014 at 12:04

  • 18

    If you’ve already pushed the commits, you will need to push -f to forcibly move the remote branch to your new commit. This will upset anyone who was working on top of the old commits, though.

    – interfect

    Dec 8, 2014 at 18:31

  • 77

    The difference between this rebase -i approach and reset --soft is, rebase -iallows me to retain the commit author, while reset --soft allows me to recommit. Sometimes i need to squash commits of pull requests yet maintaining the author information. Sometimes i need to reset soft on my own commits. Upvotes to both great answers anyways.

    – zionyx

    Sep 15, 2015 at 9:31


  • 43

    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. uhhhh… wut?

    – Cheeso

    Jul 27, 2016 at 3:18

2716

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.

In this example, <after-this-commit> is either the SHA1 hash or the relative location from the HEAD of the current branch from which commits are analyzed for the rebase command. For example, if the user wishes to view 5 commits from the current HEAD in the past the command is git rebase -i HEAD~5.

20

  • 135

    What is meant by <after-this-commit>?

    – 2540625

    Nov 4, 2014 at 5:49

  • 63

    <after-this-commit> is commit X+1 i.e. parent of the oldest commit you want to squash.

    – joozek

    Nov 4, 2014 at 12:04

  • 18

    If you’ve already pushed the commits, you will need to push -f to forcibly move the remote branch to your new commit. This will upset anyone who was working on top of the old commits, though.

    – interfect

    Dec 8, 2014 at 18:31

  • 77

    The difference between this rebase -i approach and reset --soft is, rebase -iallows me to retain the commit author, while reset --soft allows me to recommit. Sometimes i need to squash commits of pull requests yet maintaining the author information. Sometimes i need to reset soft on my own commits. Upvotes to both great answers anyways.

    – zionyx

    Sep 15, 2015 at 9:31


  • 43

    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. uhhhh… wut?

    – Cheeso

    Jul 27, 2016 at 3:18

898

You can use git merge --squash for this, which is slightly more elegant than git rebase -i. Suppose you’re on master and you want to squash the last 12 commits into one.

WARNING: First make sure you commit your work—check that git status is clean (since git reset --hard will throw away staged and unstaged changes)

Then:

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

# [email protected]{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 [email protected]{1}

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

The documentation for git merge describes the --squash option in more detail.


Update: the only real advantage of this method over the simpler git reset --soft HEAD~12 && git commit suggested by Chris Johnsen in his answer is that you get the commit message prepopulated with every commit message that you’re squashing.

16

  • 98

    @Mark Amery: There are various reasons that I said that this is more elegant. For example, it doesn’t involve unnecessarily spawning an editor and then searching and replacing for a string in the “to-do” file. Using git merge --squash is also easier to use in a script. Essentially, the reasoning was that you don’t need the “interactivity” of git rebase -i at all for this.

    Jul 8, 2013 at 15:59


  • 2

    Even though I appreciate the advantage of having a verbose commit message for big changes such as this, there’s also a real disadvantage of this method over Chris’s: doing a hard reset (git reset --hard) touches a lot more files. If you’re using Unity3D, for instance, you’ll appreciate less files being touched.

    – cregox

    Nov 26, 2013 at 12:35

  • 15

    Another advantage is that git merge --squash is less likely to produce merge conflicts in the face of moves/deletes/renames compared to rebasing, especially if you’re merging from a local branch. (disclaimer: based on only one experience, correct me if this isn’t true in the general case!)

    Feb 27, 2014 at 22:21

  • 4

    I’m always very reluctant when it comes to hard resets – I’d use a temporal tag instead of [email protected]{1} just to be on the safe side e.g. when your workflow is interrupted for an hour by a power outage etc.

    Aug 11, 2014 at 12:18

  • 12

    @B T: Destroyed your commit? 🙁 I’m not sure what you mean by that. Anything that you committed you’ll easily be able to get back to from git’s reflog. If you had uncommitted work, but the files were staged, you should still be able to get their contents back, although that will be more work. If your work wasn’t even staged, however, I’m afraid there’s little that can be done; that’s why the answer says up-front: “First check that git status is clean (since git reset –hard will throw away staged and unstaged changes)”.

    May 22, 2016 at 9:55