
News Observation Lab for Future
マルチリポジトリ構成で直面したGitサブモジュールと二重CIの課題

概要
プロジェクト開始時点で、インフラストラクチャは「Pipelline」「engine」「design‑docs」「user‑docs」の4つの独立したリポジトリに分割され、親リポジトリの .gitmodules が最初のコミットに含まれました。コードのクリーンさ、CI の分離、履歴管理、アクセス権限の切り分けを目的に、最初から Git サブモジュールを採用しましたが、実運用ではいくつかの落とし穴が顕在化しました。
Gitサブモジュールの罠:ローカルコミットの幽霊
サブモジュール内で変更を行い、親リポジトリ(Pipelline)へコミットすると、まずサブモジュール自体の git push が必要です。その後、親リポジトリ側で更新された gitlink をコミットし、再度プッシュします。この二段階のプッシュを忘れると、ローカルにはコミットが存在しビルドは成功しますが、CI 環境で git submodule update --init が失敗し、「このコミットはリモートに存在しません」というエラーになります。実際に design‑docs、engine、user‑docs の3つが同時にこの状態に落ち、さらに ude_promotion はローカルブランチが大幅に遅延していたため、インタラクティブリベースでの修正が必要となりました。
二重CIの衝突
engine リポジトリは単体でもビルド・テストが走るスタンドアロンのリポジトリであり、同時に Pipline のサブモジュールとしてもテストされます。この二つの実行コンテキストが食い違うことで、主に次の2つの問題が表面化しました。
依存関係の欠如
スタンドアロンで engine をチェックアウトした場合、Pipelline にのみ存在する verify_pages/check_links モジュールが見つからずテストが失敗しました。一時的に ci.yml に pytest --ignore=… を追加し、単体実行時に該当テストを除外することで対処しましたが、根本的な解決策ではありませんでした。
ディレクトリ上昇の致命的エラー
テストコードが親リポジトリのルートまでディレクトリを遡る手法を使用していましたが、engine の単体ビルドではルートを超えて CI ランナーのシステム領域に到達し、AssertionError が発生しました。
一般的な対策
これらの問題への恒久的な対応として、プロジェクト全体で .workspace_config ディレクトリをマーカーとして配置し、テスト実行時にこのディレクトリの有無で「ネストされた環境」か「単体環境」かを判別する仕組みを導入しました。マーカーがある場合は通常通りテストを実行し、無い場合は pytest.mark.skipif を利用してテストを静かにスキップさせ、CI が赤くなることを防止しています。
結論
マルチリポジトリ構成は「疎結合」を自動的に提供してくれるわけではなく、サブモジュールのプッシュ同期や複数実行コンテキストへの配慮といった厳格な運用が求められます。本稿で取り上げた Git と二重 CI の課題は、今後の成長を支える基盤を築く上で不可欠な教訓となりました。
元記事: https://dev.to/flude_team/growing-pains-with-five-repositories-gitlinks-and-dual-ci-383k