前回のDay 26では、第5部の集大成として「AIエージェントを活用したケーススタディ自動実行(Issue-to-PR)」を学び、現代の自律型コーディング環境とGitの強力な連携をマスターしました。
そして本日のDay 27より、いよいよ【第6部: プロの調査・保守・作業効率化テクニック】がスタートします!
第1弾のテーマは、チーム開発や現場で活躍する全エンジニアに知ってほしいGitの神機能——【git worktree で再ビルドなしの超高速ブランチ並行開発】です!
「新機能の開発に没頭している最中、突然本番環境で緊急障害が発生して調査を頼まれた……。ブランチを切り替えたら、Visual Studioが巨大なC#ソリューション全体をゼロから再ビルドし始め、NuGetパッケージの再復元で10分以上待たされた」
「調査が終わって元のブランチに戻ってきたら、またしても全件再ビルドで待ち時間……。開いていたタブやブレークポイントも消えて集中力が完全に削がれた」
こうした苦い経験は、エンジニアなら誰しも一度はあるはずです。
かつてのSubversion (SVN) では別フォルダにチェックアウトして複数開くことができましたが、Gitでも完全に別のフォルダへ別ブランチを即時展開し、Visual Studioを2つ同時に開いて並行デバッグできる仕組みが存在します。それが
git worktree です!リポジトリを丸ごと別cloneする必要はありません。コミット履歴やローカルブランチは完全に共有されたまま、ワーキングディレクトリとビルド生成物(bin/obj)だけを物理的に分離できます。
本日は、この
git worktree の仕組みから、実務でのC#並行開発テクニック、ポート番号の競合回避、そして安全な後片付け手順まで、余すところなく徹底解説します!
① 導入・本日の達成目標
Gitの最大の魅力は「軽量なブランチ作成と瞬時の切り替え」ですが、「コンパイル言語(C# / .NET)の巨大ソリューション」においては、ブランチ切り替え時にファイルタイムスタンプが更新され、Visual Studioが全プロジェクトの再ビルドやNuGet復元を実行してしまうという現実の壁が存在します。
この「ビルド待ち時間」と「コンテキストスイッチの消耗」を完全に解消する切り札が git worktree です。
- 従来の
git switchによるファイル一括置換と、巨大C#ソリューション再ビルド待ちの課題を理解する git worktreeの内部アーキテクチャ(単一の.gitディレクトリ共有 × 複数作業フォルダ展開)を把握する- リポジトリを丸ごと
git cloneし直す手法と比較した圧倒的メリット(容量節約・履歴即時共有・高速展開)を学ぶ git worktree add、list、remove、pruneの必須ライフサイクルコマンドを習得する- Visual Studioを2画面で同時起動し、本番Hotfix調査と機能開発を並行デバッグする実戦手順(ポート競合回避を含む)を身につける
② 【図解】従来のブランチ切り替えの苦悩 vs git worktree の即時性
まずは、従来のブランチ切り替え(git switch / checkout)と git worktree の挙動の違いを比較してみましょう。
Gitの基本動作では、1つの作業ディレクトリ(Working Directory)内でファイルを丸ごと差し替えることでブランチを切り替えます。
スクリプト言語などでは一瞬ですが、C#やC++などのコンパイル言語では以下の深刻な問題が発生します。
- ファイルのタイムスタンプ更新による全件リビルド: ソースコードが数万行〜数百プロジェクトに及ぶ場合、
binやobj内の中間生成物が無効化され、ビルド完了まで5〜10分以上の待機時間が発生する。 - NuGetパッケージの再復元(Restore): ブランチ間でパッケージバージョンが異なると、Visual StudioがバックグラウンドでNuGetパッケージの復元を開始し、CPUファンが激しく回転してPCが重くなる。
- IDE状態(タブ・ブレークポイント)の喪失: 開いていたエディタのタブ、設定したブレークポイント、デバッグの実行状態がリセットされ、元の作業に戻った際に「どこまで書いたか」を思い出すのに大きな精神的エネルギーを消費する。
かつてSubversion (SVN) を使っていたエンジニアからは、「SVNなら別フォルダにチェックアウト(Checkout)して複数同時に開けたのに、Gitは1つのフォルダしか使えないから不便だ」という声をよく聞きます。
しかし、それは誤解です! Gitには、SVNの複数チェックアウトの利点を完全に再現し、さらに超進化させた『git worktree』が備わっているのです!
③ 【図解】git worktree の内部アーキテクチャ:なぜ別cloneより圧倒的に優れているのか?
「別フォルダで作業したいなら、別の場所に git clone すれば良いのでは?」と思うかもしれません。
しかし、別cloneには重大な欠点があります。
| 比較項目 | 別ディレクトリへ git clone | git worktree(推奨) |
|---|---|---|
| ディスク消費量 | リポジトリ履歴(.git)を二重保存(数GB浪費) | .git は1つだけ共有!作業ファイル分のみ(極小) |
| 展開スピード | ネットワーク通信や全履歴コピーで数分〜数十分 | ローカル内で瞬時にフォルダ生成(1秒以内) |
| ローカルブランチ共有 | 完全に別リポジトリ。push/fetchしないと見えない | 完全に同一リポジトリ!即座に全ブランチが同期 |
| Stash(退避)の共有 | 共有不可(個別のstash領域) | 同一リポジトリなので stash も相互に参照可能 |
裏側の仕組み:ポインタとしての .git ファイル
メインリポジトリ(最初にcloneしたフォルダ)には、これまで通り .git という「ディレクトリ」が存在し、すべてのコミット履歴やオブジェクトが保存されています。
一方、git worktree add で新設された別フォルダの中を見ると、.git はディレクトリではなくたった1行のテキストファイルになっています!
gitdir: C:/Project/MainRepo/.git/worktrees/hotfix-login
このポインタファイルのおかげで、Gitは追加ワークツリーでのコミットやブランチ操作をメインリポジトリの .git へ直接記録します。
つまり、「実体としての作業ファイル群(bin/objを含む)は完全に別フォルダに分かれつつ、Gitの頭脳(履歴・ブランチ)は完全に1つに繋がっている」という理想的な構造が実現しているのです!
④ 【図解・コマンド実践編】git worktree 必須コマンドのライフサイクル完全マスター
git worktree を使いこなすために覚えるべきコマンドは、たったの4つです!
1. ワークツリーを追加する(add)
別フォルダにブランチを展開します。既存のブランチを指定することも、新ブランチを作成して展開することも可能です。
git worktree add ../worktrees/hotfix-login hotfix-login
# パターンB: mainから新ブランチ(-b)を作成しつつ同時に別フォルダに展開(実務で最も多用!)
git worktree add -b hotfix/issue-501 ../worktrees/hotfix-issue-501 main
「同一リポジトリ内で、同じブランチを複数のワークツリーで同時にチェックアウトすることはできない」という安全規則があります。
すでにメインで開いているブランチをworktreeで開こうとするとエラー(fatal: is already checked out)になるため、必ず別ブランチを指定または新規作成してください。
2. 現在のワークツリー一覧を確認する(list)
どのフォルダにどのブランチが展開されているかを一覧表示します。
C:/Project/MainRepo 5a3f2b1 [feature/shopping-cart]
C:/Project/worktrees/hotfix-issue-501 e91c784 [hotfix/issue-501]
3. 作業終了後にワークツリーを安全に削除する(remove)
緊急対応や修正が終わり、コミット&プッシュ(またはPR作成)が完了したら、ワークツリーを削除します。
git worktree remove ../worktrees/hotfix-issue-501
4. 手動でフォルダを消してしまった場合のクリーンアップ(prune)
もしエクスプローラーから直接フォルダをゴミ箱に捨ててしまった場合、Git内部に参照情報だけが残ってしまいます。その場合は prune を実行すれば一瞬で整合性が修復されます。
git worktree prune
⑤ 【実戦C#編】Visual Studio 2画面同時デバッグとポート競合回避テクニック
git worktree をC#開発で真に活かすための、現場ならではの実戦テクニックを解説します。
テクニック1: Visual Studio を2つ起動して左右デュアルディスプレイに配置
メインディレクトリのソリューションファイル(MainRepo/MyApp.sln)と、追加ワークツリーのソリューションファイル(hotfix-issue-501/MyApp.sln)をそれぞれVisual Studioで開きます。
フォルダが完全に分かれているため、ソリューションのビルド生成物(bin/obj)が一切衝突しません!
左画面で「本番の障害再現・修正」を行いながら、右画面で「新機能の実装コード」を開いたまま参照できます。
テクニック2: launchSettings.json によるポート競合回避
ASP.NET Core Web APIやBlazorアプリを2つ同時に「F5(デバッグ実行)」すると、同じポート番号(例: https://localhost:7001)をバインドしようとして以下のエラーが発生します。
これを防ぐには、追加ワークツリー側の Properties/launchSettings.json でポート番号をずらします。
"profiles": {
"https": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:7011;http://localhost:5011", // メイン(7001)と競合しないよう変更!
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
launchSettings.json は開発者個人のローカル設定であるため、コミットしたくない場合は git update-index --assume-unchanged Properties/launchSettings.json を実行しておけば、変更がステージングに上がってこなくなります。
📌 本日の講義まとめと実践チェックリスト
Day 27では、巨大なC#ソリューション開発においてブランチ切り替え待ち時間をゼロにし、並行開発を爆速化する git worktree の真髄を学びました。
次回のテーマは【Day 28:git add -p で必要な行だけを綺麗にコミットする部分ステージング技】です!
1つのC#ファイルの中に「本番用のバグ修正」と「動作確認のために入れた一時デバッグログ(Console.WriteLine)」が混ざってしまったとき、皆さんはどうしていますか?
ファイル丸ごとではなく、必要な変更箇所(Hunk)だけを行単位で選別してコミットできるGit屈指のプロ技
git add -p を徹底解説します!TortoiseGitでの直感的な行単位ステージング操作も合わせて実演しますので、どうぞお楽しみに!
コメント
コメントを投稿