15

I have the following 1-liner that I use to see who might be a good candidate for help with a peice of code:

git log --pretty=short . | grep ^Auth | sort | uniq -c | sort -nr

which lists authors in order of commits, it's crude but it works OK.

When I add it to my git config however, like this:

[alias]
    guru=!git log --pretty=short . | grep ^Auth | sort | uniq -c | sort -nr

running

git guru

Gives different results to running it from the command line.

stuart@beavis(rp):~/git/apps$ git log --pretty=short . | grep ^Auth | sort | uniq -c | sort -nr
710 Author: dave <dave@b2368a2b-315f-46b9-a0b0-05934f827f41>
415 Author: pete <pete@b2368a2b-315f-46b9-a0b0-05934f827f41>
402 Author: craig <craig@b2368a2b-315f-46b9-a0b0-05934f827f41>

Compared to:

stuart@beavis(rp):~/git/apps$ git guru
859 Author: craig <craig@b2368a2b-315f-46b9-a0b0-05934f827f41>
813 Author: paul <paul@b2368a2b-315f-46b9-a0b0-05934f827f41>
798 Author: dave <dave@b2368a2b-315f-46b9-a0b0-05934f827f41>

As Stefan Näwe notes below, aliases run in the root of your repository, is there any way to run the command on the directory I'm in, or specify?

Stuart Grimshaw
  • 1,541
  • 1
  • 18
  • 41

4 Answers4

24

is there any way to run the command on the directory I'm in, or specify?

Yes, there is. When you run a git command, your environment gets a GIT_PREFIX variable with the value of the relative path (from toplevel to the path before executing git) so what you need is prefix your git aliases (that run shell commands and need the right pwd) with cd ${GIT_PREFIX:-.} && .

Simple test, add this to your ~/.gitconfig

[alias]
p = !pwd && cd \"${GIT_PREFIX:-.}\" && pwd
mtraceur
  • 3,254
  • 24
  • 33
Andrei Neculau
  • 986
  • 1
  • 10
  • 15
  • 3
    For an explanation of the `${GIT_PREFIX:-.}` syntax, refer to: http://stackoverflow.com/a/16753536/79111. – Ton van den Heuvel Aug 11 '16 at 13:31
  • For those wondering why we need to protect against the unset-or-blank case: if you run a `git` alias in the top lever directory of the repo, `$GIT_PREFIX` will expand to the empty string. `cd` with an empty string argument will error out; `cd` with no argument will go to your home directory. And on that last note, always quote your shell variables: `cd "${GIT_PREFIX:-.}"`. – mtraceur Aug 03 '23 at 13:57
  • To clarify: re: shell variable quoting: `cd ${GIT_PREFIX:-.}` will do the wrong thing if your directories have spaces (or other `$IFS` characters) or globbing characters in them (unless the shell your Git calls on your system breaks backwards compatibility with Bourne-like shell behavior). That won't come up often, but if it ever does come up the unquoted variant is guaranteed to do the wrong thing. `cd "${GIT_PREFIX:-.}"` will always do what's intended. And then because `git` does its own interpretation of double-quote characters in aliases, we need `\"` instead of just `"`. – mtraceur Aug 03 '23 at 16:04
13

git's aliases using a shell command (i.e. prefixed by !) run in the toplevel of the working directory (where the .git lives). Simple aliases (without !) run at the current directory.

Stefan Näwe
  • 3,040
  • 1
  • 18
  • 19
  • Thanks Stefan, this answered my original question, I've ammeded now to hopefully make it more useful to others in the same situation. – Stuart Grimshaw Jan 12 '12 at 23:52
  • 3
    This is a fairly unintuitive Git behavior. Does anyone know how to run an alias in the current directory? Or if the current directory is available in an env var or something so that an alias can `cd` back to the right place before running? – Jim Stewart Nov 20 '13 at 17:04
  • @JimStewart see Andrei Neculau's answer above, it shows how to do just that :) – waldyrious Apr 04 '16 at 18:45
4

Looking at what you are doing you probably want to use git shortlog -sn instead as this does the task in question already.

git aliases do not all run at the toplevel. As described in the git config manual "Note that shell commands will be executed from the top-level directory of a repository, which may not necessarily be the current directory." So only shell commands get run at the top level. If you simply alias a git subcommand it will run at the current location. The following session log demonstrates this:

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$ git rev-parse  --show-cdup
../../

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$ git config alias.cdup 'rev-parse --show-cdup'

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$ git cdup
../../

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$ git config alias.cdup2 '!git rev-parse --show-cdup'

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$ git cdup2

pat@FROG /c/src/WiRE.git/wdf/src (pt/wdf)
$

Your example uses an alias command that starts with 'git'. If I try setting 'git rev-parse --show-cdup' as the alias it returns an error stating 'git is not a git command' so I suspect you actually had a exclamation mark too hence running it as a shell command, thus running from the toplevel.

patthoyts
  • 32,320
  • 3
  • 62
  • 93
0

Another option is to use the -C option to git in the alias. This worked for me:

[alias]
    guru=!git -C ${GIT_PREFIX:-.} log --pretty=short . | grep ^Auth | sort | uniq -c | sort -nr