My cherished Git aliases

by Philippe Proulx on 8 May 2025

I've been using Git for 17 years as of this date.

I wouldn't say I'm a Git guru—I just use what I need to get the job done. Something which really helped me understand the main concepts initially is the Git for Computer Scientists article. Over time though, I've picked up a few tricks that make my workflow smoother, faster, and a less painful.

Many of said tricks take the form of Git aliases, little shortcuts which I'll type dozens of times a day.

This post presents my most frequently used Git aliases.

Note that I may update this post in the future when I create new life-changing Git aliases.

The basics

The basic Git aliases that I'll type all day long:

ap = add -p
au = add -u
br = branch
ca = commit --amend
cc = cherry-pick --continue
ci = commit
cia = commit --amend
cif = commit --fixup
cifh = commit --fixup HEAD
co = checkout
cop = checkout -p
cp = cherry-pick
dc = diff --cached
mff = merge --ff-only
ra = rebase -i --autosquash
rc = rebase --continue
rea = reset --hard
rep = reset -p
ri = rebase -i
st = status

Fancy history

My pretty git log aliases are:

git lg

Alias:

lg = log --oneline --decorate

Example:

git ll

Alias:

ll = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --numstat

Example:

git lll

A tribute to Laurence Lavigne Lalonde.

Alias:

lll = log --color=always --pretty='%C(auto,yellow)%h %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(12,trunc)%aN %C(auto,reset)%s%C(auto,red)% gD% D' --date=relative --date-order

Example:

Raw commit message extraction

This one extracts the raw commit message, without common trailers, of some specific commit or of HEAD if missing:

msg = "!f() { git log -n1 --pretty=%B $1 | grep -viP '^([\\w-]+-(by|on|for)|change-id|fixes|closes):' | sed -Ez '$ s/\\n+$//'; echo; }; f"

For example, for a commit such as:

commit 882aa50506c296e8b05eb948868da52713ddc666
Author: Simon Marchi <simon.marchi@efficios.com>
Date:   Tue Jan 21 23:34:21 2025 -0500

    src.ctf.fs: remove `ctf_fs_ds_index_entry::timestamp_{begin,end}`

    Following the previous patch, the only remaining uses of the
    `timestamp_begin` and `timestamp_end` is to fill the `range-ns` map in
    the `babeltrace.trace-infos` query.  And even there, we use only the
    begin timestamp of the first entry and the end timestamp of the last
    entry.  We therefore do a lot of work that is just wasted.

    Remove those fields, all the code to compute them, and compute the
    timestamp in nanoseconds from origin on demand when handling the trace
    infos query, in `populate_stream_info()`.

    Change-Id: I29cb1baaa3ca0652e1674ab381840dbbf1687d97
    Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
    Reviewed-on: https://review.lttng.org/c/babeltrace/+/13913
    Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
    Tested-by: jenkins <jenkins@lttng.org>

You get:

src.ctf.fs: remove `ctf_fs_ds_index_entry::timestamp_{begin,end}`

Following the previous patch, the only remaining uses of the
`timestamp_begin` and `timestamp_end` is to fill the `range-ns` map in
the `babeltrace.trace-infos` query.  And even there, we use only the
begin timestamp of the first entry and the end timestamp of the last
entry.  We therefore do a lot of work that is just wasted.

Remove those fields, all the code to compute them, and compute the
timestamp in nanoseconds from origin on demand when handling the trace
infos query, in `populate_stream_info()`.

This is useful because I often find myself needing to copy and adapt an existing commit message to write a new one, or to reference one in another.

Fix commit

This alias is super simple, but its real value lies in the template it refers to:

fix = commit -t /home/eepp/git-fix-msg-template.txt

Here's said template:

git-fix-msg-template.txt
Fix:

OBSERVED ISSUE
━━━━━━━━━━━━━━
 
 
CAUSE
━━━━━
 
 
SOLUTION
━━━━━━━━
 
 
KNOWN DRAWBACKS
━━━━━━━━━━━━━━━
 
 
REFERENCES
━━━━━━━━━━
 

This is our standard fix commit message template at EfficiOS. The template requires that you write:

  1. How the problem was seen by users, developers, or tests.

  2. The identified root cause behind the issue, including references to specific code, algorithm, or design flaws.

  3. How the patch fixes the issue.

  4. Which limitations or risks the patch introduces, if any.

  5. Links and references, if any.

This file, as is, follows eepp's plain text format, which is how I write plain text documents, including commit messages. Formol helps me with that.

A new branch

We use Gerrit extensively at EfficiOS, therefore our main remote is often named review.

One common operation, for me at least, is to branch from review/master:

corn = checkout review/master -b

Then:

$ git corn fix-segfault-on-create
branch 'fix-segfault-on-create' set up to track 'review/master'.
Switched to a new branch 'fix-segfault-on-create'

corn stands for ❲c❳heck❲o❳ut ❲r❳eview/❲n❳aster (I know).

Often, I don't have an idea for a branch name, in which case I have this alternative version using qngng:

qorn = "!f() { git corn $(qngng -kcuda); }; f"

Example:

$ git qorn
branch 'roch-voisine' set up to track 'review/master'.
Switched to a new branch 'roch-voisine'

Commit selection

I often need to manually pick a commit and get its ID for various operations and scripts.

While I usually browse a Git history with Tig (by Jonas Fonseca, a guy from Montréal like us here), there's no built-in way to select (pick) a commit and have Tig print its ID.

There's tig-pick, a big hack of file descriptor redirections which works okay, but even then, I generally love myself some nice fuzzy search when having to find a commit.

This is where my most complex Git alias comes into play:

select = "!f() { local cid; cid=$(git lll | fzf --no-sort --no-mouse --reverse --ansi) || return 1; echo $cid | sed -r 's/\\x1b\\[[0-9;]*[mK]//g' | cut -f1 -d' '; }; f"

This abomination relies itself on my git lll alias and it's a real joy to use:

You may adjust the fzf options to your liking:

--no-sort
Keep the results in the original order.
--no-mouse
I don't like mouse integration in terminal applications; I want to be able to select text by default.
--reverse
HEAD at the top.
--ansi
Process ANSI color codes, as received from git lll.

git select doesn't print anything and exits with status 1 if you cancel the search (with Escape or Ctrl+C, for example).

I might do, for example:

$ git msg $(git select) | xsel -b

to find a specific commit and copy its message to the clipboard.

But my main use case of git select remains git cifi alias.

cifi

My Git workflow when working on something is to keep a few commits within my feature branch and use git commit --fixup (git cif) to add stuff to them through fixup commits.

I'll then regularly rebase with git rebase -i --autosquash (git ra) to apply the fixups. This is entirely compatible with the Gerrit workflow.

I've been opening Tig to find the commit to fixup and manually selecting its ID for years. Now I use git select:

cifi = "!f() { local cid; cid=$(git select) || return 1; git commit --fixup $cid; }; f"

git cifi won't commit if you cancel the search.