Post

Git notes

Rebase, don’t merge

Merge commits make history harder to follow and harder to reason about. Merges duplicate commits in the history and make it difficult to know where changes were first introduced. They also tend to lead to nonsensical fixups - for example, fixing merge conflicts in files that have since been removed from upstream.

Rebasing replays your commits on top of upstream. It keeps the history clean and linear. Merge conflicts are possible here, too, but they tend to be real conflicts that need to be fixed.

This configuration option automatically rebases on every git pull, which is useful when you’re working on a branch with other people.

1
git config --global pull.rebase true

Pushing new branches

This is a time saver when pushing new branches.

1
git config --global push.default matching

When creating a new branch, run git push -u origin and git will automatically push that branch to the same name at origin and set it as the upstream branch.

Rewriting history

If you’ve generated a lot of commits that haven’t yet been merged to trunk, you can use git rebase -i to clean up the history of your branch.

1
2
# Replace "main" with your trunk branch.
git rebase -i $(git merge-base HEAD main)

If you want to use VS Code to edit, make sure code is available on your PATH, and then set EDITOR.

1
2
# Replace "main" with your trunk branch.
EDITOR="code --wait" git rebase -i $(git merge-base HEAD main)

Bisect

git bisect is a powerful command to work out which commit caused a problem. It performs a binary search between two commits of your choosing and runs a command you give it on each midpoint.

Check out a commit from e.g. yesterday.

1
git checkout "$(git rev-list -1 --since='1 day ago' HEAD)"

If that commit works, start the bisect process. If it doesn’t work, you may need to go back to 1 week ago or further.

1
2
3
4
git bisect start
git bisect bad main    # Replace "main" with your trunk branch.
git bisect good HEAD
git bisect run         # Followed by your test command, e.g. make

If the test command exits 0, the current commit is marked as a good commit. If it exits 1-127, it’s marked as a bad commit. (Any return code greater than that will cancel the bisect.) git bisect repeats this process automatically until it finds the first bad commit.

Commit messages

Commit messages are the most important documentation you can write. That doesn’t mean they have to be long, but it does mean you should put some thought into how they are written. Teams should consider a clean commit history to be part of the acceptance criteria for a pull request.

A commit log is the definitive record of what changed, when it changed, and provides at least some context into what the author was thinking when they made the change. Commit histories often outlive external ticketing systems and wikis, and are more valuable than fixed documentation, which tends to diverge from reality as time goes on.

In VS Code, use the following command to edit commit messages. The default UI makes it difficult to word wrap or keep track of line length in general. Again, make sure code is available on your PATH first.

1
EDITOR="code --wait" git commit

The subject line is the part of your commit message that will be read the most over its lifetime. Make it clear and concise.

Do:

  • Keep the subject line under 72 characters.
  • Write the subject line in imperative mood. For example, “Add feature”, not “Added feature” or “Adds feature”.

Do not:

  • End the subject line with punctuation.
  • Add tickets to the subject line. Space is precious. Put information like that in the commit body instead - most ticketing software will still pick it up.
  • Add metadata schemes, such as “conventional commits,” to the subject line. These provide no practical benefit and waste space.

Consider:

  • Prefixing your commit with the part of the project you are working on, especially when doing so gives you more space. For example, foo: Add test, rather than Add test to foo. Both are still valid subject lines, but the former can fit even more detail.

The commit body is optional, but is an excellent place to log details you or your team may need to return to later. Commit bodies should word wrap at 80 columns. If you use VS Code, try Rewrap.

Note that each paragraph in a git commit has a blank line separating it, including between the subject line and the body.