My cherished Git aliases
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:
-
How the problem was seen by users, developers, or tests.
-
The identified root cause behind the issue, including references to specific code, algorithm, or design flaws.
-
How the patch fixes the issue.
-
Which limitations or risks the patch introduces, if any.
-
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.