Git Best Practices

Why are you being such a git about it?

Git is the most popular source control management system in the world today. Git can ensure your code is backed up and versioned, and also make your work accessible to other developers. If used properly, Git can be so much more than just a way to store or organize your code. Git can help ease complex processes like release management, feature development, and working with multiple people concurrently. 

In his session from the 2021 GitKon Git Conference, Joe Glombek shares his favorite Git best practices. Spoiler alert: it’s OK to be really fussy about how you use Git! That’s actually a good thing. 

Whether you prefer to work in a GUI or CLI, GitKraken Client meets developers where you’re already working, and helps you easily develop effective workflow best practices.

Unfortunately, poor Git utilization is a far more common issue than you’d think. Countless people are using Git as a dumping ground for code rather than a well-managed archive of software.

Here are five simple tips to ensure you’re leveraging Git to the fullest with these Git workflow best practices: 

Tip 1: Commit Messaging is Everything

In the brilliant XKCD webcomic shown below, the writer says “As a project drags on my Git commit messages get less and less informative.”

XKCD comic number 1296 - Git Commit messages over time

We see the comments descend from something as descriptive as “created main loop and timing control” into the absolute anarchy of my “hands are typing words” and “HAAAAAAAAAANDS.” Joe would like to say that this is just a joke in a comic strip, but it can be all too real. 

In another example, he shares what one Twitter user’s actual commit history looked like on a project.

An example commit history with poor commit messages shown in a tweet

Dennis here was investigating an issue by scanning through “useful” commit messages in his Git history. It’s pretty obvious that these commit messages don’t provide enough information to know where to start looking after a bug has been introduced.

Imagine a scenario where you see something odd in the code base and there’s no in-code comment. Using Git blame, you can see who changed it, but you see a commit message that simply says “test.”  Unfortunately, the dev who made the change is out on holiday, so you can’t immediately find the reasoning behind their changes. Now you’re at risk of reintroducing a bug if you change it, or breaking something somewhere else.

Conversely, let’s say you’ve looked at a piece of code that’s changed since you were last working on it, and you’re not happy with how it’s written now. Once again, you leverage Git blame and you see a commit message that says “fixes date formatting issue in chrome.” In this scenario, you better leave it as is.  You’ve actually been saved by a good commit message!

If you want to write a good commit message and follow Git commit best practices, the commit message should be written as if answering the question “what does this commit do?” You can also consider starting your commit message with a verb.  For example ”fixes reverts” or “integrates service.” While that’s great context, it’s not enough on its own, as these short messages still don’t fully tell us what’s happening in those commits.

Detail, Detail, Detail!

GitKraken Client gives you two fields for your commit messages: a title and a description. It’s best to keep your title short, under the 72 character maximum, and add more detail in the description field. 

For example, “Fixes date formatting issue in Chrome” is way better than just “fixes bugs” for the commit message title.  In the commit message description, you can provide even more detail.  In the description, you could say something like: “Chrome always assumes the MM/DD format no matter what locale the browser is set to.” While this is a fictional bug, the example illustrates how much more robust and informative a commit message can be.

Providing more info for Git reverts is also extremely useful. By default, the message generated from a Git revert populates with the commit message title: “reverts last commit message title.” For example, Reverts new “Paytastic Checkout” checkout flow

If we add the description “customer has changed their mind and wants to revert to using LegacyCart” then we have a fantastic overview at the top and much more detail in the description.

Examples of good commit messages with the heading Detail, detail, detail

You can add commit message descriptions on the command line as well.  You just need to pass in two message parameters:

Git commit -m “Title” -m “Description”

Link Commits to Issues

If you have a ticketing system or a to-do list, it sometimes helps to include the title of your item in your commit message or the ticket ID number. You can even provide a link to the initial issue in the description.

Joe Glombek showing how to link commits to issues in an issue tracker using GitKraken Client

If you have hooked up GitKraken Client to an issue tracker, such as GitHub Issues, you can type in the search to find the issue you want to work on, right-click on the issue, and create a Git branch for the issue. It’s very easy to add extra information this way, so when you come back to an issue in the future, you can quickly see everything that happened around that commit. All without context switching between tools! 

Tip 2: Commit and Push, Little and Often

When it comes to how often people should commit, the most persuasive argument is “little and often.” Since Git acts as a backup of your work and progress, there’s no point to only commit when something is feature complete. It’s far more useful to have partially complete work committed than none at all. 

Although it’s good practice to ensure that each commit is in a buildable or working state, it’s okay to have “work in progress” commits that are not ready to merge, as long as you state that in the commit messages.

The “little and often” strategy helps you revert unwanted pieces of functionality as well. It can be a real pain to pull a small chunk of code out of a bigger commit, but a lot easier if you just have to revert that one little change.   

