matrk's blog

十中八九Python書いてる

gitのfilterはRepoのルートから実行される話

そんな話。

ケツ論

filterはリポジトリのルートディレクトリから実行されるのでパスとか指定する時はそう考えていいと思うでござる。

は?

順を追って説明します。

filter何ぞ

filterはgit-configで指定できる挙動で、指定されたファイルがワーキングディレクトリからステージングエリアにgit-addされる際に自動で処理されるコマンドです。

めっちゃ分かりやすいスーパージーニアス図作ったので見て

f:id:matrk:20160228114002p:plain

使うケース

手前味噌。 私のdotfilesで、インスコディレクトリを格納する変数DOTDIR.zshenvの先頭行で指定しているのですが、これは環境によるので、DOTDIR定義の行だけステージングしたくないのです。そしてもちろんリポジトリから引っ張ってくるときにはDOTDIR定義の行が存在しなければなりません。そこで使うのがステージングの前後に走るfilterです。

先述の通り問題の行は.zshenvの先頭行にあるので、

  1. .zshenvのステージング前に、先頭行を除く
  2. .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の紹介記事でした