Squash: A Whole New Way to Merge Pull Requests

Matthew Mitrik (MS)

Are you the type of developer that loves to keep your repos neat and tidy?  Are you a fan of interactive rebase and fixing up your commits until they’re just right?  Do you wish you had an alternative to –no-ff merges when completing your pull request?  In the March 3rd release of Visual Studio Team Services, a new option was added to the PR merge process to allow the topic branch changes to be squash merged, greatly simplifying target branch history.

What is squash merge?

A squash merge is a merge option in Git that will produce a merge commit with only one parent.  The files are merged exactly as they would be in a normal merge, but the commit metadata is changed to show only one of the parent commits.  The result is a single commit on the target branch with all of the changes from a normal merge.

Why would I use a squash merge?

Simply put, a squash merge produces a cleaner history.  When working with topic branches, and especially when responding to code review feedback, a small change can easily grow to span multiple commits.  Interactive rebasing and force pushing is often the way to clean up these intermediate commits, but even then a new merge commit is created if you’re using pull requests and merging on the server.

When it comes to merging and history graphs, I think illustrations are really helpful.  So, let’s suppose I had a repo with a master branch and a topic branch, with a graph that looked like this:

A git graph with a master and topic branch, before merging

 

Now, let’s suppose I created two copies of this repo.  In the first repo, I’ll perform a normal merge of of topic into master.

    git checkout master 
    git merge topic

That results in a graph that looks like this:

A git graph with a master and topic branch, after a normal merge

As expected, the new merge commit F is created, and it has two parents: E from master, and D from topic.  This is the same graph that you would expect if you perform a normal pull request merge.

Now, let’s go to the second repo, and instead, I’ll perform a squash merge.

    git checkout master 
    git merge --squash topic

That results in a graph that looks like this:

A git graph with a master and topic branch, after a squash merge

There is a new commit that is created, F’ but it only has one parent: E from master.  At a glance, this doesn’t look like a merge at all.  However, the contents of F’ will contain the contents from both master and topic.  If you were to compare the contents of F and F’ you would see that they in fact contain the exact same contents – only the metadata is different.  It’s worth noting that the commits B and D won’t be reachable from the master branch, and if you delete the topic branch, they’ll be orphaned.  But don’t worry, the file changes have been merged so none of the content is lost.

If you’re playing along at home, try running this command in each repo and comparing the output:

    git cat-file -p <commit ID>

The trees will be identical for the two merge commits, and the repo with the squash merge will only have one parent commit.

Squash merging when completing your PR

The example above shows how you can use the git command line to squash merge changes into a branch, but if you’re working on a team that’s using pull requests, it’s not much help.  This is where the new squash merge option in pull requests comes in.

Using this option is easy – your workflow remains unchanged up until the point you’re ready to merge your PR.  On the merge dialog, check the “Squash changes when merging” option and the server side merge will use the –squash option.

 Squash merge option in pull request

That’s it.  Your git graph will now be clean and simple.

Happy merging!

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Steve Klabak 0

    Is there a way to get the default draft message containing all of your branch’s commit messages when completing the pull request with “Squash commit”?  I’m looking for something similar to doing it with git bash and omitting -m.

Feedback usabilla icon