web-dev-qa-db-fra.com

Git alias avec paramètres de position

Fondamentalement, j'essaie de créer un alias:

git files 9fa3

... pour exécuter la commande:

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

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

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

... et quelques autres mais cela n'a pas fonctionné.

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?

236
user400575

Le moyen le plus évident consiste à utiliser une fonction Shell:

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

Un alias sans ! est traité comme une commande Git; par exemple. commit-all = commit -a.

Avec le !, il est exécuté comme sa propre commande dans le shell, vous permettant ainsi d’utiliser une magie plus puissante.

UPD
Les commandes étant exécutées à la racine du référentiel, vous pouvez utiliser ${GIT_PREFIX} variable en faisant référence aux noms de fichier dans les commandes

338
Cascabel

Vous pouvez également référencer directement sh (au lieu de créer une fonction):

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

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

89
mipadi

L'alias que vous recherchez est:

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

Avec validation des arguments:

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

Le final # est important - il empêche le shell de traiter tous les arguments fournis par l'utilisateur (il les commente).

Remarque: 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

Les guillemets échappés (= dus à l’imbrication) sont importants pour les noms de fichiers contenant des espaces ou "; rm -rf --no-preserve-root /;)

72
Tom Hale

Utilisez GIT_TRACE = 1 décrit dans la page de manuel git pour rendre le traitement des alias 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

Vos commandes originales fonctionnent avec la version 1.8.3.4 de Git (Eimantas a noté cette modification dans la 1.8.2.1).

Les options sh -c '..' -- Et f() {..}; f gèrent proprement les paramètres "$ @" de différentes manières (voir avec GIT_TRACE). Ajouter "#" à un alias permettrait également des paramètres de position sans quitter les derniers.

24
bsb

Comme l'a déclaré Drealmer ci-dessus :

" Faites attention, ! s’exécutera à la racine du référentiel. Par conséquent, l’utilisation de chemins relatifs lors de l’appel de votre alias ne donnera pas les résultats escomptés. - Drealmer 8 août 13 à 16:28 "

GIT_PREFIX étant défini par git dans le sous-répertoire dans lequel vous vous trouvez, vous pouvez le contourner en modifiant d’abord le répertoire:

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

17
Pierre-Olivier Vares

Je voulais faire cela avec un alias qui fait ceci:

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

En fin de compte, j'ai créé un script Shell nommé 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 $1;
git merge --ff-only $2;
git branch -d $2;

Cela a l'avantage d'être beaucoup plus lisible car il se trouve sur plusieurs lignes. De plus, j'aime pouvoir appeler bash avec -x et set -e. Vous pouvez probablement faire toute cette affaire en tant que pseudonyme, mais ce serait super laid et difficile à maintenir.

Parce que le fichier s'appelle git-m vous pouvez le lancer comme ceci: git m foo bar

8
Daniel Kaplan

Juste heurté quelque chose de similaire; J'espère que c'est OK pour poster mes notes. Une chose qui me perturbe à propos de git alias avec arguments, vient probablement du git help config _ (J'ai la version 1.7.9.5 de Git):

Si le développement de l'alias est précédé d'un point d'exclamation, il sera traité comme une commande Shell. Par exemple, si vous définissez "alias.new =! Gitk --all --not ORIG_HEAD", l'invocation "git new" équivaut à exécuter la commande Shell "gitk --all --not ORIG_HEAD". Notez que les commandes Shell seront exécutées à partir du répertoire de niveau supérieur d'un référentiel, qui peut ne pas être nécessairement le répertoire actuel. [...]

La façon dont je le vois - si un alias "sera traité comme une commande Shell" lorsqu'elle porte le préfixe 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 connais toujours pas la réponse - mais je pense qu’il ya 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[[\"$0\"]] 1-\"$1\"/ A-"$@"/ "
  fechargs = "! f() { echo 0[[\"$0\"]] 1-\"$1\"/ A-"$@"/ ; }; f "

Voici ce que je lance avec 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[["$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: lorsque vous utilisez une commande "plain" après le ! "tel quel" dans un alias git - alors git ajoute automatiquement la liste des arguments à cette commande! Une façon de l'éviter, en effet, consiste à appeler votre script soit comme une fonction, soit comme argument de sh -c.

Une autre chose intéressante ici (pour moi), est que dans un script Shell, on attend généralement la variable automatique $0 être le nom du fichier du script. Mais pour une fonction git alias, le $0 L'argument est, en gros, le contenu de la chaîne entière spécifiant cette commande (telle que saisie dans le fichier de configuration).

C’est pourquoi, je suppose, s’il vous arrivait de mal citer - dans le cas ci-dessous, cela échapperait aux 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, puisque git "a vu" toute une chaîne comme un seul argument pour ! - il a essayé de l'exécuter en tant que fichier exécutable; et en conséquence, il n'a pas trouvé "echo 'A' 'B'" sous forme de fichier.

En tout cas, dans le contexte de la git help config citation ci-dessus, je dirais qu'il est plus précis de dire quelque chose comme: "... l'invocation" git new "équivaut à exécuter la commande Shell" gitk --all --not ORIG_HEAD $ @ ", où $ @ sont les arguments passés à la commande git à partir de la ligne de commande à l'exécution. ...". Je pense que cela expliquerait également pourquoi l'approche "directe" dans OP ne fonctionne pas avec les paramètres de position.

4
sdaau