Git Best Practices

Here's a list of Git version control best practices I recommend.

Staging changes: git add -p and git diff --cached

Use git add -p to stage changes to commit. It displays each change individually and asks whether to include this part in the commit or not. It thus gives control of the contents of the commit.

Similarly, use git diff --cached to review the staged changes before committing.

I'm a big fan of both methods. They force me to code review my own commits and make sure there is no commented out code and no spurious whitespace or formatting change. More importantly, this approach finds countless bugs! Re-reading the diff is a great opportunity to ask questions like "is this really correct," or "does it cover all corner cases."

Rewriting history: git commit --amend

When discovering a problem with the most recent commit, make your changes, stage them, and use git commit --amend to fix the problem directly in the previous commit. This helps to keep a clean history.

A note on changing history in git: Altering commits that were already pushed to others is considered a bad practice, because it breaks work that others might have based on top of the now-obsolete commit. In most situations, I agree with this assessment. However, the risk is manageable when you're working with a small team. Especially for feature branches that are unlikely to be the basis for further work, I tend to advocate rebasing / amending pushed commits to keep a clean history. Just make sure that it's OK with the team.

Rewriting history: git rebase -i HEAD~10

Interactive rebasing allows reordering or fixing past commits and generally reworking recent commit history. See the Git documentation on rewriting history for in-depth explanation.

The HEAD~10 part tells git to look at the 10 previous commits, which often is a sensible default.

Also note the "changing history" section above.

Atomic commits

Commits should contain one logical change. Avoid having multiple, independent changes in a single commit. Why? It's easier to review and understand multiple smaller commits than one big commit. It's easier to merge commits together than to split one big commit. If bisecting found that a bug originated from a commit, it's easier to identify and fix the issue in a small commit than in a big commit.

git add -p is great for creating atomic commits from a source tree that already has several changes.

Commit messages

Three key points:

  • Form: Write a proper subject line, separated by a blank line from the rest of your commit message.
  • References: Include a link/ID of the relevant task in your ticket system.
  • Content: Write for your future self. One year down the line questions like "why did we want this / why did we choose this particular approach / what alternatives did we consider" are going to come up. Between your commit message and your ticket system task description, you should be able to answer those questions.

Git branching patterns

The branch structure of a git repository should adapt to the development activity:

  • If several people work on the same repository at the same time, you'll need feature branches.
  • If you have to support several releases in parallel, you'll need release branches.
  • If you need frequent updates of your releases, you might need hotfix branches as well.

The large number of branches created with these schemes is unavoidable in heavily used repositories. However, the added complexity makes the commit history hard to understand.

For less active repositories, such as small tools or legacy software, simpler approaches are better suited. Often a single main or master branch together with occasional feature branches is enough.

 

If you have other Git best practices to include, please comment below.

published October 04, 2022
tags git