pathspec 除外を使って gitignore を変更せずに特定パスを除外してコミットするメモ

pathspec 除外を使って gitignore を変更せずに特定パスを除外してコミットするメモ

pathspec 除外を使って gitignore を変更せずに特定パスを除外してコミットするメモです。

背景

.gitignore は便利です。これでたいていなんとかなります。恒常的に何を追跡するかにおいてはうまくいきますね。

でも実際に運用していると「普段は見えていてほしい」「コミットするときだけは、そのフォルダを引き続き除外したい。」。たとえば「使い捨ての専用フォルダ」のようなもの。ふだんはエディタや閲覧ツールで中身を見られてほしいけど git の履歴には残したくない。みたいな用途です。

最初に考えたのは、コミットするタイミングだけ .gitignore の該当行を一時的に有効化し、コミットが終わったらまたコメントアウトして無効化に戻す、という実装したんですけど、だめですね、人力でもたまに忘れる。AI で自動化してみたけど AI は処理が揺れるので人間よりも抜け漏れが起きました。

しかも、一度でもコミットされたら追跡されるので避けたいという欲張り仕様。

そして、調べていたら、pathspec 除外を使って gitignore を変更せずに特定パスを除外してコミットできることはが分かりました。

git add の pathspec でその場で除外できる

.gitignore には一切触れず git add のパススペック(pathspec)機能で「今回のステージングだけ」特定パスを除外します。

git add . ':!*/sessions/*'

こんなコマンドです。なんかワンライナーのコード、あるいは、詠唱圧縮された魔法のように見えるので細かく解説します。

:! 部分が :(exclude) の短縮形です。で、「.(配下全部)にマッチするファイル群から、*/sessions/*にマッチするものを差し引く」という集合演算を、実行のその場で行っているだけです。

結構、昔からあるようで git 1.9以降(2013年12月導入あたりかな?)で使える標準機能で、特別なプラグインなどは不要でした。便利。

ファイルを書き換えるわけではなく、git add 実行時にその場でパターンを評価するだけなので状態を戻し忘れるという失敗が生じにくいのがいいですね。

注意点 : 効かないケースとクォートの注意

一つだけ注意点があって、すでに git add -f などで対象パス配下のファイルが追跡済みになっている場合は効きませんでした。まあそうですね。

この pathspec はあくまで新規追加候補からの除外です。すでに追跡されているファイルの変更は普通にステージされます。

この場合は、先に

git rm --cached path/to/file

で追跡を外す必要があります。

もう一つはシェルの展開ですね。

コマンドラインで直接打つ場合は ':!*/sessions/*' のように逃がさないと、シェルがグロブ展開したり変な挙動になり実行が失敗します。

知見は得たのはよかったが対応フローを見直すのも大事そう

うん、使えるところはありそう。実際に役に立った。「ファイルを書き換えて元に戻す」実装よりははるかに事故が少ない。

ただ、なんか git add に追加情報を加えるのもまあまあ、普段の対応フローではないので、こういう例外で抜くような処理が、そもそも必要なのかどうか、もっと大きく回避できる対応方法がないかというのは考えたほうがよさそうです。

実際、これで成功したプロジェクトでも、そもそもそういうファイルを git 外に逃がして、プログラム的な参照だけを引くみたいにしたらスッキリできたこともありました。奥が深いですね。このあたり。