Git - squash entire branch - one line squash command

masstroy picture masstroy · Dec 29, 2014 · Viewed 9.7k times · Source

Whilst I am working on new code, I make many small commits to track my changes. My company, however, prefers each feature to be committed as a single commit. So the solution is to squash my entire (local) branch down to a single commit.

How do I squash an entire branch without using git rebase --interactive and then changing pick to squash for all the commits?

Answer

meagar picture meagar · Dec 30, 2014

My preferred method is a two-liner (excluding steps 1 and 4 below). The benefits are you do not need to know/record any commit IDs, you can write a simple alias to perform all the steps involved, and your actually moving your entire branch onto origin/master so that the actual merge into master can be a fast-forward and there cannot be any conflicts.

First, my assumptions:

  • You're working on a branch called my-feature-branch. This branch has diverged from master by several commits; this is the checked-out branch.
  • Your local master tracks remote branch origin/master
  • You want to squash all of your commits from my-feature-branch into a single commit ontop of the current state of origin/master (not your local master, which may be out of date)
  • All of your changes are committed, you have no unstaged changes (they will be lost during git reset --hard)

My process is as follows:

  1. Fetch, so origin/master is current:

    $ git fetch
    
  2. Throw away all the commits on your local branch by resetting it to point at origin/master

    $ git reset --mixed origin/master
    
  3. Merge all of your old changes from the previous state of your branch into the index

    $ git merge --squash HEAD@{1}
    
  4. Commit your changes - Git will pre-populate your editor with a commit message containing all the commit messages from the squashed commits

The simple alias I mentioned would be:

alias squash="git fetch; git reset --mixed origin/master; git merge --squash HEAD@{1}"