gitのfilterはRepoのルートから実行される話
そんな話。
ケツ論
filterはリポジトリのルートディレクトリから実行されるのでパスとか指定する時はそう考えていいと思うでござる。
は?
順を追って説明します。
filter何ぞ
filterはgit-configで指定できる挙動で、指定されたファイルがワーキングディレクトリからステージングエリアにgit-addされる際に自動で処理されるコマンドです。
めっちゃ分かりやすいスーパージーニアス図作ったので見て
使うケース
手前味噌。
私のdotfilesで、インスコディレクトリを格納する変数DOTDIR
を.zshenv
の先頭行で指定しているのですが、これは環境によるので、DOTDIR
定義の行だけステージングしたくないのです。そしてもちろんリポジトリから引っ張ってくるときにはDOTDIR
定義の行が存在しなければなりません。そこで使うのがステージングの前後に走るfilterです。
先述の通り問題の行は.zshenv
の先頭行にあるので、
.zshenv
のステージング前に、先頭行を除く.zshenv
のチェックアウト前に、自分の環境のために先頭行を補修する
やってみます
やってみます
やってみます。
まずgit-config
でフィルタを定義します。形式はgit config filter.<filter_name>.<case> <command>
です。caseはステージング前(clean)とチェックアウト前(sumdge)があります。
git config filter.dotdir.clean "tail -n +2 `pwd`/.zshenv" git config filter.dotdir.smudge "echo export DOTDIR=`pwd`; cat .zshenv"
これでステージング前に先頭行がカットされ、リポジトリにはDOTDIR
定義行が登録されません。そして、リポジトリからチェックアウトする際は定義行が修復されます。そんなフィルタdotdir
を定義できました。
お気づきかと思いますが、これにはコマンドのリダイレクトやteeは使っていません。フィルタ処理は対象ファイルをストリームの出力としていることに注意してください。エラーはどうなってるか知らね
もちろん空白を含むコマンドを使う場合はクォーテーションで括る必要があります。これが気持ち悪かったらフィルタ処理をするシェルスクリプトを作ってユーザ実行権限を与え、filterから走らせるといいと思います。
注意
git-config
コマンドはリポジトリの.git/config
を対象とする操作ですので、フィルタの定義は共有できません。シンボリックリンクを張ったりするプラクティスがありますが、これはhooksに対してはいいのですが、configは人によってはuserの使い分けなどで個人の設定が入る可能性があります。フィルタを共有したい場合はフィルタの設定をリポジトリ管理下の別ファイルに記述し、.git/config
からincludeするようにするといいと思います。
話は戻して、次に.gitattributes
にファイル名でフィルタを登録します。
.zshenv filter=dotdir
.gitattributes
はリポジトリの配下となりますが、これをコミットしたくない場合(プロジェクトではなく個人の設定である場合)はgitignoreするのではなく、コミットしたくない属性内容を.git/info/attributes
に記述するようにするといいです。
ログファイルを作ってフィルタを通すことでテストなんかもできますが、テストはpre-pushなどのフックにかけるプラクティスが多いように思います。
本題
filterが何かなんて今回は別にどうでもよくてですね、今回の本題はpwdコマンド、あるいはシェルスクリプトを作成した場合のパスの指定をする際、実行パスはどうなってんのって話です。
結論だけ言います「ユーザがgit-*
コマンドを実行してる場所かな?だったら面倒くさいなとか思ったけどリポジトリのルートディレクトリでした。賢い」です。
例えば.git-filter/hoge.clean
を作り、chmod u+x .git-filter/hoge.clean
として、フィルタでこれを走らせたい時パス指定は
git config filter.hoge.clean .git-filter/hoge.clean
とすれば大丈夫です。リポジトリ内のどこにいても(パスに関しては)正常に動きます。ポイントは実行パスはリポジトリのルートということ。
余談ですが、フックも同じですね。実質git-filterの紹介記事でした