Home > OS >  How to use "$@" in a Git alias?
How to use "$@" in a Git alias?

Time:09-26

git log --name-status --pretty=format: | sed '/^$/d' | cut --fields=2- | sort | uniq --count | sort --numeric-sort --reverse | head prints the 10 most edited files in a Git repo (based on this). I want to create a Git alias most-edited for this command with one caveat: the command should put any extra arguments into the git log command. This would allow me to run git most-edited 'foo bar/' baz/ to get the most edited files in the foo bar (note the space) and baz directories.

In a script this would be as simple as adding -- "$@" to the git log command. However, if I create an alias most-edited = !git log --name-status --pretty=format: -- "$@" | sed '/^$/d' | cut --fields=2- | sort | uniq --count | sort --numeric-sort --reverse | head the arguments are instead passed to the last command in the pipeline, head. Is there some way to pass the arguments to git log?

CodePudding user response:

In the alias, define a function followed by an immediate call to the function. When the alias is expanded, any additional arguments on the command line become arguments to that function.

most-edited = '!f () { git log --name-status --pretty=format: -- "$@" | sed '/^$/d' | cut --fields=2- | sort | uniq --count | sort --numeric-sort --reverse | head; }; f'

CodePudding user response:

TL;DR: you can also use "!git log --name-status --pretty=format: \"$@\" | sed '/^$/d' | cut --fields=2- | sort | uniq --count | sort --numeric-sort --reverse | head #". The final # is required.

Long

Both iBug's answer ("write your own script and make it Git-callable") and chepner's answer ("use an alias that invokes a shell function") work fine, and are fully generic. There's one more possibility here, which is quite tricky, but also illustrative. I like to use the wc command to help show how the arguments get broken up:

[alias]
    visargs = "!wc head \"$@\" tail #"

Running:

GIT_TRACE=1 git visargs "one two" three

produces this output:

18:58:34.031386 git.c:702               trace: exec: git-visargs 'one two' three
18:58:34.031749 run-command.c:663       trace: run_command: git-visargs 'one two' three
18:58:34.032434 run-command.c:663       trace: run_command: 'wc head "$@" tail #' 'one two' three
wc: head: open: No such file or directory
wc: one two: open: No such file or directory
wc: three: open: No such file or directory
wc: tail: open: No such file or directory
       0       0       0 total

Note how the arguments were passed through to wc correctly: one two, as a single argument, got through as a single argument, and three got through as a single argument as well. The wc command got the arguments head and tail separately, and did not get a repeated set of arguments, even though, as we can see from the trace lines, the command run was really:

trace: run_command: 'wc head "$@" tail #' 'one two' three

The first expression is fed straight to sh as its -c argument. The remaining expressions are $1, $2, and so on. That's why the $@ works where it is, but also why we need the comment character: without the #, the arguments get tacked onto the final part of the alias expansion.

CodePudding user response:

Save your shell script to a file named git-most-edited somewhere in the $PATH, like ~/.local/bin/, and do chmod 755 on the file.

#!/bin/sh

git log --name-status --pretty=format: -- "$@" | sed '/^$/d' | cut --fields=2- | sort | uniq --count | sort --numeric-sort --reverse | head

You can then run git most-edited and Git will invoke your shell script for you.

  •  Tags:  
  • git
  • Related