Mark Needham

Thoughts on Software Development

Git/GitHub: Squashing all commits before sending a pull request

with 5 comments

My colleague Michael has been doing some work to make it easier for people to import data into neo4j and his latest attempt is neo4j-shell-tools which adds some additional commands to the neo4j-shell.

I’ve spent a bit of time refactoring the readme which I’d done on a branch of my fork of the repository and consisted of 46 commits, most changing 2 or 3 lines.

I wanted to send Michael a pull request on Github but first I needed to squash all my commits down into a single one.

I initially thought there might be a way that I could do that via Github but I couldn’t see how to do that and eventually came across a post on Steve Klabnik’s blog which explained what I needed to do.

This is what my .git/config looked like initially:

[remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*
	url = git@github.com:mneedham/neo4j-shell-tools.git
[branch "master"]
	remote = origin
	merge = refs/heads/master
[remote "base"]
	url = git@github.com:jexp/neo4j-shell-tools.git
	fetch = +refs/heads/*:refs/remotes/base/*
[branch "readme"]
	remote = origin
	merge = refs/heads/readme

I had all my commits on the ‘readme’ branch but the easiest approach seemed to be to create another branch on which I could squash all my commit – I called that branch ‘readme-pull':

$ git branch readme-pull
$ git checkout readme-pull
Switched to branch 'readme-pull'

I then synced myself with Michael’s repository:

$ git fetch base
remote: Counting objects: 77, done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 43 (delta 15), reused 40 (delta 12)
Unpacking objects: 100% (43/43), done.
From github.com:jexp/neo4j-shell-tools
   e81c431..c4e94f6  master     -> base/master
 
$ git rebase base/master
First, rewinding head to replay your work on top of it...

I then had to handle any conflicts when applying my changes on top of Michael’s master repository and then I was in a position to squash all my commits!

We can use rebase in interactive mode to do this and I’ve always done so by counting back how many commits I want to squash, so in this case it was 35:

$ git rebase -i HEAD~35
 
pick 141d0ae updating readme with link
pick 94f8f93 more updating
pick 03de50b readme updates
pick 4e60332 more updates
pick 3447d50 simplifying
pick d577520 tweaks
pick 2d993d4 more
pick f948582 list of commands
pick 713aae8 updating

I later realised that I could have just passed in the last commit hash from the master to the rebase command i.e.

commit c4e94f668223d53f6c7364d19aa965d09ea7eb00
Author: Michael Hunger <github@jexp.de>
Date:   Fri Jul 12 10:33:55 2013 +0200
 
    fixed test
$ git rebase -i c4e94f668223d53f6c7364d19aa965d09ea7eb00

I then set all but the first commit to ‘squash‘ and pushed to my repository:

$ git push -u origin readme-pull:readme-pull

Finally I issued my pull request and Michael merged it in!

Be Sociable, Share!

Written by Mark Needham

July 13th, 2013 at 6:47 pm

Posted in Version Control

Tagged with

  • http://andypalmer.com Andy Palmer

    Apart from overall tidyness, what is the value in squashing the commits?
    The pull request will consolidate all the changes into its diff view and the repository (assuming good commit messages) will contain valuable insight into your thoughts.
    Admittedly, this is probably less valuable for a README than, say, refactoring a major component.

  • http://www.markhneedham.com/blog Mark Needham

    @andypalmer:disqus for this case it didn’t make sense to have all the commits individually because they all tweaked 2 or 3 lines of the file. In general perhaps the granularity of individual commits isn’t interesting to people on the base repository and therefore if you can summarise your thoughts into a single commit it keeps it tidier as you say.

  • Rob Hunter

    “I later realised that I could have just passed in the last commit hash from the master to the rebase command”

        $ git rebase -i c4e94f668223d53f6c7364d19aa965d09ea7eb00
    

    You can abbreviate even further, since git rebase accepts any of the many formats (see git-rev-parse(1)’s manual on SPECIFYING REVISIONS).

        $ git rebase -i base/master
    
    

    If your branch uses git’s “upstream tracking” feature, you can abbreviate further:

        $ git rebase -i @{upstream}
        $ git rebase -i @{u}
        $ git rebase -i
    

    Yes, all the way to eliminating the upstream commit reference entirely.

  • http://www.markhneedham.com/blog Mark Needham

    @39e19e0acb0d2809f60f57cec9b50512:disqus nice I didn’t realise you could do that, works pretty well :)

  • Pingback: Git: Commit squashing made even easier using ‘git branch –set-upstream’ at Mark Needham