Tip 3: Git Squash 

One downside is that all those “little and often” commit messages can become quite noisy rather quickly. While smaller work-in-progress commits are helpful locally, you don’t want all of those commit messages to show up in the final Git history. One solution to clean up your history is combining multiple commits, which is where the Git squash action comes in. Squashing is part of the Git rebase command. 

GitKraken Client makes it very simple to select multiple commits that you want to combine and right-click to select “squash x commits,” where x is the number of commits you have selected. 

Joe Glombek illustrates what Git squash does by combining 3 commits using GitKraken Client

Be careful not to squash your mistakes! Your mistakes and your reworkings tell a story. They can provide a valuable explanation to a future developer, but also they document your learnings. We should be proud of these because it shows you developing your craft. Don’t hide the mistakes. Use squash to tidy things up, not to sweep things under the rug.

Tip 4: Use a Git Branching Strategy

There are many Git branching strategies out there; while Joe’s personal favorite is GitHub Flow, there are many more. Regardless of which you choose, Git branching strategies generally follow a feature-driven development pattern. You create a branch for each feature you’re working on and then there’s some notion of a state of a particular release. Typically, a Git branch or a tag tells you what was deployed and at what point.

It’s also common to ensure that only one person is committing to any single branch at one time, so if you’ve got two people working on a feature, you might be better off breaking that feature down into sub-features. This allows every developer to do that “little and often” commit strategy effectively.

GitKraken Client has advanced features, like merge conflict detection, which alerts users when two team members are working on the same file at the same time. Collaborating with Git has never been better.

Taking a closer look at the GitHub Flow branching strategy, you will see it involves creating a branch for your feature which is mapped to a GitHub issue. You then add your commits to that branch, open a GitHub pull request, leading to a discussion, and then a colleague performs a code review of your changes. 

You might add more commits, but once that Git pull request process is over, you deploy those changes for testing. Once the testing is complete and everyone’s happy, your code is merged into the main branch.

An example of a GitHub Flow chart

There are arguments for using different workflows and Git branching best practices. Each has advantages to consider. Pick one as your baseline and then adapt it to your organization, to your needs, and to your project. Whatever one you choose, it is critical to have a branching strategy.

Tip 5: Use Rebase and Merge

On larger projects with multiple concurrent workflows, you can end up with a tangle of branches and merges. Branches become interlinked with each other and it can be quite hard to follow what’s happened. GitHub actually provides three options when you create a pull request:

  1. Create a merge commit
  2. Squash and merge
  3. Rebase and merge
The 3 default GitHub Pull Request options to Create a merge commit, Squash and commit, or Rebase and merge

The “create a merge commit” is fairly self-explanatory. If the pull request is successful, just merge the suggested branch with its changes directly into the specified target branch.  This is the simplest option, but it leaves the messiest history.

The “squash and merge” option means your entire feature gets squashed into one commit and then plopped straight onto the main or developed branch. While it’s very neat and tidy, you lose a lot of the documentation of when, how, and why code changes were made. This makes reversing changes very difficult and it’s harder to see why something might have happened.

The “rebase and merge” option allows you to avoid losing data while keeping the tree clean and tidy. This is Joe’s favorite option. Note that if you’re using Azure DevOps, this option is called “semi-linear merge,” but it generates the same result.

An example of Rebase and merge strategy

You can jump to 22:26 in the GitKon session video to hear Joe give a more thorough explanation of this option.  

Rewriting History

For tips four and five, you are rewriting history, not as an act of whitewashing historical atrocities, but simply changing what’s been pushed to the Git repository. Maintaining your true history certainly has its merits, as it can be useful for learning and for code reviews. It is also impossible to really mess up your history if you never tamper with it. However, know that this approach comes at the cost of repo readability in the long term. A quick tidying up process makes for a cleaner history overall.

Pushing Your Rewritten History

The key to rewriting history safely is to make sure you’ve pushed your repository before you start messing with history. This ensures you’ve got your backup on an external server, and it gives you a way to double-check before you push. It’s important to note: because you’re changing history, you will have to perform a force push. If you’re using GitKraken Client, you will receive a helpful pop-up with a little warning, making sure you really want to do a force push rewriting history.

GitKraken Client makes it easy to see your Git history, make and amend Git commit messages, squash commits, and leverage Git to make your commit history the best it can be.  Be like Joe and be a real git about your Git history, and use GitKraken Client to make it easy and safe to use the advanced functionality of the world’s leading version control system.  Download GitKraken Client free today!

Make Git Easier, Safer & more Powerful

With the #1 Git GUI + Git Enhanced CLI

Visual Studio Code is required to install GitLens.

Don’t have Visual Studio Code? Get it now.