Git alias with positional parameters

Basically I’m trying to alias:

git files 9fa3

…to execute the command:

  • Adding Git Bash Alias
  • `find -exec` in git alias
  • Cannot create simple Git alias in MinGW32 on windows 7
  • User Input to Bash Alias?
  • How can I define an alias for a Git subcommand (e.g. for `list` in `git stash list`)?
  • How to embed bash script directly inside a git alias
  • git diff --name-status 9fa3^ 9fa3

    but git doesn’t appear to pass positional parameters to the alias command. I have tried:

        files = "!git diff --name-status $1^ $1"
        files = "!git diff --name-status {1}^ {1}"

    …and a few others but those didn’t work.

    The degenerate case would be:

    $ git echo_reverse_these_params a b c d e
    e d c b a

    …how can I make this work?

  • Push a tag to a remote repository using Git?
  • Pushing files from one Git repository to another
  • Mercurial convert extension not able to pull from remote Git repository
  • Setting umask in Git / Gitolite
  • Re-doing a reverted merge in Git
  • Git setup remote tracking branch
  • 7 Solutions collect form web for “Git alias with positional parameters”

    The most obvious way is to use a shell function:

        files = "!f() { git diff --name-status \"$1^\" \"$1\"; }; f"

    An alias without ! is treated as a Git command; e.g. commit-all = commit -a.

    With the !, it’s run as its own command in the shell, letting you use stronger magic like this.

    You can also reference sh directly (instead of creating a function):

            files = !sh -c 'git diff --name-status $1^ $1' -

    (Note the dash at the end of the line — you’ll need that.)

    The alias you are looking for is:

    files = "!git diff --name-status \"$1\"^ \"$1\" #"

    With argument validation:

    files = "![ x$# != x1 ]&&echo "commit-ish required" >&2 || git diff --name-status \"$1\"^ \"$1\" #"

    The final # is important – it prevents all the user-supplied arguments from being processed by the shell (it comments them out).

    Note: git puts all user-supplied arguments at the end of the command line. To see this in action, try: GIT_TRACE=2 git files a b c d

    The escaped (due to nesting) quotes are important for filenames containing spaces or "; rm -rf --no-preserve-root /;)

    Use GIT_TRACE=1 described on the git man page to make the alias processing transparent:

    $ git config alias.files
    !git diff --name-status $1^ $1
    $ GIT_TRACE=1 git files 1d49ec0
    trace: exec: 'git-files' '1d49ec0'
    trace: run_command: 'git-files' '1d49ec0'
    trace: run_command: 'git diff --name-status $1^ $1' '1d49ec0'
    trace: exec: '/bin/sh' '-c' 'git diff --name-status $1^ $1 "$@"' 'git diff --name-status $1^ $1' '1d49ec0'
    trace: built-in: git 'diff' '--name-status' '1d49ec0^' '1d49ec0' '1d49ec0'
    trace: run_command: 'less -R'
    trace: exec: '/bin/sh' '-c' 'less -R' 'less -R'
    MM      TODO

    Your original commands work with git version (Eimantas noted this changed in

    The sh -c '..' -- and f() {..}; f options both cleanly handle the “$@” parameters in different ways (see with GIT_TRACE). Appending “#” to an alias would also allow positional parameters without leaving the trailing ones.

    As stated by Drealmer above (

    « Be careful, ! will run at the root of the repository, so using relative paths when calling your alias will not give the results you might expect. – Drealmer Aug 8 ’13 at 16:28 »

    GIT_PREFIX being set by git to the subdirectory you’re in, you can circumvent this by first changing the directory :

    git alias ls=’!cd ${GIT_PREFIX:-.}; ls -al’

    I wanted to do this with an alias that does this:

    git checkout $1;
    git merge --ff-only $2;
    git branch -d $2;

    In the end, I created a shell script named git-m that has this content:

    #!/bin/bash -x
    set -e
    #by naming this git-m and putting it in your PATH, git will be able to run it when you type "git m ..."
    if [ "$#" -ne 2 ]
      echo "Wrong number of arguments. Should be 2, was $#";
      exit 1;
    git checkout $1;
    git merge --ff-only $2;
    git branch -d $2;

    This has the benefit that it’s much more legible because it’s on multiple lines. Plus I like being able to call bash with -x and set -e. You can probably do this whole thing as an alias, but it would be super ugly and difficult to maintain.

    Because the file is named git-m you can run it like this: git m foo bar

    Just bumped into something similar; hope it’s oK to post my notes. One thing that confuses me about git aliases with arguments, probably comes from the git help config (I have git version

    If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. For example, defining “ = !gitk –all –not ORIG_HEAD”, the invocation “git new” is equivalent to running the shell command
    “gitk –all –not ORIG_HEAD”. Note that shell commands will be executed from the top-level directory of a repository,
    which may not necessarily be the current directory. […]

    The way I see it – if an alias “will be treated as a shell command” when prefixed with exclamation point – why would I need to use a function, or sh -c with arguments; why not just write my command as-is?

    I still don’t know the answer – but I think actually there is a slight difference in outcome. Here’s a little test – throw this in your .git/config or your ~/.gitconfig:

      # ...
      ech = "! echo rem: "
      shech = "! sh -c 'echo rem:' "
      fech = "! f() { echo rem: ; }; f " # must have ; after echo!
      echargs = "! echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ "
      fechargs = "! f() { echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ ; }; f "

    Here is what I get running these aliases:

    $ git ech word1 word2
    rem: word1 word2
    $ git shech word1 word2
    $ git fech word1 word2
    $ git echargs word1 word2
    0[[ echo 0[["$0"]] 1-"$1"/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2
    $ git fechargs word1 word2
    0[[ f() { echo 0[["$0"]] 1-"$1"/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/

    … or: when you’re using a “plain” command after the ! “as-is” in a git alias – then git automatically appends the arguments list to that command! A way to avoid it, is indeed, to call your script as either a function – or as argument to sh -c.

    Another interesting thing here (for me), is that in a shell script, one typically expects the automatic variable $0 to be the filename of the script. But for a git alias function, the $0 argument is, basically, the content of the entire string specifying that command (as entered in the config file).

    Which is why, I guess, if you happen to misquote – in the below case, that would be escaping the outer double quotes:

      # ...
      fail = ! \"echo 'A' 'B'\"

    … – then git would fail with (for me, at least) somewhat cryptic message:

    $ git fail
     "echo 'A' 'B'": 1: echo 'A' 'B': not found
    fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory

    I think, since git “saw” a whole string as only one argument to ! – it tried to run it as an executable file; and correspondingly it failed finding "echo 'A' 'B'" as a file.

    In any case, in context of the git help config quote above, I’d speculate that it’s more accurate to state something like: ” … the invocation “git new” is equivalent to running the shell command “gitk –all –not ORIG_HEAD $@”, where $@ are the arguments passed to the git command alias from command line at runtime. … “. I think that would also explain, why the “direct” approach in OP doesn’t work with positional parameters.

    Git Baby is a git and github fan, let's start git clone.