Most of you are coming in with at least some basic familiarity with Git, but the way we use Git is sometimes surprising and different than what you've seen before. Git can do a lot of different types of workflows, and if you mix and match different techniques, it's easy to get yourself into a big mess. This page includes some general concepts and some specific tricks for keeping your repository ship-shape.

Know your branch

When you begin a new project (whether it's a simple bugfix, or a giant, semester-long feature), you'll start by creating a new branch for your work, often called a "topic branch" or "feature branch". To start with, you'll want to make sure that your current checkout and environment is targeting the correct release branch (see Branches and Compatibility). The name of your branch is purely local, but make sure it's something useful and meaningful to you. It's best to prefer good descriptions (bug-12345 or fix-attachment-captions) over quick ones (fix or asdf).

<aside> ⚠️ Make sure that you always have a local feature branch any time you want to do a commit. You should never commit directly to master or one of the other public release branches.

</aside>

When it comes time to do anything that might affect the commits (such as staging or committing changes, or pulling new commits from the central repository), make sure that you know what branch you have checked out. It's surprisingly common to commit or pull to the wrong branch, and disentangling that later can be difficult. Many people find it helpful to configure their shell prompt to show their currently checked-out branch.

<aside> ⚠️ Just like we never want to commit to upstream branches, we never want to pull into local branches. Before you pull, make sure to check out whichever release branch you initially were on. You can then rebase your feature branch onto the latest branch head.

</aside>

If you have multiple changes in-flight, always make sure you're working on the right feature branch.

Avoid merges (unless you're really careful)

Merging in Git is an incredibly powerful tool, but like most powerful tools, it can also get you into big trouble. One of the most common causes of trouble is when people do either explicit merges (git merge) or implicit (git pull when you have your feature branch checked out).

If you want to update your code to be based off the latest upstream, the best approach is a pull and rebase:

  1. Check out the upstream branch which you initially branched off (for example, git checkout release-4.0.x)
  2. Get the latest code from upstream (git pull)
  3. Rebase (git rebase release-4.0.x mybranch)

During the rebase, you may be asked to fix any conflicts. It's generally good practice to do this every week or so to avoid having the upstream code diverge too much from your work. A lot of small, tiny conflict resolutions are a lot easier than one big one.

<aside> 💡 If you are collaborating with someone else by pushing branches to a shared repository, you may need to use merge to get the latest upstream code into your feature branch. Even then, you may want to consider a squash/rebase before finalizing any review requests or landing any changes.

</aside>

Keep your commits clean

Rebasing goes a long way toward keeping a clean tree, but there are some other techniques that help too. The basic Git workflow suggests making new commits any time you want to save your work, but that tends to result in commit histories that are full of a lot of tiny fix-up commits. When a commit history is full of these, it makes it really difficult to keep track of all your changes.

We're big fans of rewriting commits as we iterate on changes in order to have a 1:1 mapping of commit to task. It's also a good idea to write your commit messages carefully—by default, those will repopulate the fields of the review request, and it's much easier to keep track of everything that's in each commit when your commit messages are fleshed out. There's a lot of detail on how to do all of this at Keeping Commit Histories Clean

A repository viewer that allows you to see the commit DAG can be very useful, especially when you start juggling a dozen branches with various dependencies.