위치 매개 변수가있는 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

... 어떻게 작동시킬 수 있습니까?


17
git 1.8.2.1에서는 쉘 기능 없이이 작업을 수행 할 수 있습니다 (원래 접근 방식 $1이 작동해야 함).
Eimantas

7
@Eimantas 답변을 정교하게 작성 하시겠습니까? 그것은 나를 위해 작동하지 않으며 그것에 관한 문서를 찾을 수 없습니다.
pavon

@Eimantas 릴리스 노트 에는 이것에 대해 아무것도 없습니다 .
Knu

1
Git 2.11에서 shenanigans없이 인수로 쉘 명령을 실행할 수 있음을 확인할 수 있습니다.
anarcat

답변:


365

가장 확실한 방법은 쉘 함수를 사용하는 것입니다.

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

없는 별칭 !은 Git 명령으로 취급됩니다. 예 commit-all = commit -a.

을 사용하면 !쉘에서 자체 명령으로 실행되므로 이와 같은 강력한 마법을 사용할 수 있습니다.

UPD
명령은 저장소 루트에서 실행되므로 명령 ${GIT_PREFIX}에서 파일 이름을 참조 할 때 변수를 사용할 수 있습니다


8
감사합니다. 이것은 정확히 옳아 보입니다 : [alias] files = "! f () {echo $ 3 $ 2 $ 1;}; f"; $ 자식 파일 abc => cba
user400575

1
@ KohányiRóbert : 그것은 실제로 쉘 스크립트 질문이 아닙니다. 그것은 git config의 특별한 것입니다. 없는 별칭 !은 Git 명령으로 취급됩니다. 예 commit-all = commit -a. 을 사용하면 !쉘에서 자체 명령으로 실행되므로 이와 같은 강력한 마법을 사용할 수 있습니다.
Cascabel

40
조심 !당신이 기대하는 결과를 제공하지 않습니다 별명을 호출 할 때 그래서 상대 경로를 사용하여 저장소의 루트에서 실행됩니다.
Drealmer

4
@RobertDailey 그것은 그것을 깨뜨리지 않고 그것을 구현하지 않습니다. 추가 방법 은 stackoverflow.com/questions/342969/… 를 참조하십시오 .
Cascabel

3
참고 : 이것은 인수를 인용하지 않습니다 (일반적으로 위험합니다). 또한 기능이 필요하지 않습니다. 자세한 설명 은 내 답변 을 참조하십시오 .
Tom Hale

96

sh함수를 작성하는 대신 직접 참조 할 수도 있습니다 .

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

(줄 끝의 대시를 참고하십시오-필요합니다.)


8
명령을 공유하고 있다면 아마도 sh그 자체가 쉘이고 대부분의 시스템에서 사용할 수 있기 때문에을 사용하고 싶을 것입니다 . 기본 쉘 사용은 명령이 모든 쉘에 대해 작성된대로 작동하는 경우에만 작동합니다.
nomothetis

12
나는 친숙하고 우연히 stdin을 의미 할 가능성이 적기 때문에 선호 --합니다 -. (bash (1)에서 "-의 인수는-와 같습니다"는 Google에서 사용할 수 없습니다)
bsb


5
끝 '-'의 정확한 의미는 무엇이며 어디에 기록되어 있습니까?
Zitrax

5
참고 : 이것은 인수를 인용하지 않습니다 (일반적으로 위험합니다). 을 사용하여 서브 쉘을 작성하는 sh -c것도 필요하지 않습니다. 대안에 대한 내 대답 을 참조하십시오 .
Tom Hale

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로 감싸서 복잡하게 할 필요는 없습니다.
Ed Randall

4
예, ( ) 앞에 !이미 암시 되어 있으므로 다른 하위 셸을 실행할 필요가 없습니다. 더 복잡한 경우에 어떤 문제가 있습니까? sh -cGIT_TRACE=2
Tom Hale

기본 인수를 설정하려는 경우 작동합니까? 예를 들어 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
그것을 해결하고, 새로운 매개 변수를 설정하면 작동하므로 괜찮습니다 fp = "! a=${1:-$(git headBranch)}; b=${2:-up}; git fetch -fu $b pull/$a/head:$a; git checkout $a; git branch -u $b #".
gib

