mbigras mbigras - 1 month ago 10
Git Question

Why is my git log alias not working?

In my

.gitconfig
I have an alias set to
lol
to run the following command:

git --no-pager log --graph --pretty=oneline --abbrev-commit --decorate --all $*


I read in another post that I shouldn't use no-pager, so I used the method of setting the pager to
cat
as shown below.

I was expecting the output of my alias to match the output of the above command as shown below, but nothing happens. Any ideas why?

command history:

➜ ~/w/t/some-dir master ✓ git log
commit 4f6dc31e12fb6b39c8d44f293b7561f132c4d9ad
Author: Max Bigras <mbigras22@gmail.com>
Date: Sun Oct 30 20:43:40 2016 -0700

Add readme
➜ ~/w/t/some-dir master ✓ git lg
* 4f6dc31 - (HEAD -> master) Add readme (5 minutes ago) <Max Bigras>
➜ ~/w/t/some-dir master ✓ git --no-pager log --graph --pretty=oneline --abbrev-commit --decorate --all $*
* 4f6dc31 (HEAD -> master) Add readme
➜ ~/w/t/some-dir master ✓ git lol
➜ ~/w/t/some-dir master ✓


.gitconfig
:

[user]
name = Max Bigras
email = mbigras22@gmail.com
[core]
editor = vim
autocrlf = input
excludesfile = /Users/max/.gitignore_global
[push]
default = simple
[alias]
co = checkout
br = branch
ci = commit
s = status
unstage = reset HEAD --
quickcommit-m= "!git add -A; git commit -m"
alias = config --get-regexp ^alias\\.
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
lol = log --graph --pretty=oneline --abbrev-commit --decorate --all $*
[pager]
lol = cat
.
.
.

Answer

The problem here is the $* at the end. You should simply omit it.

Explanation

In shell scripts, $* (or better, "$@"—note the surrounding double quotes1) expands to "all additional arguments", which would be desirable here. But Git aliases are not themselves shell scripts, and should not be treated this way.

Instead, Git adds any additional arguments at the end regardless of the alias expansion. For instance, with:

[alias]
    echo = !echo

I get:

$ git echo several additional arguments
several additional arguments

Hence, to pass the remaining arguments through to the expanded command (in this case echo but in your case git log), you simply do nothing. You can cause certain arguments to be repeated:

[alias]
    echo = !echo $1

yields:

$ git echo several additional arguments
several several additional arguments

but that's not the goal here, and $* simply expands to a literal $*.

Because this command is !-prefixed and therefore passed through to the shell, causes the shell to expand $*, so it is hard to demonstrate: we need a Git command that will print its argument. The rev-parse command works well enough:

[alias]
    rp = rev-parse $*

after which:

$ git rp
$*
$ git rp master
$*
master
fatal: master: no such path in the working tree.
Use 'git <command> -- <path>...' to specify paths that do not exist locally.

or better yet:

$ GIT_TRACE=1 git rp master
22:16:01.828980 git.c:563               trace: exec: 'git-rp' 'master'
22:16:01.831942 run-command.c:336       trace: run_command: 'git-rp' 'master'
22:16:01.850163 git.c:286               trace: alias expansion: rp => 'rev-parse' '$*'
22:16:01.850581 git.c:563               trace: exec: 'git-rev-parse' '$*' 'master'
22:16:01.850678 run-command.c:336       trace: run_command: 'git-rev-parse' '$*' 'master'
22:16:01.883257 git.c:350               trace: built-in: git 'rev-parse' '$*' 'master'
$*
master
fatal: master: no such path in the working tree.
Use 'git <command> -- <path>...' to specify paths that do not exist locally.

(Setting GIT_TRACE=1 in the environment is a handy debug trick.)


1The double quotes protect against the shell breaking up arguments containing white space (really, $IFS values).

In the bad old days, "$@" failed when $# was zero, as the internal expansion wound up producing a single empty argument. So we had to spell this ${1+"$@"}, i.e., use "$@" if $1 exists, otherwise use nothing. POSIX fixed this particular problem.)

Comments