Git псевдоним с позиционными параметрами
В основном я пытаюсь псевдоним:
git files 9fa3
... выполнить команду:
git diff --name-status 9fa3^ 9fa3
но git не передает позиционные параметры команде alias. Я пытался:
[alias]
files = "!git diff --name-status $1^ $1"
files = "!git diff --name-status {1}^ {1}"
... и несколько других, но те не работали.
Вырожденный случай будет:
$ git echo_reverse_these_params a b c d e
e d c b a
... как я могу заставить эту работу?
7 ответов
Наиболее очевидный способ - использовать функцию оболочки:
[alias]
files = "!f() { git diff --name-status \"$1^\" \"$1\"; }; f"
Псевдоним без !
рассматривается как команда Git; например commit-all = commit -a
,
С !
он запускается как отдельная команда в оболочке, позволяя вам использовать более сильную магию, подобную этой.
UPD
Поскольку команды выполняются в корне хранилища, вы можете использовать ${GIT_PREFIX}
переменная при обращении к именам файлов в командах
Псевдоним, который вы ищете:
files = "!git diff --name-status \"$1\"^ \"$1\" #"
С проверкой аргумента:
files = "!cd -- \"${GIT_PREFIX:-.}\" && [ x$# != x1 ] && echo commit-ish required >&2 || git diff --name-status \"$1\"^ \"$1\" #"
Финал#
важно - он предотвращает обработку всех пользовательских аргументов оболочкой (она их комментирует).
Замечания: git
помещает все предоставленные пользователем аргументы в конец командной строки. Чтобы увидеть это в действии, попробуйте: GIT_TRACE=2 git files a b c d
Экранированные (из-за вложенности) кавычки важны для имен файлов, содержащих пробелы или "; rm -rf --no-preserve-root /;
)
Вы также можете ссылаться sh
напрямую (вместо создания функции):
[alias]
files = !sh -c 'git diff --name-status $1^ $1' -
(Обратите внимание на черту в конце строки - она вам понадобится.)
Используйте GIT_TRACE=1, описанный на странице руководства git, чтобы сделать обработку псевдонимов прозрачной:
$ 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
Ваши оригинальные команды работают с git версии 1.8.3.4 (Eimantas отметил, что это изменилось в 1.8.2.1).
sh -c '..' --
а также f() {..}; f
оба варианта корректно обрабатывают параметры "$@" по-разному (см. с помощью GIT_TRACE). Добавление "#" к псевдониму также позволило бы позиционные параметры, не оставляя завершающих.
Как указано выше в Drealmer:
" Быть осторожен,! будет выполняться в корне хранилища, поэтому использование относительных путей при вызове псевдонима не даст ожидаемых результатов. - Drealmer 8 августа '13 в 16:28 "
GIT_PREFIX
Установив git в подкаталог, в котором вы находитесь, вы можете обойти это, сначала изменив каталог:
git config --global alias.ls '!cd "$ {GIT_PREFIX: -.}"; ls -al '
Я хотел сделать это с псевдонимом, который делает это:
git checkout $1;
git merge --ff-only $2;
git branch -d $2;
В конце я создал скрипт оболочки с именем git-m, который имеет следующее содержимое:
#!/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;
Преимущество в том, что он более разборчивый, потому что он состоит из нескольких строк. Плюс мне нравится возможность звонить Bash с -x
а также set -e
, Вероятно, вы можете сделать все это как псевдоним, но это было бы ужасно и трудно поддерживать.
Поскольку файл называется git-m
вы можете запустить его так: git m foo bar
Просто наткнулся на что-то подобное; надеюсь, что все в порядке, чтобы опубликовать мои заметки. Одна вещь, которая смущает меня о git
псевдонимы с аргументами, вероятно, происходит от git help config
(У меня git версия 1.7.9.5):
Если расширение псевдонима начинается с восклицательного знака, оно будет рассматриваться как команда оболочки. Например, при определении "alias.new =! Gitk --all --not ORIG_HEAD" вызов "git new" эквивалентен выполнению команды оболочки "gitk --all --not ORIG_HEAD". Обратите внимание, что команды оболочки будут выполняться из каталога верхнего уровня репозитория, который не обязательно может быть текущим каталогом. [...]
На мой взгляд, если псевдоним "будет обрабатываться как команда оболочки" с префиксом восклицательного знака, - зачем мне использовать функцию, или sh -c
с аргументами; почему бы просто не написать мою команду как есть?
Я до сих пор не знаю ответа - но я думаю, что на самом деле есть небольшая разница в результатах. Вот небольшой тест - бросьте это в свой .git/config
или ваш ~/.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 "
Вот что я запускаю эти псевдонимы:
$ 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/
... или: когда вы используете "обычную" команду после !
"как есть" в git
псевдоним - тогда git
автоматически добавляет список аргументов к этой команде! Способ избежать этого, действительно, вызвать ваш скрипт как функцию или как аргумент sh -c
,
Еще одна интересная вещь здесь (для меня), это то, что в сценарии оболочки обычно ожидается автоматическая переменная $0
быть именем файла сценария. Но для git
функция псевдонима, $0
Аргумент - это, в основном, содержимое всей строки, определяющей эту команду (как указано в файле конфигурации).
Вот почему, я полагаю, если вы ошибетесь в кавычках - в приведенном ниже случае это будет экранировать внешние двойные кавычки:
[alias]
# ...
fail = ! \"echo 'A' 'B'\"
... - затем git
потерпит неудачу с (для меня, по крайней мере) несколько загадочным сообщением:
$ git fail
"echo 'A' 'B'": 1: echo 'A' 'B': not found
fatal: While expanding alias 'fail': ' "echo 'A' 'B'"': No such file or directory
Я думаю, так как git
"видел" целую строку как только один аргумент !
- он попытался запустить его как исполняемый файл; и соответственно он не смог найти "echo 'A' 'B'"
как файл
В любом случае, в контексте git help config
цитата выше, я бы предположил, что точнее было бы сказать что-то вроде: " ... вызов" git new "эквивалентен выполнению команды оболочки"gitk --all --not ORIG_HEAD $@", где $ @ аргументы, переданные псевдониму команды git из командной строки во время выполнения.... ". Я думаю, это также объясняет, почему "прямой" подход в OP не работает с позиционными параметрами.