The Linear Git History

A lot of teams follow these rules. The question is why!?

The rules are:

  • Use GitHub flow – i.e. master is the stable trunk
  • Everything else should be a feature branch
  • Feature branches are merged to master with pull requests
  • No matter how many commits are made to achieve the last HEAD of a feature branch, they should all be squashed into a single commit before merge
  • The merge should be made after a rebase and retest of the feature branch – in other words, merge only one-commit-from-HEAD-of-master
  • Depending on the team the merge itself might then be:
    • A fast-forward-only on master
    • An actual merge (even if fast-forward is possible, which it must be)

This leads to a git history which looks like a straight line with no weird crossing of the streams. In the fast-forward-only approach, it’s like there were no branches. In the merge approach, there’s a series of detours in the commit history, showing the vestigial remnant of the branch that existed.

But Why?

Why are we doing this? Especially since the rebasing and retesting can be very time consuming:

  • Genuinely testing the commit that will exist on master before it reaches master
  • Make easily revertible changes
  • Explain the history to people reviewing the code after the event

Of these, the most important is probably the first. Though some build systems cheat and perform a secret merge before they build, the problem with a working branch and a working master is that the intersection of them isn’t necessarily a working master. It could be, but it might not. Merge conflicts alone are not enough of a measure of likelihood of success.

Forcing ourselves to retest the merge before it becomes the head of master is a very good idea.

But there’s more?

Why Rebase not Merge Though?

Git will let you spaghettify your merges and connect lots of dots together. You can become inured to resolving merge conflicts, only to do it again next time.

Merges have their place, but rebasing is a cleaner way to rewrite the history where there’s everything that’s gone before and then plus my stuff. That’s much easier to reason with.

When there’s been a spaghetti festival near the HEAD of master and there’s need for a revert, it becomes quite difficult to know what to revert to what, and how to get things back into a clear state.

The ideal revert involves resetting master to a state where the offending commit is no longer in the code base, and then dropping that commit into a fresh feature branch for its authors to review in order to work out how to fix it. Doing that from spaghetti is relatively insane.

Similarly, for telling the story of how the code was evolved, the long cross lines of merges from around the tree may tell how hard it was, but don’t really explain the intent of the increments. Simple individual rebased commits do.

TL;DR

Keep your git commit history idealised and it will always help you.

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s