Helpful git aliases and config settings

I have quite a few aliases and config recommendations. My personal favorite is git oops.

Tip: Patch Mode

Neither config nor alias per-se, but very useful: I do almost all my staging of changes hunk-by-hunk rather than file-by-file with git add -p (--patch). Check it out if you’ve never used it before! It allows me to craft much more intentional commits from a messy work tree.

It especially makes it really easy to do things like add temporary imports/requires/aliases for debugging purposes, and log/debug statements, in your code without accidentally committing them, or having to unwind them for committing purposes.

There are quite a few options when adding in “patch” mode, ? will give you some context. Over time I’ve incorporated y,n,q,a,d,j pretty deep into my muscle memory and workflow, but it takes some time and just y/n/q is a good start. For the purpose of subdividing hunks in order to separate a debug log line from some relevant code you want to commit, use s.

Already use git add -p? Did you know that --patch also works with:

  • git reset to selectively un-stage changes from files in the index into the work tree
  • git restore to selectively discard changes from files in the work tree
  • git stash to selectively stash changes from files out of the work tree

Config

A lot of my config is fairly specific to my own preferred git workflows, but these are workflow-agonistic, useful for anyone, and in my opinion should be defaults.

  • rerere.enabled = true

    Reuse Recorded Resolution. Better ink than mine has been spilled on this, but essentially, if you ever rebase at all, you want this set. It makes dealing with merge conflicts while rebasing palatable.

    git config set --global rerere.enabled true
    
  • merge.conflictstyle = diff3

    Adds a third section to merge conflicts, showing what the code looked like before either conflicting commit touched it. This gives essential context to what each author was trying to accomplish when changing the code, making it much more trivial to reconcile.

    git config set --global merge.conflictstyle diff3
    
  • diff.mnemonicprefix = true

    Uses helpful prefixes rather than the default a/file/name and b/file/name when diffing between things, where at least one thing is not a commit. Makes it easier to remember halfway scrolling through a long diff if you are comparing between a commit (c/), the index (i/), or the work tree (w/); or comparing two arbitrary commits (back to a/ and b/).

    Useful if you often run git diff with various arguments (git diff, git diff <ref>, git diff --cached).

    git config set --global diff.mnemonicprefix true
    

Aliases

I also don’t care for the git alphabet soup shortcuts many folk use, it makes it harder for rich tab-completion and command history tools to work. I type just fast enough that using the full form doesn’t really slow down common operations, and think just slowly enough it wouldn’t speed up uncommon ones. I also tend to make more typos mashing out a short vowel-less alias and jamming Enter than I would composing a full command using things closer to full words.

Utility

  • git alias

    An alias that lists all aliases.

    git config set --global alias.alias "!alias(){ git config --get-regexp '^alias.${1}'; }; alias"
    
  • git cherrypick

    Because I forget the - in cherry-pick, every time.

    git config set --global alias.cherrypick cherry-pick
    

Informational

  • git current

    Shows the current local branch.

    Useful for scripting purposes, prompt display, or command substitution.

    For example, when pushing up a branch for the first time, git push -u origin $(git current).

    git config set --global alias.current rev-parse --abbrev-ref HEAD
    
  • git last

    Shows a rich display of the last commit.

    Customizable using pretty formats.

    git config set --global alias.last "log -n1 --pretty='format:Commit: %C(yellow)%H%nAuthored by: %C(magenta)%aN %Creset%ar%nCommited by: %Cblue%cN %Creset%cr%n%n%B'"
    
    
  • git latest [N]

    Shows a rich summary of the last N commits, default 5.

    Customizable using pretty formats.

    (I use --- >8 --- to separate commits because I also use commit.cleanup = scissors and it pleases me.)

    git config set --global alias.latest "log -n${1:-5} --pretty='format:%Cgreen---------------------- >8 ----------------------%nCommit: %C(yellow)%H%nAuthored by: %C(magenta)%aN %Creset%ar%nCommited by: %Cblue%cN %Creset%cr%n%n%s%n'"
    
  • git contains <ref>

    Lists the branches a <ref> is in.

    Performs a fetch first to ensure you are up-to-date with, ex, PRs being merged into mainline while working on your branch.

    git config set --global alias.contains "!contains(){ git fetch && git rev-parse ${1:-HEAD} | xargs git branch -r --contains; }; contains"
    
  • git ancestor <branch1> [<branch2>]

    Shows the last commit shared between two branches. Uses HEAD if only one branch is provided.

    git config set --global alias.ancestor merge-base --octopus
    

History Modification

  • git oops [-m "new message"] [-a | list/of/files]

    Add something you forgot to the latest commit.

    Any staged changes in the index are folded into the last commit you made. Other unstaged changes in the work tree can be added by listing files, or all unstaged changes can be added with -a.

    The commit’s message can be changed with -m, but unlike standard commiting, you will not be presented with an editor if none is provided: the existing message will be left as-is.

    git config set --global alias.oops commit --amend --no-edit
    
  • git rollback [N]

    Soft-resets the latest N commits, default 1.

    All changes in rolled back commits are preserved, staged into the index.

    git config set --global alias.rollback "!rollback(){ cd ${GIT_PREFIX:-.} && git reset HEAD~${1:-1} --soft; }; rollback"
    
4 Likes