git config alias
Gitでエイリアスを追加したい時は
$ git config --global alias.st status
などとすると、~/.gitconfig
へ
[alias]
st = status
という行が付け加えられ、今後
$ git st
とすると、git status
とした時と同じ結果が見られます。
--global
を除けば現在の作業リポジトリのみに反映される様に.git/config
へ追加されます。
もちろん、~/.gitconfig
等に直接[alias]
下にコマンドを書いていってもOK。
複数の文字を与えても良くて
ci = commit -a
としておけばgit ci
でgit commit -a
が使えます。
外部コマンドを渡す
与えるコマンドが!
から始まると、外部コマンドとしてそのコマンドを直接実行します。
~/.gitconfig
で
echo = !echo test
としてみると、
$ git echo
test
単にecho test
を実行してるだけです
1。
細かくやっていることを見て見るためには
環境変数のGIT_TRACE
を1
にします。
常に有効にするなら
$ export GIT_TRACE=1
(戻すには0に)、一時的に行いたい時はコマンドの前に書いて
$ GIT_TRACE=1 git echo
trace: exec: 'git-echo'
trace: run_command: 'git-echo'
trace: run_command: 'echo test'
trace: exec: '/bin/sh' '-c' 'echo test' 'echo test'
test
こんな感じで、TRACEオプションを有効にすると エイリアスがどう解釈されてるかも表示してくれます。
git-echo
が実行されて、それがecho test
と解釈され
実行されてるのが分かります。
最後の行にecho test
が二つありますが、
下を見ると分かりますがこの部分では引数の展開前後を示しています。
引数を渡す
さて、上のechoコマンドにそのまま引数を渡すと
$ GIT_TRACE=1 git echo hoge
trace: exec: 'git-echo' 'hoge'
trace: run_command: 'git-echo' 'hoge'
trace: run_command: 'echo test' 'hoge'
trace: exec: '/bin/sh' '-c' 'echo test "$@"' 'echo test' 'hoge'
test hoge
単に後ろにくっついただけです。
引数を任意の場所で使うためには関数を作って渡すようにするのが簡単です。
~/.gitconfig
に
echo2 = "!f () { echo $1;};f"
と言ったエイリアスを加えて見ます。最初に!
で外部コマンドであることを教えて、後は
1 2 3 4 |
|
といった感じでecho
するだけの関数を作って最後にその関数を実行してるだけです。
注意として、ワンライナーで書こうとするときに()
の両側の空白を忘れたり、
{}
内で;
を忘れたり、{
の後に空白を入れ忘れたり、
最後の関数後の;
を忘れたりしないように。
実行結果はこんな感じ。
$ GIT_TRACE=1 git echo2 test1 test2
trace: exec: 'git-echo2' 'test1' 'test2'
trace: run_command: 'git-echo2' 'test1' 'test2'
trace: run_command: 'f () { echo $1;};f' 'test1' 'test2'
trace: exec: '/bin/sh' '-c' 'f () { echo $1;};f "$@"' 'f () { echo $1;};f' 'test1' 'test2'
test1
最後のf
関数に続いてそのまま引数が書かれるので、関数に直接引数を与えてることになります。
これで、第一引数のtest1
だけがecho
されてます。
また、sh
にコマンドとして渡す様に、こんな感じで書くことも出来ます。
echo3 = "!sh -c 'echo ${0}'"
ただし、この場合、引数が0
から始まるので気をつけて下さい。
関数の場合と比べるためにこんなエイリアスを~/.gitconfig
に書いて確かめてみます。
echo-f = "!f () { echo 0: ${0};echo 1: ${1};echo 2: ${2}};f"
echo-sh = "!sh -c 'echo 0: ${0};echo 1: ${1};echo 2: ${2}'"
echo-f
の方は
$ GIT_TRACE=1 git echo-f a b c
trace: exec: 'git-echo-f' 'a' 'b' 'c'
trace: run_command: 'git-echo-f' 'a' 'b' 'c'
trace: run_command: 'f () { echo ${0};echo ${1};echo ${2};};f' 'a' 'b' 'c'
trace: exec: '/bin/sh' '-c' 'f () { echo ${0};echo ${1};echo ${2};};f "$@"' 'f () { echo ${0};echo ${1};echo ${2};};f' 'a' 'b' 'c'
0: f () { echo ${0};echo ${1};echo ${2};};f
1: a
2: b
こんな感じに${0}
には関数そのものが入っています。
一方、echo-sh
の方は
$ GIT_TRACE=1 git echo-sh a b c
trace: exec: 'git-echo-sh' 'a' 'b' 'c'
trace: run_command: 'git-echo-sh' 'a' 'b' 'c'
trace: run_command: 'sh -c '\''echo ${0};echo ${1};echo ${2}'\''' 'a' 'b' 'c'
trace: exec: '/bin/sh' '-c' 'sh -c '\''echo ${0};echo ${1};echo ${2}'\'' "$@"' 'sh -c '\''echo ${0};echo ${1};echo ${2}'\''' 'a' 'b' 'c'
0: a
1: b
2: c
の様に${0}
から詰まっています。
この辺の混乱を避ける為に(?)、shを使う時は
echo-sh = "!sh -c 'echo 0: ${0};echo 1: ${1};echo 2: ${2}' -"
こんな感じで1つ引数を予め渡して置いて、関数の場合と同じように${1}
から始める
様にしておくのも結構見られます
2。
実行されるディレクトリ
gitコマンドなので、リポジトリ内で実行する時、 必ずそのリポジトリのトップでコマンドが実行されます。
pwd = !pwd
みたいなコマンドで色んな所でgit pwd
してみれば確認出来ます。
より長いコマンド
git submoduleについてのメモ で書いたsubmoduleの追加と削除を1つのコマンドにしてみます。
長いコマンドを書く時は行末に \
を付けて改行して書いていくことが出来ます。
注意点としてはthen
やdo
またelse
の後に必ず空白を入れてから \
を付けること、
それ以外の場所で;
を忘れないこと、等。
submoduleの追加については、レポジトリのpathを与えて、第二引数があれば その名前のディレクトリ下に配置する様に。
smad = "!f () {\
if [ $# -lt 1 ];then \
echo \"Usage: git smad <git_repo_path> [submodule parent path]\";\
exit;\
fi;\
git_repo=${1};\
repo_name=${git_repo#*/};\
repo_name=${repo_name%.git};\
echo git submodule add ${git_repo} ./${2}/${repo_name};\
git submodule add ${git_repo} ./${2}/${repo_name};\
};f"
リポジトリ名に.git
まで付けてた場合に取り除くこともしています。
$ git submodule add [email protected]:rcmdnk/evernote_mail.git ./submodules/evernote_mail
としていたのを
$ git smad [email protected]:rcmdnk/evernote_mail.git ./submodules
と出来ます(余り減ってないか。。。)。
submoduleの削除についてはこんな感じで。
smrm = "!f () {\
if [ $# -ne 1 ];then \
echo \"Usage: git smrm <path/to/submodule>\";\
exit;\
fi;\
sm=${1%/};\
echo git config --remove-section submodule.${sm};\
git config --remove-section submodule.${sm};\
echo git config --file .gitmodules --remove-section submodule.${sm};\
git config --file .gitmodules --remove-section submodule.${sm};\
echo git rm --cached ${sm};\
git rm --cached ${sm};\
gitdir=./;\
gitfile=.git;\
while : ;do \
if [ -f $gitfile ];then \
gitfile=${gitdir}/$(awk '/gitdir/ {print $2}' ${gitfile});\
else \
gitdir=${gitfile};\
break;\
fi;\
done;\
if [ -n \"${gitdir}\" ];then \
echo rm -rf ${gitdir}/modules/${sm};\
rm -rf ${gitdir}/modules/${sm};\
fi;\
echo rm -rf ${sm};\
rm -rf ${sm};\
};f"
使い方は
$ git smrm ./submodules/evernote_mail
こんな感じで。modules
以下を消しているのは
に追記してあるゴミを消すため。 最後にもう一度submoduleのディレクトリを直接消してますが、これもたまに ゴミが残っている時に対処するためです。
サブコマンドを作る
追記: 2017/10/01
エイリアスで複雑なことをしようとすると上みたいに結構面倒ですが、 複雑なことをする場合にはサブコマンドを作ってしまうのも1つの手です。
PATHが通ったディレクトリにgit-mycommand
といったgit-
と付いた実行ファイルを入れておくと
$ git mycommand
と実行できる様になります。 この実行ファイルはシェルスクリプトでもC++で書いてコンパイルしたものでも なんでも構いません。 Gitに全く関係ないものでも使えます。
このコマンドはそのままgit-mycommand
を実行したのと同じ様なものなので
引数等もそのまま使えます。
上のエイリアスをサブコマンドにするなら、
1 2 3 4 5 6 7 8 9 10 11 |
|
みたいなシェルスクリプトをPATHが通ったディレクトリに置いておけば エイリアスのときと同様に使えます。
追記ここまで
まとめ
こんな感じで関数を使えばシェルスクリプトがそのまま書けるので
git
のコマンドになんでも加えられます。
単純にエイリアスで良ければ普通のalias
でgit-*
的なコマンドを
作ってしまっても良いかも知れませんが。
(そしてそれを更にgitのエイリアスにしたり。。。)