One commit feature branch using Git squash

Default featured post

One commit feature branch using Git squash. Squashing commits is a dangerous yet lovely feature of Git. It is dangerous because if we are not sure what we are doing or being careful about it, we can screw up the entire repository or at least cause some code loss.

Lovely, because it’s handy to keep commit history tidy by squashing commits into one. This is necessary to avoid Git history hell.

Git housekeeping is necessary when working on big projects with big teams. A good way to start is to keep the commit history tidy. This allows anyone in the team to look at the commit history and understand what is going on.

This is especially very crucial when debugging a code. Surely, we don’t want to go through commit history like below:

~ Initial commit for feature X
~ More functionality for feature X
~ Fix NPE related to class X in feature X

Messages like above make developer’s life miserable. Scattered commits related to a feature, make it difficult to revert the code for whatever reason.

One may argue that we don’t need to revert a feature if we put it behind a toggle switch. That’s correct most of the time. But sometimes a feature cannot be put behind a toggle because it’s tightly coupled to the codebase (Yes, we know it’s a bad thing). A security-related change could be a good example where feature toggle is not applicable. Hence, sometimes a feature needs to be reverted.

If the developer is not around and there is a high urgency to revert a feature, feature X in the above example, going through a messy commit history and find out what to revert one by one is counterproductive.

One approach to avoid such a problem is to squash all commits related to a feature in a single commit when creating a pull request. This is usually referred to as “one commit feature branch”.

Keep note that, one commit feature branch does not stop us from committing often. We should still keep committing code often but before opening a pull request we squash all commit to one.

Doing so, firstly, makes reviewers happy. Secondly, if needed, the feature can be reverted easily.

Enough talk, let’s get our hands dirty.

Assume we want to work on feature X and then create a pull request for the team members to review it.

First, we need to branch out from master and push the new branch to upstream like this:

$ git checkout master
$ git pull
$ git checkout -b feature-X
$ git push -u origin feature-X # pushes the branch to upstream

Then we keep working on our brach, feature-x.

$ git add setup.py
$ git commit -m "Initial commit of feature X" # commit #1
$ git push

$ git add setup.py
$ git commit -m "Fix the DateTime bug" # commit #2
$ git push

$ git add configuration.py
$ git commit -m "Put the feature behind the toggle" # commit #3
$ git push

$ git add configuration_test.py setup_test.py
$ git commit -m "Add unit tests" # commit #4
$ git push

Notice that we committed four times while working on the feature X.

Now, we need to squash all the commits into one to keep commit history clean and everything perfect.

To squash all commits, first we need to update the master branch in local because other developers might have committed something. After that need to rebase the feature-x branch by the number of commits we made, here is four.

Putting together what said in Git commands terminology would be something like below:

$ git checkout master
$ git pull
$ git checkout feature-x
$ git rebase -i HEAD~4 # number could be different depends on how many commits you made. It always should be committed count

Just, we need to keep the first commit untouched and then change the other commits from pick to fixup or simply f. Then save and quit.

We also want to amend the first commit message,

$ git commit --amend

Once we have done with the new message, we save and quit from the editor.

The last step is to force push the changes to upstream. This is because we’ve overwritten the history and now the branch diverges.

$ git push -f

If you are new to git rebase, we highly recommend to first branch out from your feature branch and all rebasing there. Once you ensured everything is safe then remove the old feature branch. Otherwise, you may end up losing some of your precious codes.