The problem: Git experience required

One common situation I face when working with platform teams is the huge variation in the individuals' Git experience. Git experience, although common for developers, is far less common for those with more traditional infrastructure or operations backgrounds. And this makes sense, because source control has historically been used by software developers when they write code. "Configuration as code" is still new.

The breakdown of experience tends to be something like this:

  • Some have used it a little and know enough to be dangerous
  • A few are experts
  • Most have not used it and are scared of it

Often it is required to grow someone's Git knowledge from zero to "highly functional in a collaborative team environment". To make matters worse, this growth must happen in a short amount. Even under ideal circumstances, Git is not an easy tool to learn. Combine this with the existing cognitive load (from learning the numerous other new tools thrown their way) and the typical short duration project time pressures, and the result is an extremely poor learning environment.

Git 101 - a simple, structured solution

On a recent engagement, we tried a more formalized approach of teaching "trunk-based development" with Git in a simple way. Although I had been doing this informally for a while, this time it was written on the whiteboard under the heading "Git 101".

To put it simply:

Git 101 provides just enough Git to enable a team of multiple engineers to work collaboratively on different streams of work and minimize distracting Git traps.

This post is written for those who are already familiar with Git, but desire a focussed approach for teaching it in a short amount of time.

The best part of Git 101 is it can be tactile:

  • you can write it down
  • they can write it down
  • you both can point at it as you do the steps
  • (most importantly) it will be there when you leave

Overview

There are only 5 major commands. 2 are nearly identical. They are executed roughly linearly.

  1. git pull
  2. git add
  3. git commit
  4. git pull --rebase
  5. git push

Some noteworthy omissions

You may notice an absence of some informative (minor) commands like git status, git log, or git diff. That is intentional.

There is an expectation that you will use these minor commands (when appropriate) in between each major step. In addition to being useful commands in the own right, they are essential for explaining key concepts liked tracked/untracked files, staged/unchanged changes, and being ahead/behind of origin.

Following the steps

What I'd like to do next is run through the steps and expand upon each one. I'm assuming you already have a remote repository cloned locally and you are working from master branch.

1. git pull

Before making any changes, start off with a git pull. This will make sure any new upstream changes are already in your local repository before making any commits. This lessens the magnitude and likelihood of a conflict during the later git pull --rebase.

Now you do some work!

2. git add

After finishing the work, run a git add to stage the important changes (emphasis on the important). It may be tempting to stage all the changes with git add . or git add -A but I promise you this won't end well. There will be pain, there will be tears. Remember, this is Git 101.

Be explicit about exactly which changes will be added.

At a minimum, use git add <file_path> to stage everything in a file, and not everything in the directory tree. I will start with this.

Ideally you will want to be even more explicit and use:

  • git add -N <new_file_path> to start tracking a new file excluding any file contents
  • git add -p to perform hunk-by-hunk staging (in a very code review style)

3. git commit

Once the changes have been staged, it's time to make the commit. Committing with git commit -m "<message_goes_here>" works great - giving the illusion of a one line command encourages brevity whilst avoiding a vi session, which can confuse some.

At first I won't focus too much on commit message content. After a few iterations, I'll start to focus on it more. Valuable commit messages add context to the commit content with information not contained within the commit itself. For example, the message "Added vars.yml" adds no context, because that is easy to see in the commit. Instead, focus on why this commit happened - was it related to something bigger, was it related to a story (with an ID), etc.

4. git pull --rebase

Once the commit is ready, you are almost ready to push. Almost. Someone else has probably pushed a commit since you started work. This is where git pull --rebase shines.

By running git pull --rebase next, you effectively:

  1. Take our new commit off the top of master
  2. Pull down any upstream changes
  3. Put these upstream changes on top of master
  4. Put our new commit on top of the inbound changes

More succinctly, any upstream commits are placed in between your new commit and the previous commits. A picture is worth a thousand words here, so draw one!

This adds a good amount of value. This prevents any "merge commits" and keeps the commit history clean and linear. This buys time to teach merging later on. The worst thing that can happen is a conflict. The best thing that can happen is nothing!

5. git push

Now that your local repository is fully up to date with origin (or "we have all the commits that are on BitBucket/Github") you can push the new commit. This step is pretty straight forward.

Maybe this step fails because the rebase during git pull --rebase took some time, and someone else pushed to origin in the interim. If this happens, just run another git pull --rebase and then try pushing again.

Just a foundation

That is it. That is Git 101. There are many commands you might want to add. Critically though, there aren't any commands you can remove and preserve functionality. Well, maybe the first git pull, but I think it's a valuable addition.

Now, you have a solid foundation to introduce more advanced concepts. There are many directions you could go, such as introducing multiple commits and squashing, feature branches, WIP branches, Git implementation details, etc. The point is, instead of leading with these concepts, you start with a simple foundation and iteratively add complexity.

Git 101 gives you a foundation to build upon, so that you can successfully introduce Git based source control to anyone.