How to squash git commits

featured_image

If you use git to secure the outcome of your work frequently, the code responsible for one functionality may be scattered  across many commits within a feature branch. You can still commit a unit of work as a whole even if you pushed it to the origin in several stages.

Requirements

  • The familiarity with Gitflow Workflow – we are working on a local feature_branch, all work is done only within this one branch and there are no commits or partial merges on the develop.

Squash commits during a pull request

When using a tool like BitBucket, commits will be automatically squashed during a pull request with a message that lists all integrated commits.

It may be just enough if you didn’t have to push the work half done at the end of your work day and complete it in another commit. We want to be able to keep the app working properly even if there is a need to revert some commits. We should never encounter the moment in the git history when the app is broken.

Do not rewrite the git history if there are other programmers working on the branches affected.

Squash latest commits

If you want to compress 3 latest commits on your local feature_branch, reset the HEAD:

Now all the changes from those 3 commits awaits to be aggregated into one:

To fix the inconsistency between local and origin push the repo with the --force-with-lease option to be sure that you will not interfere with somebody else’s work:

The feature_branch has squashed commits and the git history is the same in both local and remote repositories. You can continue your work on the branch and merge it with develop when you are done.

Squash only selected commits

You are on the local feature_branch, it’s late Friday afternoon and there is no way you will finish the task. You want to save what you did so far, even though the app crashes, so you commit and push on the remote:

On Monday you add the missing code and the app is again working properly, so you make another commit:

And then you add something more to the branch and commit it as well:

The history of the branch looks like this:

If necessary, you need to be able to revert commits safely – it happens only when every one of them keeps the app in a working condition. Therefore you need to squash Work - part 1 and Work - part 2 into one commit and keep the rest as it is.

We want to keep all commits before Work-part 1 intact, so we will rewrite the history only within the three latest commits:

The rebase editor displays specified commits ordered from the oldest to the newest:

Rebase will squash a newer commit with the older one. Just write squash instead of pick in the lines of commits you want to integrate with the preceding one. In our example we want to keep together Work - part 1 and Work - part 2 so we will put squash only in the line with Work - part 2:

Save changes and exit the rebase editor. After that you will be able to write a new commit message for both squashed commits in a commit editor:

Specify the new message and comment the one that is no longer needed:

Save the changes and exit. Now the git history looks like this:

If you want to keep the original commit message “Work – part 2.” use fixup instead of squash:

and the git history will look like this:

Too keep the local feature_branch compatible with the origin, push the branch with the --force-with-lease option to be sure that you will not interfere with somebody else’s work:

You can find useful info in this git ready post.

Forgot to add something to the latest commit?

Instead of committing the forgotten changes and squashing the commits, you can change the latest commit with --amend. Just add the remaining files with:

  •   $ git add -A (all remaining files)
  • or  $ git add file_name  (a specified file)

and run:

The latest commit contains the previously added files and the new ones like they were committed together in one action. The --no-edit option leaves the commit message unmodified.

You should always have a very good reason to rewrite the git history and be sure that nobody from the team will be affected by conflicts when you decide to do this.

Merge feature branch to the develop in one commit

If you are going to merge the feature_branch to the develop branch, you can make it in one commit – use the --squash option:

The feature_branch still has multiple commits, but, if you delete branches after they are merged – there is no need to fix the inconsistency.

Photo by Jason Blackeye on StockSnap

Leave a Reply

Your email address will not be published.