I often help friends who are new to using git with using it. This blog post is going to serve as a single link to share with them, instead of trying to find individual links over and over.

Understanding Git

I got started with using git after using svn and hg for a few months. But, I would often be lost in the myriad of command line options, putting myself in situations I couldn’t come out of without some scars. I didn’t really understand how git worked, and that was the real problem.

Improving my mental model of how git works, and then trying to fit the commands into this mental model is what made git finally click for me. The Git Parable really helped me understand git from the inside out, and gave me a much clearer mental model of git. There was no looking back from there.

If parables are not your thing, and you’d rather read something that takes a less flowery and more straighforward approach to explaining these concepts, I really liked John Wiegley’s Git from the Bottom Up.

Day-to-day git

Zulip (an open source group chat application that I spend a lot of time contributing to) uses a rebase-heavy workflow, where good commits are merged from different PRs, as and when they are reviewed, instead of waiting for all the commits in a PR to be good to be merged. Developers often have to pull from branches that have been force-pushed to, rebase their commits, squash commits, learn to change git history, etc.

Zulip’s Git Guide is top-class documentation that gives guidelines on using git from a practical stand-point. A lot of new developers use it to get upto speed with Zulip’s workflow that involves a lot of things that I’ve seen devs who have been using git for many years struggle with.

The section on pull request workflow is quite helpful, and should work reasonably well for contributing to other FOSS projects too.

I also like the sections with recipes for common git history edit actions, and the troubleshooting section with recipes to get out of common troublesome situations. Oh shit, git! is a very similar resource to this, that has a bunch of useful “recipes” to recover from different scenarios.

Julia Evans’s exercises approach to learning to explore a git repository is quite interesting, though I haven’t run through all the exercises myself.

Git as a communication tool

I like to look at git history as telling the story of evolution of a code base. The advice that is sometimes given to writers about doing the hardwork, so that the readers can do less of it, holds true for git history too. Communicate the story as clearly as possible for your readers to understand, and don’t just publish a “stream of consciousness” piece.

What does this mean in practical terms, though?

I think editing git history to present a clearer story is completely acceptable. If one tries a handful of different things, and then finally finds the solution to do something, it’s not necessary to have all the failed attempts as commits. Just the final approach can be a commit/pull-request, while documenting the other approaches the commit message or as a comment in the code, if that makes sense.

Expect your collaborators (including future you) to look at not just older versions of code, but the commit history for understanding how a piece of code evolved, for undertsanding the history. Make your git commit messages as useful as you can. Writing a good summary line goes a long way in understanding a change. In most cases a body would be useful to explain the how and the why of the change, while the summary line explains the what.

I like this commit discipline that the Git project itself uses, and was adopted by the Zulip project: “Each commit is a minimal coherent idea”. Simply put, you want each commit to be such that they can be can be deployed (and/or reverted by itself), without depending on any other commits alongside them. You can read more about what minimal and coherent mean in this context in the Zulip documentation.

Tools for Git

Some of the confusion in using git even after understanding how it works is the inconsitent CLI API that it often exposes. There has been some work going into this, to make this more consistent. But, using a nice client can help with this. I use the excellent Emacs client for git called magit. It is an intuitive UI on top of git's data model, that allows me to do things that I commonly want to do, with just a few hot-keys, instead of typing out elaborate recipes to do things. I highly recommend it, if you are an Emacs user.

It is also helpful to change you shell’s prompt to tell you more about the status of the current directory’s repository. There are a bunch of configurations out there (Stackoverflow, Gists, etc.) that let you do this. The git repo itself comes with a prompt customisation. I like being able to see at least the current branch and dirty/clean state of the repo.

Here are some simple changes to the global git config, off the top of my head. These could make your git workflow more pleasant.

[push]
  # Push to the branch to the same remote branch as the one we are working on,
  # locally. This is the default in Git >= 2.0, so you may not need to set it.
  default = simple

[diff]
  # You could configure a GUI tool to use here. (I haven't used one in a long
  # time, and I don't have recommendations on what to use)
  tool = icdiff

[merge]
  # Shows common ancestor in a merge conflict. Makes it easier to understand
    # the conflict and merge, for me.
  conflictstyle = diff3

# Never garbage collect commits/blobs that are unreachable
# The cost of keeping this data around is negligble compared losing data
[gc]
  reflogExpire = never
  reflogExpireUnreachable = never

Outro

If you have other recommendations or tools that you’d like to share with me, please do! Using git better, and understanding it better, is something that I’m always excited about. I’d also be happy to answer questions, or help you with specific things that you are trying to do with git.