Git псевдоним с позиционными параметрами

261

В основном я пытаюсь псевдоним:

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

... как я могу заставить эту работу?

user400575
источник
17
Обратите внимание, что в git 1.8.2.1 это можно сделать без функции оболочки (ваш оригинальный подход с $1должен работать).
Eimantas
7
@Eimantas Не могли бы вы уточнить ответ? Это не работает для меня, и я не могу найти документацию по этому поводу.
павон
@Eimantas, хотя в примечаниях к выпуску об этом ничего нет .
Кну
1
я могу подтвердить, что могу выполнять команды оболочки с аргументами без каких-либо изменений в Git 2.11.
anarcat

Ответы:

365

Наиболее очевидный способ - использовать функцию оболочки:

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

Псевдоним без !рассматривается как команда Git; например commit-all = commit -a.

С помощью !он запускается как отдельная команда в оболочке, позволяя вам использовать более сильную магию, подобную этой.

UPD
Поскольку команды выполняются в корне хранилища, вы можете использовать ${GIT_PREFIX}переменную при обращении к именам файлов в командах

Cascabel
источник
8
Спасибо, это выглядит совершенно правильно: [alias] files = "! F () {echo $ 3 $ 2 $ 1;}; f"; $ git files abc => cba
user400575
1
@ KohányiRóbert: Это на самом деле не вопрос сценария оболочки; это особенность git config. Псевдоним без !рассматривается как команда Git; например commit-all = commit -a. С помощью !он запускается как отдельная команда в оболочке, позволяя вам использовать более сильную магию, подобную этой.
Каскабель
40
Будьте осторожны, он !будет запускаться в корне хранилища, поэтому использование относительных путей при вызове псевдонима не даст ожидаемых результатов.
Drealmer
4
@RobertDailey Это не ломает, просто не реализует. См. Stackoverflow.com/questions/342969/… чтобы узнать, как его добавить.
Каскабель
3
Примечание : здесь не приводятся аргументы (что в целом опасно). Кроме того, функция не нужна. Смотрите мой ответ для более подробного объяснения.
Том Хейл,
96

Вы также можете ссылаться shнапрямую (вместо создания функции):

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

(Обратите внимание на черту в конце строки - она ​​вам понадобится.)

mipadi
источник
8
Если вы делитесь командой, вы, вероятно, захотите ее использовать sh, поскольку она сама по себе является оболочкой и доступна в подавляющем большинстве систем. Использование оболочки по умолчанию работает, только если команда работает так, как написано для всех оболочек.
nomothetis
12
Я предпочитаю , --чтобы , -как это более знакомо и менее вероятно, случайно средний стандартный ввод в каком - то момент. («Аргумент - эквивалентен -» в bash (1) недоступен для просмотра)
bsb
5
Каково точное значение окончания «-» и где оно задокументировано?
Цитракс
5
Примечание : здесь не приводятся аргументы (что в целом опасно). Создание под-оболочки (с sh -c) также не требуется . Смотрите мой ответ для альтернативы.
Том Хейл
81

Псевдоним, который вы ищете:

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 -c.
Эд Рэндалл
4
Да, !уже подразумевается sh -c(показывается при добавлении GIT_TRACE=2), поэтому нет необходимости запускать другую вложенную оболочку. Какие проблемы вы видите в более сложных случаях?
Том Хейл,
Это работает, если вы хотите установить аргументы по умолчанию? например , я хочу сделать это , чтобы принести GitHub PR: fp = "! 1=${1:-$(git headBranch)}; 2=${2:-up}; git fetch -fu $2 pull/$1/head:$1; git checkout $1; git branch -u $2 #". Это прекрасно работает без первых двух утверждений, но падает, если вы их используете. (У меня headBranch = symbolic-ref --short HEADтак же).
gib
2
Работал его, это работает , если вы установите новый Params, так что это нормально: fp = "! a=${1:-$(git headBranch)}; b=${2:-up}; git fetch -fu $b pull/$a/head:$a; git checkout $a; git branch -u $b #".
gib
почему "цитаты обязательны?
Евгений Коньков
28

Используйте 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). Добавление «#» к псевдониму также позволило бы позиционные параметры, не оставляя завершающих.

BSB
источник
1
спасибо за объяснения: эти команды работают на исходную проблему, следуя вашим советам:files = "!git diff --name-status $1^ $1 #" files = "!git diff --name-status $1^"
user2291758
20

Как сказано выше Drealmer :

" Быть осторожен, ! будет выполняться в корне хранилища, поэтому использование относительных путей при вызове псевдонима не даст ожидаемых результатов. - Drealmer 8 августа '13 в 16:28 »

GIT_PREFIX Установив git в подкаталог, в котором вы находитесь, вы можете обойти это, сначала изменив каталог:

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

Пьер-Оливье Варес
источник
У меня тоже проблемы с этим (команды запускаются в корне хранилища), но это решение, похоже, ничего не делает. (Если это имеет значение, я использую OS X.)
Waldyrious
Упс ... Git alias - это псевдоним, который я сделал.
Пьер-Оливье Варес
(начиная с git 1.8.2) git config --set alias.alias = '! git config - псевдоним глобальный. $ 1 "$ 2" '
Пьер-Оливье Варес
Вот что в итоге сработало для меня: «добавьте к своим псевдонимам git (которые запускают команды оболочки и нуждаются в правильном pwd) cd ${GIT_PREFIX:-.} &&.» (источник: stackoverflow.com/a/21929373/266309 )
вальдер,
Цитируй это. !cd "${GIT_PREFIX:-.}" && ls -al
Мирабилось
8

Я хотел сделать это с псевдонимом, который делает это:

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;

Это имеет то преимущество, что это гораздо более разборчивыми , потому что это на несколько строк. Кроме того, я , как возможность позвонить Баш с -xи set -e. Вероятно, вы можете сделать все это как псевдоним, но это было бы ужасно и трудно поддерживать.

Поскольку файл назван, git-mвы можете запустить его так:git m foo bar

Даниэль Каплан
источник
1
Мне это тоже нравится намного больше, но я не смог понять, как использовать автозаполнение, которое я хочу, с этим подходом. На псевдонимах вы можете сделать это: '!f() { : git branch ; ... }; f'и он автоматически завершит псевдоним как ветвь, что очень удобно.
Hassek
Да, я думаю, что я предпочитаю делать нетривиальные вещи в виде отдельных файлов сценариев на пути. С другой стороны, да, вы теряете автоматическое завершение таких вещей, как ссылки. Вы можете исправить это, вручную настроив свое автозаполнение. Опять же, мне нравится, что вы можете просто поместить скрипт в папку на пути, и он начнет работать, но для автозаполнения вам нужно «загрузить» его, поэтому обычно он находится в моем .bashrcфайле, который я получаю. Но я не думаю, что я изменяю то, как я автоматически заполняю аргументы для скрипта так же, как сам скрипт, и это происходит только во время разработки.
июня
4

Просто наткнулся на что-то подобное; надеюсь, что все в порядке, чтобы опубликовать мои заметки. Одна вещь, которая путает меня в 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 не работает с позиционными параметрами.

sdaau
источник
хороший тест. Быстрый способ проверить все возможности!
Альбфан
failпытается выполнить команду с именем "echo 'A' 'B" (т. е. длиной 10 символов). Та же ошибка sh -c "'echo a b'"и та же причина, слишком много слоев цитат
bsb