GIT Squashing and open source contribution

Never thought that GIT squashing would be that important for the open source contribution. I was contributing to an open source project. I finished the feature and created a pull request. Surprise!!! the community didn’t accept my pull request. Okay. … It was not rejected because of my wrong implementation or bad code. It was rejected just because of my commit history.

So, in the open source project, this is kinda common practice to use one commit message per feature/branch per push. It actually makes sense when you look at the commit history of an open source project. Nobody wants to see your code noises in the commit history. Basically, you will have to squash multiple commits into one commit before creating pull request.

What is GIT Squashing?

Normally, we do commit as we progress.  But, we don’t want to push all of them into the repository. GIT squashing compress down multiple commits into one single meaningful commit. Sometime, we do some unnecessary commits or we find some commits that should be belong to the same logical change-set. GIT squashing enables rewrite the history by keeping one commit message,  and squashing those subsequent commits into the previous one.

In this tutorial we will use GIT interactive rebase command for squashing. We will use squash and fixup.

  • squash (s for short), which melds the commit into the previous one (the one in the line before)
  • fixup (f for short), which acts like “squash”, but discards this commits message

Let’s go through an example. We have five commits in log history.

bbf19a9 my 1st commit
9added2 my 2nd commit
1a8482a my 3rd commit
68782bd my 4th commit
3c9956e my 5th commit

We want squash the last three commits (3c9956e to 1a8482a) into the first commit (bbf19a9 )and discard the forth commit from the last (9added2). You need to run the command: interactive (-i for short ) rabsae

git rebase -i HEAD~5

It will show a list of each commit  as below in your default git editor (either nano or vim)

pick bbf19a9 my 1st commit
pick 9added2 my 2nd commit
pick 1a8482a my 3rd commit
pick 68782bd my 4th commit
pick 3c9956e my 5th commit
 
# Rebase 187a597..3c9956e onto 187a597 (5 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
# d, drop = remove commit
#
# 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

The above screen already describes with all the options and what exactly you have to use based on our requirement. In our case, we use squash and fixup.

pick bbf19a9 my 1st commit
fixup 9added2 my 2nd commit
squash 1a8482a my 3rd commit
squash 68782bd my 4th commit
squash 3c9956e my 5th commit

You can also use s as short for squash and f as short for fixup.

Save and exit the editor. It will show another screen

# This is a combination of 5 commits.
# This is the 1st commit message:
 
my 1st commit
 
# The commit message #2 will be skipped:
 
# third commit
 
# This is the commit message #3:
 
my 3rd commit
 
# This is the commit message #4:
 
my 4th commit
 
# This is the commit message #5:
 
my 5th commit
 
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sat Nov 11 18:29:04 2017 -0500
#
# interactive rebase in progress; onto 187a597
# Last commands done (5 commands done):
# s 68782bd fifth commit
# s 3c9956e sixth commit
# No commands remaining.
# You are currently rebasing branch 'master' on '187a597'.
#
# Changes to be committed:
# modified: indext.html
#

The above screen describes what would be your new modified and composite commit message. You can leave as it is or you can write your new commit message. If you leave as it, all commit messages will appear except the commit: my 2nd commit.

If you check git log, you will get one commit with all of your changes

git log

When you shouldn’t do this?

Don’t sqaush or rewrite the history if they have been already push to public repository.

Some developers have different thought, they don’t like to squash because the commits are well-structured a series of commits which represents a logical series of meaningful changes. The main trick is not squashing everything into one gigantic commits, rather clean up or remove the unnecessary commits from git change history.

Tips:

1. To halt the squashing middle of rebase, simple run this command: git rebase --abort
2. To see git log in a cleaner way: git log --pretty=oneline
3. To rewrite the commit message, use reword rather than squash or fixup.
4. Just to change the last commit message: git commit --amend

Helpful links:

https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History
http://stackoverflow.com/questions/2563632/how-can-i-merge-two-commits-into-one

 

Eftakhairul Islam

Hi, I'm Eftakhairul Islam, a passionate Software Engineer, Hacker and Open Source Enthusiast. I enjoy writing about technical things, work in a couple of startup as a technical advisor and in my spare time, I contribute a lot of open source projects.

 

Leave a Reply

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

 

Read previous post:
Transfer tokens from orderbook.io to MyEtherWallet (MEW) wallet

It's always suggested to transfer tokens to a new wallet that supports ERC20 tokens. MyEtherWallet (aka MEW) is an ERC20-compliant...

Close