git squash all commits into one and merge back into master with rebase and merge –ff-only

This is my workflow.

Work in a remote branch:
git checkout -b topsecretbranch

Make lots of small iterative changes, committing each one with vague messages like “small changes”, “typos” and “lol”.

At some point this code will be ready to merge back into master. Instead of polluting the commit history with confusing and unhelpful commit messages, first use rebase to squash all the changes into one.

Let’s say there were 4 commits. Then first rebase from master:
git rebase master

This will pull in all the commits from master first, without the messy merge commits that “git pull origin master” generate.

Next, squash all commits with rebase in interactive mode. Let’s say there are four commits you want to squash:
git rebase -i HEAD~4

This will open up a text editor (default VIM). Pick the commit you want to keep (usually the top one), and replace “pick” with “s” (for squash) for the rest. For example:

pick f96d52f Add new API endpoint
 s 7247ac7 add test
 s 62c7c02 fix test
 s d38ca5e typos
 Rebase 758eaa1..890aff7 onto 758eaa1 (4 commands)
 #
 Commands:
 p, pick  = use commit
 r, reword  = use commit, but edit the commit message
 e, edit  = use commit, but stop for amending
 s, squash  = use commit, but meld into previous commit
 f, fixup  = like "squash", but discard this commit's log message
 x, exec  = run command (the rest of the line) using shell
 b, break = stop here (continue rebase later with 'git rebase --continue')
 d, drop  = remove commit
 l, label  = label current HEAD with a name
 t, reset  = reset HEAD to a label
 m, merge [-C  | -c ]  [# ]
 .       create a merge commit using the original merge commit's
 .       message (or the oneline, if no original merge commit was
 .       specified). Use -c  to reword the commit message.
 #
 These lines can be re-ordered; they are executed from top to bottom.
 #
 If you remove a line here THAT COMMIT WILL BE LOST.
 #
 However, if you remove everything, the rebase will be aborted.
 #
 Note that empty commits are commented out

Save the changes. This will now pop up a new text editor window where you can edit the commit messages. I usually just keep one around and delete everything else. Once this is done, checkout master:
git checkout master

Now merge changes using fast forward only (skips the confusing merge commit):
git merge topsecretbranch –ff-only

Done correctly, you will have one clean commit in master branch of all your code changes.

Caveats – if you’ve already pushed your remote branch to origin, and you want to squash the commits in your branch be reflected in the remote as well, you’ll have to do a force push

Leave a Reply

Your email address will not be published. Required fields are marked *