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:
bash_alias
—full_command
— explanation
)
gs
—git status
— ubiquitousgd
—git diff
— diffgds
—git diff --staged
— sanity-check after stagingg
—git
— saves two keystrokes for non-abbreviated commandsgb
—git branch
— ubiquitousgbd
—git branch -d
— delete a branchgbdf
—git branch -D
— force-delete a branchgsw
—git switch
— switch to given branchgswc
—git switch -c
— create a new branch and switch to itgsh
—git show
— shows a commit’s diff (…sometimes)gc
—git commit
— list commit historygca
—git commit --amend
— create a new commit off ofhead^
, including the changes inhead
gl
—git log
— ubiquitousglg
—git log --graph
— ascii commit graphglgo
—git log --graph --oneline
— ascii commit graph, minimal boilerplateglmd
—git log --remerge-diff
— ascii commit graph, minimal boilerplatega
—git add
— ubiquitousgai
—git add -i
— interactive add (add partial files)gp
—git push
— ubiquitousgpff
—git push --force
— set remote branch to match localgpf
—git push --force-with-lease
— safer force-push (requires fetch)gf
—git fetch
— download (but don’t merge) from remotegpl
—git pull
— download and merge remote branchgm
—git merge
— ubiquitousgrb
—git rebase
— ubiquitousgrbi
—git rebase -i
— interactive rebasegcp
—git cherry-pick
— ubiquitousgcpc
—git cherry-pick --continue
— continue after conflict/fixup/etcgrl
—git reflog
— list previous values ofHEAD
gbs
—git bisect
— binary search to find when a bug was introducedgr
—git reset
— ubiquitousgrh
—git reset --hard
— ubiquitousgrs
—git restore
— scrap unstaged changesgrss
—git restore --staged
— unstage changesgmb
—git merge-base
— find the least-common-ancestor of two commits
Other Commands
git init
— create new blank repositorygit clone
— download repository from given urlgit revert
— create a new commit that undoes the changes of the given commitgit blame
— list a file and the users/commits who last modified its linesgit stash [push|pop|list|drop|apply|...]
— temporary-commitsgit rm
— remove a file, locally and in the git repositorygit mv
— move a file, locally and in the git repositorygit difftool
— use vimdiff to visualize diffsgit mergetool
— use vimdiff to resolve merge conflicts
Idioms
git commit
— use the default behavior (enter message in text editor) instead of-m
7git switch -
— switch to the last-switched-from branchgit switch -c <name> [<parent>]
— switch to a new branch off ofparent
(orHEAD
, by default)git reset --hard @~
— hard-reset toHEAD
’s parentgit log -S <string>
— “Pickaxe”: list commits whose diffs include the givenstring
Tricks
Locally ignore a file that is tracked by git:
git update-index --assume-unchanged <file>
— ignore changes tofile
git update-index --no-assume-unchanged <file>
— undo the above
Setting up worktrees for a repository:
- (TODO)
- I haven’t gotten into worktrees yet, or used them enough to flesh this out
- But it would be a crime not to mention them.
- See: blog video docs
Revision Specifiers
(the docs for this have a pretty low opportunity cost)
HEAD
,@
—HEAD
(current “active” commit)<rev>^<n>
—n
th merge parent ofrev
<rev>^
— parent ofrev
<rev>~<n>
—n
th generational parent ofrev
<rev>~
— parent ofrev
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
<rev>^..<rev>
— inclusive range (kind of)8
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
# ...
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). ↩︎
(I’d even go as far as saying they’re better for certain operations, like staging files and resolving merge conflicts). ↩︎
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. ↩︎
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. ↩︎
For example, the popular github git cheat-sheet (this post is meant to serve as an alternative to it, hence the title). ↩︎
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”. ↩︎
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. ↩︎
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..
). ↩︎