Git Cheatsheet Prime

October 13, 2024

I’m an enthusiast and daily user of git’s command line interface 1. While GUIs offer advantages in visualization and intuition2, they greatly fall short in power3, concision, and extensibility.

Like vim, learning to use git (or any other CLI tool with lots of input options) has a steep learning curve4 and many little shortcuts and conveniences that left out of tutorials and references5 (because they’re not necessary for baseline usage), and thus never learned6.

This post (much like my vim one) includes the git subcommands (and options) I use on a regular basis, and their abbreviations (bash aliases) (which is how I use them).

I don’t claim to be a master of git, and this list is far from complete, but it offers a wider range than the github one, and can be used as a richer starting point (for beginners) or as a sparse expansion pack (for everybody else).

I intend for it to evolve over time, as I uncover better ways of doing these things.


Commands

Commands With Abbreviations (The Most Frequent Ones)

(Key:

)

Other Commands

Idioms

Tricks

Locally ignore a file that is tracked by git:

Setting up worktrees for a repository:

Revision Specifiers

(the docs for this have a pretty low opportunity cost)

An elucidating example of ^ and ~ from the docs:

G   H   I   J
 \ /     \ /
  D   E   F
   \  |  / \
    \ | /   |
     \|/    |
      B     C
       \   /
        \ /
         A
A =      = A^0
B = A^   = A^1     = A~1
C =      = A^2
D = A^^  = A^1^1   = A~2
E = B^2  = A^^2
F = B^3  = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2  = B^^2    = A^^^2  = A~2^2
I = F^   = B^3^    = A^^3^
J = F^2  = B^3^2   = A^^3^2

Ranges


The following git_alias function lives in my bashrc. It sets up a bash abbreviation with git tab-completion. There’s probably a cleaner way to do it, but this works.

#!/bin/bash
git_alias() {
    alias "$1"="git $2"
    if (($# >= 3)) then
        __git_complete "$1" "$3"
    fi
}

git_alias g "" __git_main
git_alias gs status _git_status
git_alias gd diff _git_diff
git_alias gds "diff --staged" _git_diff
# ...

  1. This is far from abnormal: I don’t know the numbers, but I’d venture to say that git is the most popular version control system, and that a large percentage of developers use it through the command line (as opposed to some GUI). ↩︎

  2. (I’d even go as far as saying they’re better for certain operations, like staging files and resolving merge conflicts). ↩︎

  3. Namely range (sheer number) of possible operations. This is an inherent flaw of GUIs (and, conversely, an inherent power of CLIs): the screen space used for visualization (and the necessity of using visuals) directly impedes the speed and efficiency at which the user can communicate intent. For example, most GUIs use tabs and dropdowns to allow a wide range of possible user inputs. This is usually clumsy, and will never beat the speed of using a keyboard. One possible solution to this is using keybindings with modifier keys (e.g. ctrl, alt, meta, …). Vim takes this a step farther by avoiding the modifiers; it’s an extreme measure to allow the simultaneous use of visuals and rich user input. ↩︎

  4. As mentioned in the above footnote, the power of CLIs comes from the fact that they don’t use visuals (the input is shaped in the mind of the user), so this learning curve is (in some ways) a necessity for power and speed of input. ↩︎

  5. For example, the popular github git cheat-sheet (this post is meant to serve as an alternative to it, hence the title). ↩︎

  6. Or, more accurately, learned very slowly over time, with many remarks like “I can’t believe I’ve been doing it this way all this time”. ↩︎

  7. I feel pretty strongly about this, because it (1) shows the files changed, branch, conventional commit message max line width, (2) allows an abort, (3) escapes special charcters, which would cause problems on the cli (even between double quotes), e.g. backtick, (4) makes multi-line messages easier to write, and (5) perhaps most importantly, is vim. ↩︎

  8. Technically the .. involves a set difference between reachable commits from the lhs and rhs, but I primarily use this for cherry-picking linear ranges of commits, so I think of it as a range (also note that the ^ is independent from the ..). ↩︎