remote - how to delete tag git
Git alias con parámetros posicionales. (7)
Básicamente estoy tratando de alias:
git files 9fa3
... para ejecutar el comando:
git diff --name-status 9fa3^ 9fa3
pero parece que git no pasa los parámetros posicionales al comando alias. Yo he tratado:
[alias]
files = "!git diff --name-status $1^ $1"
files = "!git diff --name-status {1}^ {1}"
... y algunos otros, pero esos no funcionaron.
El caso degenerado sería:
$ git echo_reverse_these_params a b c d e
e d c b a
... ¿cómo puedo hacer que esto funcione?
Acabo de tropezar con algo similar; Espero que sea bueno para publicar mis notas. Una cosa que me confunde acerca de los alias de git
con los argumentos, probablemente proviene de la git help config
(tengo la versión 1.7.9.5 de git):
Si la expansión de alias tiene un prefijo con un signo de exclamación, se tratará como un comando de shell. Por ejemplo, al definir "alias.new =! Gitk --all --not ORIG_HEAD", la invocación "git new" es equivalente a ejecutar el comando de shell "gitk --all --not ORIG_HEAD". Tenga en cuenta que los comandos de shell se ejecutarán desde el directorio de nivel superior de un repositorio, que puede no ser necesariamente el directorio actual. [...]
La forma en que lo veo, si un alias "se tratará como un comando de shell" cuando se prefija con un signo de exclamación, ¿por qué necesitaría usar una función, o sh -c
con argumentos; ¿Por qué no solo escribo mi orden como está?
Todavía no sé la respuesta, pero creo que en realidad hay una ligera diferencia en el resultado. Aquí hay una pequeña prueba: ~/.gitconfig
esto en su .git/config
o su ~/.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 "
Aquí es lo que me sale corriendo estos 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/
... o: cuando estás usando un comando "normal" después de !
"tal como está" en un alias de git
- ¡entonces git
agrega automáticamente la lista de argumentos a ese comando! Una forma de evitarlo es, de hecho, llamar a su script como una función, o como un argumento para sh -c
.
Otra cosa interesante aquí (para mí), es que en un script de shell, uno normalmente espera que la variable automática $0
sea el nombre de archivo del script. Pero para una función de alias de git
, el argumento de $0
es, básicamente, el contenido de toda la cadena que especifica ese comando (tal como se ingresó en el archivo de configuración).
Es por eso que, supongo, si se da una cita errónea, en el caso siguiente, se escaparía de las comillas dobles externas:
[alias]
# ...
fail = ! /"echo ''A'' ''B''/"
... - entonces git
fallaría con (para mí, al menos) un mensaje un tanto críptico:
$ git fail
"echo ''A'' ''B''": 1: echo ''A'' ''B'': not found
fatal: While expanding alias ''fail'': '' "echo ''A'' ''B''"'': No such file or directory
Creo que, ya que git
"vio" una cadena entera como solo un argumento para !
- trató de ejecutarlo como un archivo ejecutable; y, en consecuencia, no pudo encontrar "echo ''A'' ''B''"
como archivo.
En cualquier caso, en el contexto de la cita de git help config
anterior, yo especularía que es más exacto decir algo como: " ... la invocación" git new "es equivalente a ejecutar el comando de shell" gitk --all - -no ORIG_HEAD $ @ ", donde $ @ son los argumentos pasados al alias de comando git desde la línea de comando en tiempo de ejecución. ... ". Creo que eso también explicaría, por qué el enfoque "directo" en OP no funciona con parámetros posicionales.
El alias que buscas es:
files = "!git diff --name-status /"$1/"^ /"$1/" #"
Con validación de argumentos:
files = "!cd -- /"${GIT_PREFIX:-.}/" && [ x$# != x1 ] && echo commit-ish required >&2 || git diff --name-status /"$1/"^ /"$1/" #"
El #
final es importante: evita que todos los argumentos proporcionados por el usuario sean procesados por el shell (los comenta).
Nota: git
coloca todos los argumentos proporcionados por el usuario al final de la línea de comando. Para ver esto en acción, intente: GIT_TRACE=2 git files abcd
Las citas escapadas (debido al anidamiento) son importantes para los nombres de archivos que contienen espacios o "; rm -rf --no-preserve-root /;
)
La forma más obvia es usar una función de shell:
[alias]
files = "!f() { git diff --name-status /"$1^/" /"$1/"; }; f"
Un alias sin !
se trata como un comando Git; por ejemplo, commit-all = commit -a
.
Con el !
, se ejecuta como su propio comando en el shell, permitiéndote usar magia más fuerte como esta.
UPD
Debido a que los comandos se ejecutan en la raíz del repositorio, puede usar la variable ${GIT_PREFIX}
cuando ${GIT_PREFIX}
referencia a los nombres de archivo en los comandos
Quería hacer esto con un alias que hace esto:
git checkout $1;
git merge --ff-only $2;
git branch -d $2;
Al final, creé un script de shell llamado git-m que tiene este contenido:
#!/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;
Esto tiene la ventaja de que es mucho más legible porque está en varias líneas. Además, me gusta poder llamar a bash con -x
y set -e
. Probablemente puedas hacer todo esto como un alias, pero sería muy feo y difícil de mantener.
Debido a que el archivo se llama git-m
, puedes ejecutarlo así: git m foo bar
Según lo indicado por Drealmer above :
" Ten cuidado, ! se ejecutará en la raíz del repositorio, por lo que el uso de rutas relativas al llamar a su alias no dará los resultados que puede esperar. - Drealmer 8 de agosto de 13 a 16:28 »
GIT_PREFIX
configura GIT_PREFIX
en el subdirectorio en el que se encuentra, puede evitarlo cambiando primero el directorio:
git config --global alias.ls ''! cd "$ {GIT_PREFIX: -.}"; ls -al ''
También puede hacer referencia a sh
directamente (en lugar de crear una función):
[alias]
files = !sh -c ''git diff --name-status $1^ $1'' -
(Tenga en cuenta el guión al final de la línea; lo necesitará).
Use GIT_TRACE = 1 descrito en la página de manual de git para que el procesamiento de alias sea 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
Sus comandos originales funcionan con la versión 1.8.3.4 de git (Eimantas notó que esto cambió en 1.8.2.1).
El sh -c ''..'' --
y f() {..}; f
f() {..}; f
opciones f() {..}; f
ambas manejan limpiamente los parámetros "$ @" de diferentes maneras (ver con GIT_TRACE). Agregar "#" a un alias también permitiría los parámetros posicionales sin dejar los finales.