How can I write a git alias that will let me create more aliases?
For example:
git alias st status
Should create a new alias for git status
under st
.
Each alias is simply an entry in the alias
section of a git config file. For instance, if zog
were an alias, it would be alias.zog
To update a git config file, you can use git config
with one of the options to choose which configuration file to update. The most appropriate such options are --global
(affecting your personal config file that applies to all repositories) and --local
(affecting the current repository only, i.e., an alias that only works in one repo). The default is --local
but --global
usually makes more sense for aliases.
So let's consider a trivial example, to make git zog
mean the same thing as git log
:
$ git config --global alias.zog log
$ git zog --oneline
a17003a change f1
9af3861 initial
Now let's change it from meaning log
to meaning frog
:
$ git config --global alias.zog frog
$ git zog
Expansion of alias 'zog' failed; 'frog' is not a git command
Last, we'll remove it, since this is just for illustration and it's time to clean up:
$ git config --global --unset alias.zog
$ git zog
git: 'zog' is not a git command. See 'git --help'.
Did you mean this?
log
You say you want an alias that creates more aliases. That means we want the alias alias
to run git config
. This would almost work:
git config --global alias.alias 'config --global alias.'
except for one very big problem: with this alias in place, running git alias st status
results in the equivalent of the command:
git config --global alias. st status
when we want one that has alias.st
as the first argument. Also, we'd run into issues with the remaining arguments if there were more than one: git config
would get them split up inappropriately.
Thus, we need to resort to invoking the shell. There are many ways to code the remainder. They are hard to type in as shell commands; it's easier to edit the config file and put them in manually (git config --global --edit
will do this, or you can just invoke your editor directly).
Here's an example from the git authors (I added some backslash-newline bits to make it fit better on StackOverflow; note that you can write the alias this way in your various config files):
[alias]
alias = "!sh -c '[ $# = 2 ] && \
git config --global alias.\"$1\" \"$2\" && exit 0 || \
echo \"usage: git alias <new alias> <original command>\" >&2 && exit 1' -"
To make this one work I had to add another -
right at the end (not shown above); I'm not really sure why, probably some FreeBSD sh
variance.
Here's my version of the same thing, using shell functions to handle arguments. If you supply more than two arguments, all the extras are combined:
[alias]
alias = "!f() { a=\"$1\"; shift; \
git config --global alias.\"$a\" \"$*\"; }; f"
So now:
$ git alias st status --short
$ GIT_TRACE=1 git st
trace: exec: 'git-st'
trace: run_command: 'git-st'
trace: alias expansion: st => 'status' '--short'
trace: built-in: git 'status' '--short'
(or just look at the config file, with editor or git config --get
).
These—both versions—are still slightly defective as they can try to re-alias an existing alias. It might be better to see if alias."$1"
is already in the config file, and if so, complain (or require an argument like --overwrite
or a different alias like realias
or some such). Feel free to experiment with what git does with multiple entries for, e.g., alias.foo
, and see the documentation for git config
for how git config
deals with multiple entries (they are allowed, under various circumstances).
As a general rule, once your git alias starts getting hairy like this, it's probably better to just write a shell script (or shell function) for it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With