no7.space
💻

git config を状況に応じて付け替える

Git のプロジェクトを触るときに、仕事用とプライベートで異なる設定(メールアドレスとか、署名用の鍵とか)を使いたいというシーンって珍しくないと思います。
(そもそも仕事用のパソコンでプライベートなリポジトリ開くなよという意見は一旦おいておくとして……)

実は昔似たような状況になったことがあって、そのときは、シェルスクリプトをつかって裏で git config --local コマンドを自動で設定させてたんですが、
署名の設定とかまでやるとけっこう大変だなっておもって、もうそれならどこかの完成済みな .git/config の内容をコピーしておいてこれを毎回リポジトリにコピーするスクリプトでも作ろうかなって思って調べ始めてみたところ、Git の設定ファイルは分割して管理できる(インクルード機能がある)上に、さらにインクルード条件を指定することもできるということを知り、これを使うのが一番スマートそうだなということでそちらでやってみることにしました。

ディレクトリによって異なる設定を取り込む

git のコンフィグの記述方法の1つに、外部に分割した設定を取り込む include というものがあるのですが、これに更に条件を指定できる、
条件付きインクルードConditional includes)という機能があります。

たとえば、グローバルなコンフィグである ~/.gitconfig にこんな感じで追記してあげると

[includeIf "gitdir:~/Projects/"]
    path = ~/dotfiles/gitconfig/work.conf

~/Projects 以下のリポジトリでは、グローバルな設定に加えて、~/dotfiles/gitconfig/work.conf の内容も取り込んで設定してくれるようになります。
ちなみに拡張子を .conf としてますが、テキストファイルで、中のフォーマットが一致してればなんでもよさそうです。もちろん、オリジナルに倣って拡張子なしもOKだと思いますが、ファイルを分けて管理する場合、Git コマンドで管理するよりも、テキストエディタなどでファイルを開いて管理することのほうが多くなると思うので、エディタで開ける拡張子が良いと思います。私は VSCode の場合 .conf は Properties として認識されてシンタックスハイライトされるようになるので、こうしてますがお好みで。

includeIf で指定できる条件

[includeIf "<condition>"]<condition> の部分は、gitdir:onbranch: などの「キーワード」と、その後ろに書く「パターン」を : で区切って指定する構文になっています。

gitdir:

gitdir:は、 .git ディレクトリがあるパスがその後に続くパス(glob パターンで指定できる)とマッチしたときに TRUE となります。
glob パターンでの指定なので、チルダ展開や、ワイルドカードによる指定など使えます。
よって、前述の "gitdir:~/Projects/" は、ホームディレクトリ直下にある Projects ディレクトリの中につくられたリポジトリが対象ということになります。

gitdir/i:

gitdir/i: というふうに、/i がつくと、大文字小文字を区別しなくなります。そのため、~/Projects/~/projects/ もマッチするようになります。
ただ、ここで指定する場所は、そのコンフィグを使用するプロジェクト置き場のルートだと解釈してますので、そもそも絶対1箇所しかマッチしないような記述のほうが安全じゃないかなと思うので、個人的にはこっちの記述は使わないようにしています。

onbranch:

じつはこの条件付きインクルードは、ブランチ名をトリガーにもできるみたいです。(そしてブランチ名にも glob パターンが使えます)
利用シーンは…私には全然思い浮かびませんでしたが、ものすごい複雑な運用をしてる人も、世の中にはいるのでしょうね。。

末尾のスラッシュの取り扱い

パスを指定する際は、末尾のスラッシュのありとなしで指定の意味が全く異なってくるために注意が必要で、今回のように特定のディレクトリ以下すべてを対象としたい場合は必ず末尾のスラッシュまで含めてディレクトリのパスを指定する必要があります。

この方法のメリット・デメリット

実際に設定して少し使ってみての感想なので、もうすこし使い込んでみたら意見も変わるかもしれませんが、現時点で感じたメリデメを書いてみます。

メリット

この方法ですと、個々のリポジトリに細かい設定を一切保つ必要がない(local コンフィグが不要)なので、あとで設定を変えないといけないみたいなときに
柔軟に対応が可能です。

また、local コンフィグを一切触ってないため、ここからさらに --local でリポジトリ固有の設定の上書きの余地もあります(やると混乱しそうですが。。)

デメリット

逆に、ディレクトリを軸にコンフィグを分けるので、指定のディレクトリ以外だと、デフォルト設定しかロードされません。
とはいえ、普通だいたいプロジェクト置き場って決まってると思うので、さほど問題にはならないような気もしますが…

参考