位置パラメーターを持つ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 2013

7
@Eimantas回答を詳しく説明していただけませんか?それは私にはうまくいきません、そしてそれについてのドキュメントを見つけることができません。
pavon

@Eimantas リリースノートには、これについては何もありません。
Knu

1
私は、Git 2.11でシェナンガンなしで引数付きのシェルコマンドを実行できることを確認できます。
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"; $ git files abc => cba
user400575

1
@KohányiRóbert:それは実際にはシェルスクリプトの質問ではありません。これはgit configに特有のものです。なしのエイリアス!はGitコマンドとして扱われます。例えばcommit-all = commit -a。を使用する!と、シェルで独自のコマンドとして実行され、このような強力な魔法を使用できます。
Cascabel、2011年

40
!はリポジトリのルートで実行されるので注意してください。エイリアスを呼び出すときに相対パスを使用しても、期待した結果が得られません。
Drealmer 2013

4
@RobertDaileyそれはそれを壊さない、それはそれを実装しないだけです。追加方法については、stackoverflow.com / questions / 342969 /…を参照してください。
Cascabel 2014年

3
:これは引数を引用しません(これは一般に危険です)。また、機能は不要です。詳細については、私の回答を参照しください。
トム・ヘイル

96

sh(関数を作成する代わりに)直接参照することもできます。

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

(行末のダッシュに注意してください-必要になります。)


8
コマンドを共有している場合shは、それ自体がシェルであり、ほとんどのシステムで使用できるため、おそらくを使用する必要があります。デフォルトのシェルの使用は、コマンドがすべてのシェルに対して記述されたとおりに機能する場合にのみ機能します。
nomothetis

12
私が好む---、それはいくつかの点で誤っ平均STDINに、より身近でより少ない可能性がありますよう。(bash(1)の "-の引数は-と同等です"
bsb


5
末尾の「-」の正確な意味は何ですか?どこに記載されていますか?
Zitrax

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でラップして複雑にする必要はありません。
Ed Randall

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 #"。これは最初の2つのステートメントがなくてもうまく機能しますが、使用すると落ちます。(私も持ってheadBranch = symbolic-ref --short HEADいます)。
ギブ

2
うまくいきました。新しいパラメータを設定すると機能するので、これで問題ありませんfp = "! a=${1:-$(git headBranch)}; b=${2:-up}; git fetch -fu $b pull/$a/head:$a; git checkout $a; git branch -u $b #"
2017

なぜ"見積もりが必要なのですか?
Eugen Konkov 2018年

28

エイリアスの処理を透過的にするには、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で変更されたことに注意しました)。

オプションの両方きれいに異なる方法でパラメータ「@ $を」(GIT_TRACEを参照)を扱います。エイリアスに「#」を追加すると、末尾のパラメータを残さずに位置パラメータも許可されます。sh -c '..' --f() {..}; f


1
説明に感謝:これらのコマンドは、あなたのアドバイスに従って、元の問題で私のために機能します:files = "!git diff --name-status $1^ $1 #" files = "!git diff --name-status $1^"
user2291758

20

上記の Drealmerによって述べられたように

" 注意してください、 !はリポジトリのルートで実行されるため、エイリアスを呼び出すときに相対パスを使用しても、期待した結果が得られません。– Drealmer 2013年8月8日16:28»

GIT_PREFIX あなたがいるサブディレクトリにgitによって設定されているので、最初にディレクトリを変更することでこれを回避することができます:

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


これにも問題があります(コマンドはリポジトリのルートで実行されています)が、このソリューションでは何も実行されないようです。(問題がある場合、私はOS Xを使用しています。)
危険な

おっと... gitエイリアスは私が作ったエイリアスです。
Pierre-Olivier Vares

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

これは私のために機能するようになったものです:「プレフィックスあなたのgitエイリアス(シェルコマンドを実行し、正しいpwdが必要です)cd ${GIT_PREFIX:-.} &&.」(ソース: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;

これは、だという利点があるくらい、それは複数の行にありますので、読みやすくします。プラスではbashを呼び出すことができるというようなI -xset -e。たぶん、エイリアスとしてこのすべてを行うことができますが、非常に醜く、維持するのが困難です。

ファイルには名前が付いているので、次のgit-mように実行できます。git m foo bar


1
私もこれがもっと好きですが、このアプローチでオートコンプリートを使用する方法を理解できていません。エイリアスではこれを行うことができます:'!f() { : git branch ; ... }; f'そしてそれは非常に便利なブランチとしてエイリアスをオートコンプリートします。
Hassek

ええ、私は重要なことをパス上の個々のスクリプトファイルとして実行することを好むと思います。欠点はイエスですが、参照などの自動補完が失われます。ただし、独自のオートコンプリートを手動で構成することで、これを修正できます。繰り返しになりますが、スクリプトをパス上のフォルダーにドロップするだけで機能するようになりますが、オートコンプリートの場合は、スクリプトを 'ロード'する必要があるため、通常.bashrcはソースファイルにあります。しかし、スクリプトへの引数のオートコンプリート方法をスクリプト自体ほど変更することはないと思います。これは、開発中のみです。
thecoshman

4

ちょうど同じようなものにぶつかった。私のメモを投稿してよいと思います。gitエイリアスと引数について私を混乱させる1つのことは、おそらく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です。

ここでもう1つ興味深いのは(私にとって)、シェルスクリプトでは、通常、自動変数$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 2013

fail「echo 'A' 'B」(つまり、10文字)というコマンドを実行しようとしています。同じエラーsh -c "'echo a b'"、同じ原因、引用符の層が多すぎる
bsb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.