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