Git alias com parâmetros posicionais

Basicamente estou tentando alias:

git files 9fa3 

… para executar o comando:

 git diff --name-status 9fa3^ 9fa3 

mas o git não parece passar parâmetros posicionais para o comando alias. Eu tentei:

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

… e alguns outros, mas eles não funcionaram.

O caso degenerado seria:

 $ git echo_reverse_these_params abcde edcba 

… como posso fazer isso funcionar?

    A maneira mais óbvia é usar uma function shell:

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

    Um alias sem ! é tratado como um comando Git; Por exemplo, commit-all = commit -a .

    Com o ! , ele é executado como seu próprio comando no shell, permitindo que você use magia mais forte como essa.

    UPD
    Como os comandos são executados na raiz do repository, você pode usar a variável ${GIT_PREFIX} ao se referir aos nomes dos arquivos nos comandos

    Você também pode referenciar sh diretamente (em vez de criar uma function):

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

    (Observe o traço no final da linha – você vai precisar disso.)

    O alias que você está procurando é:

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

    Com validação de argumentos:

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

    O # final é importante – evita que todos os argumentos fornecidos pelo usuário sejam processados ​​pelo shell (comenta-os).

    Nota: O git coloca todos os argumentos fornecidos pelo usuário no final da linha de comando. Para ver isso em ação, tente: GIT_TRACE=2 git files abcd

    Aspas escapadas (devido a aninhamento) são importantes para nomes de arquivos que contêm espaços ou "; rm -rf --no-preserve-root /; )

    Use GIT_TRACE = 1 descrito na página man do git para tornar o processamento do alias transparente:

     $ 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 

    Seus comandos originais trabalham com a versão 1.8.3.4 do git (Eimantas notou que isto mudou em 1.8.2.1).

    O sh -c '..' -- e f() {..}; f f() {..}; f opções de f() {..}; f manipulam os parâmetros “$ @” de maneiras diferentes (consulte com GIT_TRACE). Acrescentar “#” a um alias também permitiria parâmetros posicionais sem deixar os parâmetros posteriores.

    Como afirmado por Drealmer acima :

    ” Seja cuidadoso, ! será executado na raiz do repository, portanto, o uso de caminhos relativos ao chamar seu alias não fornecerá os resultados esperados. – Drealmer 8 de agosto de 2013 às 16:28 »

    GIT_PREFIX sendo definido por git para o subdiretório em que você está, você pode contornar isso alterando primeiro o diretório:

    git config –global alias.ls ‘! cd “$ {GIT_PREFIX: -.}”; ls -al ‘

    Eu queria fazer isso com um alias que faz isso:

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

    No final, criei um script de shell chamado git-m que possui este conteúdo:

     #!/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 ] then echo "Wrong number of arguments. Should be 2, was $#"; exit 1; fi git checkout $1; git merge --ff-only $2; git branch -d $2; 

    Isso tem a vantagem de ser muito mais legível porque está em várias linhas. Além disso, gosto de poder chamar bash com -x e set -e . Você provavelmente pode fazer isso como um pseudônimo, mas seria super feio e difícil de manter.

    Como o arquivo é chamado git-m você pode executá-lo assim: git m foo bar

    Apenas esbarrou em algo semelhante; Espero que seja OK postar minhas annotations. Uma coisa que me confunde sobre git aliases com argumentos, provavelmente vem da git help config do git help config (eu tenho a versão 1.7.9.5 do git):

    Se a expansão de alias for prefixada com um ponto de exclamação, ela será tratada como um comando de shell. Por exemplo, definindo “alias.new =! Gitk –all –not ORIG_HEAD”, a invocação “git new” é equivalente a executar o comando shell “gitk –all –not ORIG_HEAD”. Observe que os comandos shell serão executados no diretório de nível superior de um repository, que pode não ser necessariamente o diretório atual. […]

    A maneira que eu vejo isso – se um alias “será tratado como um comando shell” quando prefixado com ponto de exclamação – por que eu precisaria usar uma function, ou sh -c com argumentos; Por que não apenas escrever meu comando como está?

    Eu ainda não sei a resposta – mas acho que existe uma pequena diferença no resultado. Aqui está um pequeno teste – jogue isso no seu .git/config ou no seu ~/.gitconfig :

     [alias] # ... 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 " 

    Aqui está o que eu recebo executando esses aliases:

     $ git ech word1 word2 rem: word1 word2 $ git shech word1 word2 rem: $ git fech word1 word2 rem: $ 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/ 

    … ou: quando você está usando um comando “simples” após o ! “como está” em um alias git – então o git automaticamente anexa a lista de argumentos a esse comando! Uma maneira de evitar isso é, na verdade, chamar seu script como uma function – ou como argumento para sh -c .

    Outra coisa interessante aqui (para mim) é que, em um script de shell, normalmente se espera que a variável automática $0 seja o nome do arquivo do script. Mas para uma function git alias, o argumento $0 é, basicamente, o conteúdo de toda a string especificando esse comando (conforme inserido no arquivo de configuração).

    Por isso, creio eu, se acontecer de você citar incorretamente – no caso abaixo, isso escapingia das aspas duplas externas:

     [alias] # ... fail = ! \"echo 'A' 'B'\" 

    … – então git falha com (para mim, pelo menos) mensagem um tanto enigmática:

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

    Eu acho que desde o git “vi” uma string inteira como apenas um argumento ! – tentou executá-lo como um arquivo executável; e correspondentemente falhou em encontrar "echo 'A' 'B'" como um arquivo.

    Em qualquer caso, no contexto da citação de git help config do git help config acima, eu especularia que é mais correto afirmar algo como: ” … a invocação” git new “é equivalente a executar o comando shell” gitk –all – – não ORIG_HEAD $ @ “, onde $ @ são os argumentos passados ​​para o alias do comando git da linha de comando em tempo de execução … “. Eu acho que isso também explicaria, porque a abordagem “direta” no OP não funciona com parâmetros posicionais.