Prompt

.gitignoreで追跡しないファイルがある場合、checkoutした後にビルドすると、それらが干渉しエラーになる場合がある

それはまさに、エンジニアが一度は通る 「クリーンな環境のジレンマ」 だね。

.gitignore は「リポジトリを汚さない(機密情報やビルド成果物を上げない)」ための守護神だけど、チェックアウト(ブランチ切り替え)時には 「古い残骸」 を消してくれないから、それが悪さをしちゃうんだ。

情報工学的に言えば、「作業ディレクトリの状態(Working Tree)」と「インデックス(Staging Area)」の不一致 が原因だね。還元主義的に、なぜこれが起きるのかと、そのスマートな解決策を解剖しよう!


1. なぜ「干渉」が起きるのか?

Git は「追跡しているファイル」についてはブランチ切り替え時に責任を持って入れ替えてくれるけれど、.gitignore に指定された「追跡対象外(Untracked)」のファイルには一切手を触れない。

  • よくあるエラー:

    • コンパイル済みバイナリ: A ブランチで生成した target/dist/ が残ったまま B ブランチでビルドし、古いオブジェクトファイルと新しいソースが混ざってリンクエラーになる。

    • 依存関係 (node_modules 等): ブランチ間でライブラリのバージョンが違うのに、古い実体が残っていてランタイムエラーになる。

    • 自動生成ソース: プロトコルバッファや OpenAPI から生成されたコードが、古い定義のまま残ってしまう。


2. 最強の解決策:git clean

手動でファイルを消すのは面倒だし、消し忘れも怖いよね。そこで Git 自体に「ゴミ掃除」を命令するコマンドがあるよ。

Bash

# 追跡対象外のファイル(.gitignore されているもの含む)を削除する
# -f: 強制実行, -d: ディレクトリも含む, -x: .gitignore されているファイルも無視して消す
git clean -fdx

注意: これを実行すると、.env ファイルなどの「リポジトリには上げないけど必要な設定ファイル」も消えてしまう。

特定のファイルを守りたいなら、-e ".env" オプションを付けるか、設定ファイルだけは別の安全な場所に退避させる設計が必要だね。


3. インフラ・開発手法による解決案

① Build Artifacts の分離(Out-of-source build)

ビルド成果物をソースコードと同じディレクトリツリーに置かない方法だよ。

C++ の CMake などでよく使われる手法だけど、build/ ディレクトリをプロジェクトのルート外に作るように設定すれば、ソースのブランチを切り替えてもビルドディレクトリを空にするだけで確実にクリーンにできる。

② Docker コンテナによる「使い捨て」環境

前回の話にも繋がるけれど、「ビルド環境自体をコンテナ化」 して、ビルドのたびに新しいコンテナで回せば、ローカルの汚れ(汚染)を一切気にしなくて済む。

CI/CD(GitHub Actions 等)でビルドが失敗しないのは、毎回この「真っさらな環境」を作っているからなんだね。


豆知識:git checkout --recurse-submodules

もし君のプロジェクトで Git Submodules を使っているなら、ブランチを切り替えた後にサブモジュールの中身が古いまま残っていてビルドエラーになることがよくある。

--recurse-submodules フラグを付けてチェックアウトするか、git submodule update --init --recursive を叩く癖をつけておくと、サブモジュール由来の事故を減らせるよ。


見落とされがちな視点:IDE のインデックス

VSCode や IntelliJ などの IDE は、ファイルが消えたり変わったりした後に独自の 「インデックス(キャッシュ)」 を持っている。

ターミナルで git clean してビルドが通るようになっても、IDE 上で赤線(エラー表示)が消えない場合は、IDE の再起動やキャッシュのクリアが必要になることもあるんだ。


結論

チェックアウト後に「何かおかしい」と思ったら、まずは git clean -fdx(ただし .env 等の消失には注意!)。

これが面倒なら、ビルド成果物を格納するディレクトリを丸ごと削除するスクリプトを package.jsonMakefile に仕込んでおくのが、日々の開発を快適にするコツだね。

次は、「Git のフック(post-checkout)を使って、ブランチを切り替えた瞬間に自動でゴミ掃除や依存関係の更新をする自動化」 についてやってみる?

Would you like me to write a simple Git Hook script that automatically runs npm install or git clean when you switch branches?