"따옴표가 필요한 이유 는 무엇입니까?
Eugen Konkov

27

별명 처리를 투명하게하려면 git man 페이지에 설명 된 GIT_TRACE = 1을 사용하십시오.

$ 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와 함께 참조). 별명에 "#"을 추가하면 후행 매개 변수를 떠나지 않고 위치 매개 변수를 사용할 수 있습니다.


1
설명 주셔서 감사합니다 : 그 명령은 당신의 조언에 따라 원래의 문제에 대해 나를 위해 작동합니다 :files = "!git diff --name-status $1^ $1 #" files = "!git diff --name-status $1^"
user2291758

20

위에서 Drealmer가 언급 한대로 :

" 조심해, ! 리포지토리의 루트에서 실행되므로 별칭을 호출 할 때 상대 경로를 사용하면 예상 한 결과를 얻지 못합니다. – Drealmer Aug 8 '13 at 16:28»

GIT_PREFIX git에 의해 당신이있는 하위 디렉토리로 설정되면, 먼저 디렉토리를 변경하여 이것을 우회 할 수 있습니다 :

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


이 문제 (저장소의 루트에서 실행되는 명령)에도 문제가 있지만이 솔루션은 아무것도하지 않는 것 같습니다. (중요하다면 OS X를 사용하고 있습니다.)
waldyrious

죄송합니다 ... 자식 별칭은 내가 만든 별칭입니다.
Pierre-Olivier Vares

(git 1.8.2부터) git config --set alias.alias = '! git config --global alias. $ 1 "$ 2" '
Pierre-Olivier Vares

"나를 위해 일한 결과 :"git aliases (쉘 명령을 실행하고 올바른 pwd를 필요로하는 접두사)와 함께 cd ${GIT_PREFIX:-.} &&."(source : stackoverflow.com/a/21929373/266309 )
waldyrious

이것을 인용하십시오. !cd "${GIT_PREFIX:-.}" && ls -al
mirabilos

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;

이것은 여러 줄로되어 있기 때문에 훨씬 더 읽기 쉽다 는 이점이 있습니다 . 플러스로 떠들썩한 파티를 호출 할 수있는 것 같아 I -xset -e. 이 모든 것을 별칭으로 할 수는 있지만 유지하기가 매우 어려울 것입니다.

파일 이름이 지정되었으므로 다음 git-m과 같이 실행할 수 있습니다.git m foo bar


1
나는 이것을 훨씬 더 좋아하지만이 접근법으로 원하는 자동 완성을 사용하는 방법을 알 수 없었습니다. 별칭에서 다음을 수행 할 수 있습니다 '!f() { : git branch ; ... }; f'. 별칭으로 별칭으로 자동 완성됩니다.
Hassek

예, 나는 사소한 일을 경로에서 개별 스크립트 파일로 수행하는 것을 선호한다고 생각합니다. 단점은 그렇습니다. 참조와 같은 것들의 자동 완성을 풉니 다. 그러나 자동 완성 기능을 수동으로 구성하여이 문제를 해결할 수 있습니다. 다시 말하지만, 경로의 폴더에 스크립트를 넣을 수 있고 작동하기 시작하지만 자동 완성을 위해 '로드'해야하므로 일반적으로 .bashrc소스 파일에 있습니다. 그러나 스크립트 자체만큼이나 인수를 자동 완성하는 방법을 변경하지 않는다고 생각합니다. 개발 기간에만 가능합니다.
thecoshman

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/

... 또는 : 별명 !에서 "있는 그대로" 뒤에 "plain"명령을 사용하는 경우 인수 목록을 해당 명령에 자동으로 추가합니다! 이를 피하는 방법은 실제로 스크립트를 함수 또는에 대한 인수로 호출하는 것 입니다.gitgitsh -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의 "직접"접근법이 위치 매개 변수와 함께 작동하지 않는 이유도 설명 할 것이라고 생각합니다.


좋은 시험. 모든 가능성을 확인하는 빠른 방법!
albfan

fail"echo 'A' 'B"(즉, 10 자 길이)라는 명령을 실행하려고합니다. 같은 오류 sh -c "'echo a b'"와 같은 원인, 너무 많은 인용문 계층
bsb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.