セキュリティ対応で複数のfeatureブランチを並行して進める必要が出てきました。最初は git stash してブランチを切り替えて、を繰り返していましたが、3ブランチとなるとかなり大変です。そこで使い始めたのが git worktree

同じリポジトリを複数のディレクトリに展開できる機能で、.git を共有したまま作業ディレクトリだけ増やせます。リポジトリをまるごとクローンするより軽く、設定やリモートURLのコピーも不要。

今回の構成

feature/security-base という共通のベースブランチから、CSRF対策・XSS対策・セッションタイムアウトの3つを切る構成。

共通の親フォルダ/
  ├── project-main/      ← メインの作業ディレクトリ(別ブランチのままでOK)
  ├── csrf-fix/          ← feature/csrf-fix
  ├── xss-fix/           ← feature/xss-fix
  └── session-timeout/   ← feature/session-timeout

project-main はいじらなくて大丈夫です。今作業中のブランチのままキープしつつ、worktreeだけ並べられます。

worktreeを作る

project-main のディレクトリから実行します。

git worktree add ../csrf-fix -b feature/csrf-fix origin/feature/security-base
git worktree add ../xss-fix -b feature/xss-fix origin/feature/security-base
git worktree add ../session-timeout -b feature/session-timeout origin/feature/security-base

-b feature/csrf-fix でブランチを新規作成しつつ、origin/feature/security-base を起点にしています。実行すると ../csrf-fix ディレクトリが生成され、すぐ cd して作業できる状態。あとはターミナルを3枚開いてそれぞれに入るだけです。

終わったら削除する

pushまで終わったらworktreeを片付けます。

git worktree remove ../csrf-fix
git worktree remove ../xss-fix
git worktree remove ../session-timeout

ここで詰まったのが、コミットしていない変更が残っていたときのエラーでした。

error: '../csrf-fix' contains modified local files

--force をつければ強制削除できます。ただし未コミットの変更は消えるので、削除前に git status での確認は必須。

git worktree remove --force ../csrf-fix

forceで消してしまっても、コミット済みのものは .git に残っているのでプッシュは可能です。

# project-main から
git push origin feature/csrf-fix

状態確認

git worktree list

ディレクトリが増えてくると「どれがどのブランチだっけ」となりがちです。パスとブランチ名をまとめて確認できるコマンドです。