Software Development

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.

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: The Linear Git History

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button