Gitで複数のブランチで並列して扱うべんりな方法

タイトルどおりのトピックです

Gitには便利なことにgit-worktree(1)が存在する。しかし、普通にgit-cloneしてきたレポジトリの中でgit-worktreeで他のブランチをチェックアウトしてくると、当然だがgitとしてはそのチェックアウトしてきた別のブランチのあるディレクトリがまるっとuntracking filesに出てきて、大変ジャマなことこの上ない、という欠点があるのである……

解決方法

git-clone(1)にはいくつかcloneの方法がある。--mirror--bareなどである。今回は--bareを取り上げる。

mkdir my_project
cd my_project
git clone --bare git@github.com/orumin/my_project .bare

このようにcloneすると、my_project/.bare配下にgitのレポジトリ本体だけがcloneされる。レポジトリで管理されているファイル群やコミットも全てgitレポジトリでgit objectとして管理されている状態にのみなっており、ファイルの実体はどこにもcheckoutされていない状態となる

cd my_project
echo "gitdir: .bare" > .git
git worktree add main

こうすると、実際はgitレポジトリではないmy_projectディレクトリ直下に居るときでもgitレポジトリとしてgitコマンドが認識してくれるので、git-worktree(1)も利用できる状態となっている。この場合、ここでgit worktree add mainをすることで、my_project/mainというディレクトリにorigin/mainのブランチがcheckoutされて、gitで管理しているファイル群にアクセスできるようになる。同様に、他のブランチに関してもmy_project直下でgit worktree addすればディレクトリの形でぽこぽこブランチがcheckoutできる、というわけである。

また、

git worktree -b add_new_feature feature_branch origin/main

などとすれば、origin/mainをベースとして新規ブランチadd_new_featureを切り、これをfeature_branchというディレクトリ名でworktreeを作成してくれる。べんり!

remote branchをfetchできない!

以上でよいように思うが、git-pullなどをするとき途端に困った事実に直面する。remote branchをfetchできないのである。これは、--bareではなく普通にgit-cloneするときに設定される値が、git clone --bareでは設定されないためである。

git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

簡単に言えば、この設定を追加すればoriginとして設定しているremote repositoryに対してgit-fetchしたときちゃんとlocal repositoryに紐付けてダウンロードしてくれるようになる。これで、オールオッケー!

ブランチごとにディレクトリを作成する……?

でもこれってSVNみたいじゃないですか?

はい……でも便利だし……