Alias Git avec paramètres de position

en gros, J'essaie d'alias:

git files 9fa3

...pour exécuter la commande:

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

mais git ne semble pas passer les paramètres de position à la commande alias. J'ai essayé:

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

...et quelques autres, mais ceux qui n'ont pas de travail.

le cas dégénéré serait:

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

...comment puis-je faire ce travail?

209
demandé sur user400575 2010-07-23 23:03:23

7 réponses

la manière la plus évidente est d'utiliser une fonction shell:

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

un alias sans ! est traité comme une commande Git; p.ex. commit-all = commit -a .

avec le ! , il est exécuté comme sa propre commande dans le shell, vous permettant d'utiliser une magie plus forte comme celle-ci.

UPD

Parce que les commandes sont exécutées à la racine du dépôt, vous pouvez utiliser la variable ${GIT_PREFIX} en se référant aux noms de fichier dans les commandes

306
répondu Cascabel 2018-03-04 13:20:24

vous pouvez aussi faire référence à sh directement (au lieu de créer une fonction):

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

(Notez le tiret à la fin de la ligne, vous en aurez besoin.)

82
répondu mipadi 2016-02-09 09:39:55

l'alias que vous recherchez est:

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

avec validation de l'argument:

files = "!cd -- \"${GIT_PREFIX:-.}\" && [ x$# != x1 ] && echo commit-ish required >&2 || git diff --name-status \"\"^ \"\" #"

le final # est important - il empêche tous les arguments fournis par l'utilisateur d'être traités par le shell (il les commente).

Note: git place tous les arguments fournis par l'utilisateur à la fin de la ligne de commande. Pour voir cela en action, essayez: GIT_TRACE=2 git files a b c d

L'échappé (en raison de la nidification) citations sont importantes pour les noms de fichiers contenant des espaces ou des "; rm -rf --no-preserve-root /; )

51
répondu Tom Hale 2018-09-09 10:41:57

utilisez GIT_TRACE=1 décrit sur la page de manuel git pour rendre le traitement d'alias transparent:

$ git config alias.files
!git diff --name-status ^ 
$ GIT_TRACE=1 git files 1d49ec0
trace: exec: 'git-files' '1d49ec0'
trace: run_command: 'git-files' '1d49ec0'
trace: run_command: 'git diff --name-status ^ ' '1d49ec0'
trace: exec: '/bin/sh' '-c' 'git diff --name-status ^  "$@"' 'git diff --name-status ^ ' '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

vos commandes originales fonctionnent avec la version 1.8.3.4 de git (Eimantas a noté ce changement au 1.8.2.1).

les options sh -c '..' -- et f() {..}; f gèrent les paramètres" $ @ " de différentes façons (voir avec GIT_TRACE). Ajouter " # " à un alias permettrait également d'ajouter des paramètres de position sans laisser de trace.

21
répondu bsb 2013-08-26 01:27:01

comme indiqué par Drealmer au-dessus de :

" attention ! va exécuter à la racine du référentiel, donc l'utilisation de chemins relatifs lors de l'appel de votre alias ne donnera pas les résultats que vous pouvez attendre. - Drealmer Aug 8 '13 à 16: 28 "

GIT_PREFIX étant défini par git au sous-répertoire dans lequel vous êtes, vous pouvez contourner cela en changeant d'abord le répertoire:

git config --global alias.ls '! cd " ${GIT_PREFIX: -.} "; ls-al'

16
répondu Pierre-Olivier Vares 2018-03-05 08:57:20

je voulais faire ça avec un alias qui fait ça:

git checkout ;
git merge --ff-only ;
git branch -d ;

à la fin, j'ai créé un script shell appelé git-m qui a ce contenu:

#!/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 ;
git merge --ff-only ;
git branch -d ;

cela a l'avantage que c'est beaucoup plus lisible parce qu'il est sur plusieurs lignes. De plus, j'aime pouvoir appeler bash avec -x et set -e . Vous pouvez probablement faire toute cette chose comme un alias, mais il serait super laid et difficile à maintenir.

Parce que le fichier est nommé git-m vous pouvez l'exécuter comme ceci: git m foo bar

8
répondu Daniel Kaplan 2014-06-21 04:09:34

vient de tomber sur quelque chose de similaire; j'espère que c'est oK pour poster mes notes. Une chose qui me confond à propos des alias git avec des arguments, vient probablement du git help config (j'ai la version de git 1.7.9.5):

si l'extension alias est préfixée par un point d'exclamation, elle sera traitée comme une commande shell. Par exemple, définir "alias".nouveau = !gitk --all --not ORIG_HEAD", l'invocation "git new" est équivalente à exécuter le shell commande "gitk -- all --not ORIG_HEAD". Notez que les commandes shell seront exécutées à partir du répertoire supérieur d'un dépôt., qui peut ne pas être le répertoire courant. [...]

de la façon dont je le vois - si un alias" sera traité comme une commande shell "lorsqu'il est préfixé avec un point d'exclamation - pourquoi aurais-je besoin d'utiliser une fonction, ou sh -c avec des arguments; pourquoi ne pas simplement écrire ma commande telle quelle?

Je ne sais toujours pas réponse-mais je pense qu'il y a en fait une légère différence dans les résultats. Voici un petit test - jetez ceci dans votre .git/config ou votre ~/.gitconfig :

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

voici ce que j'obtiens en exécutant ces alias:

$ git ech word1 word2
rem: word1 word2

$ git shech word1 word2
rem:

$ git fech word1 word2
rem:

$ git echargs word1 word2
0[[ echo 0[[""151910920""]] 1-""/ A-$@/ ]] 1-word1/ A-word1 word2/ word1 word2

$ git fechargs word1 word2
0[[ f() { echo 0[[""151910920""]] 1-""/ A-$@/ ; }; f ]] 1-word1/ A-word1 word2/

... ou: lorsque vous utilisez une commande" simple "après la commande ! " AS-is "dans un alias git - alors git ajoute automatiquement la liste des arguments à cette commande! Une façon de l'éviter, est en effet, à l'appel votre script comme une fonction - ou comme argument à sh -c .

une autre chose intéressante ici (pour moi), c'est que dans un script shell, on s'attend typiquement à ce que la variable automatique " 1519130920 " soit le nom du fichier du script. Mais pour une fonction d'alias git , l'argument "1519130920" est, fondamentalement, le contenu de la chaîne de caractères entier spécifiant cette commande (telle qu'entrée dans le fichier de configuration).

qui c'est pourquoi, je suppose, si vous vous trompez - dans le cas ci-dessous, qui serait échapper aux doubles guillemets extérieurs:

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

... - alors git échouerait avec (pour moi, au moins) un message quelque peu cryptique:

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

je pense, depuis git " a vu "une chaîne entière comme un seul argument à ! - il a essayé de l'exécuter comme un fichier exécutable; et en conséquence il a échoué à trouver "echo 'A' 'B'" comme un fichier.

quoi qu'il en soit, dans le contexte de la citation git help config ci-dessus, je dirais qu'il est plus exact de dire quelque chose comme: ... l'invocation " git new "est équivalente à l'exécution de la commande shell" gitk --all --not ORIG_HEAD$@", où $@ sont les arguments passés à l'alias de la commande git depuis la ligne de commande à l'exécution. ... ". Je pense que cela expliquerait aussi, pourquoi l'approche "directe" en OP ne fonctionne pas avec les paramètres de position.

4
répondu sdaau 2013-04-22 20:10:40