git grep
の exclude を指定する。[alias]
grep-with-exclude = !git grep $@ -- ':!*.svg' && :
[alias]
grep-with-exclude = !git grep --line-number -I --show-function --heading --break $@ -- ':!*.svg' ':!*/package-lock.json' ':!*/yarn.lock' ':!*/Gemfile.lock' && :
g = grep-with-exclude --ignore-case
G = grep-with-exclude
# fgrep
f = grep-with-exclude --fixed-strings --ignore-case
F = grep-with-exclude --fixed-strings
# egrep
e = grep-with-exclude --extended-regexp --ignore-case
E = grep-with-exclude --extended-regexp
「確かバージョン 1.0 指定したはずだな…」と思って git grep '1\.0'
とか打つと、大抵 svg ファイルや Gemfile.lock や package-lock.json などから大量に不要な情報がヒットする現象、発生しがちじゃないですか。これ伝わると思う。
けど git grep
に除外パターンを指定するのは結構しんどくて、 git grep '1\.0' -- ':!*.svg' ':!*/package-lock.json' ':!*/yarn.lock' ':!*/Gemfile.lock'
などと打つ必要があり、とにかくダルい。なんとかできないかなとずっと (15年くらい) 思ってたけど、なんとかしたという話。
!
で始めて書くとシェルコマンドとして扱われる。git grep
に渡している --
は、シェルにおいてこれ以降はオプションではなく引数として扱ってね、と明示するためのもの。 -f
というファイルがあったとして、それを消したいときに rm -- -f
という使い方をする。$@
で grep-with-exclude
に渡した引数の位置をここに持ってくる。:
というコマンドを &&
で繋げてやる。 :
というコマンドはシェルスクリプトを書くときにも重宝するやつで、例えば set -e
してる環境で終了コードが 0 以外になるものを取りたいときに && :
で繋げてやると、スクリプトの終了は抑制しつつ終了コードを取ることができる。git grep
のオプションで
--line-number
-I
--show-function
--heading
--break
あたりは付けたいので付けておいて、 git g
で git grep
するようにしつつ、大文字小文字の区別や egrep
, fgrep
を使うときの alias まで書くと上のような感じになるかな、というところ。
GIT_TRACE
環境変数に 1 とか true を放り込みながら git
コマンドを実行すると alias がどう解決されて、どう実行されているのかデバッグすることができる。
$ GIT_TRACE=1 git g '1\.0'
17:09:31.602057 git.c:749 trace: exec: git-g '1\.0'
17:09:31.602774 run-command.c:659 trace: run_command: git-g '1\.0'
17:09:31.603284 git.c:407 trace: alias expansion: g => grep-with-exclude
17:09:31.603527 git.c:749 trace: exec: git-grep-with-exclude '1\.0'
17:09:31.603533 run-command.c:659 trace: run_command: git-grep-with-exclude '1\.0'
17:09:31.604084 run-command.c:659 trace: run_command: 'git grep --line-number -I --show-function --heading --break $@ -- '\'':'\!'*.svg'\'' '\'':'\!'*/package-lock.json'\'' '\'':'\!'*/yarn.lock'\'' '\'':'\!'*/Gemfile.lock'\'' && :' '1\.0'
17:09:31.622676 run-command.c:659 trace: run_command: unset GIT_PAGER_IN_USE; LV=-c less
17:09:31.625115 git.c:463 trace: built-in: git grep --line-number -I --show-function --heading --break '1\.0' -- ':'\!'*.svg' ':'\!'*/package-lock.json' ':'\!'*/yarn.lock' ':'\!'*/Gemfile.lock'
こういう感じになり、 git g
に渡した '1\.0'
引数がちゃんと $@
で指定した位置に渡されていて、末尾に渡されるものに関しては && : '1\.0'
となって無事無視されており、期待通りに動いていることが分かる。
ちなみに GIT_TRACE
以外にも GIT_TRACE_SETUP
や GIT_CURL_VERBOSE
環境変数もあるらしい。
前回ブログ書いたのが 1 年前で吃驚した。