モノレポ構成とは?

モノシリックレポジトリ(Monolithic Repository)
直訳すると、一枚岩のリポジトリという意味です!

簡単に説明すると、複数のリポジトリをまとめて1つのリポジトリで管理することです。
よくある例だと以下ではないでしょうか?(ちなみに複数のリポジトリで管理することはマルチレポです)

モノレポ(複数のリポジトリをまとめている)

project
 ├── frontend
 └── backend 

マルチレポ(複数のリポジトリが独立している)

project-frontend
project-backend

モノレポ、マルチレポは双方メリット・デメリットあるかと思いますが、
まとめると以下になります!

構成 メリット デメリット
モノレポ 生成AIが各リポジトリを横断して情報を取得できる
共通部品を共有することができる
履歴が煩雑になる
マルチレポ 履歴管理が楽 複数のリポジトリの管理が大変

モノレポ構成はgit履歴の管理が煩雑になるデメリットがある一方で
生成AIを活用するにあたっては十分にメリットを享受できると思います!

今回の記事では移行編と運用編でご紹介したいと思います!

移行編

以下を例にマルチレポ→モノレポに移行する手順を紹介します!

AsIs

マルチレポ(複数のリポジトリが独立している)

project-frontend
project-backend

ToBe

モノレポ(複数のリポジトリをまとめている)

project
 ├── frontend
 └── backend 

モノレポ移行する手法としてはsubtree化するか、sumoduleとして扱うかの2択になります。
submoduleを扱う場合は直接submoduleを更新することも可能ですが、
参照目的で使用することをプロジェクトでルール化しておくことがおすすめです。
今回はsubtreeで登録する方法を紹介します。

説明 メリット デメリット
subtree 元のリポジトリをコピーしてくる 統合後は1つのリポジトリとして、統合前と変わらない開発フロー(pull→add→commit→push)で作業ができる。
統合前の各リポジトリのコミットログを引き継ぐことができる
コミットログの肥大化
マージ作業が増える・煩雑になる
submodule 元のリポジトリのコミットを参照する 元のリポジトリと独立しているので管理が楽 submodule分の更新を手動で最新化する必要がある
submoduleをコミットする場合、元のリポジトリにpushする作業が大変

手順

1、モノレポとして管理するリポジトリを作成する
2、1で作成したリポジトリにサブのリポジトリを追加する
git remote add frontend
git remote add backend

3、 各リポジトリの履歴を取得 ※frontend、backendそれぞれで実施

git fetch --all

4、サブリポジトリとして登録する

git subtree add --prefix=[作成したいディレクトリ名] [remote addしたブランチ名]

例)

git subtree add --prefix=frontend frontend/main
git subtree add --prefix=backend backend/main

5、リモートにpushする

git push origin main

参考)submoduleを追加したい場合

git submodule add -b [サブモジュール化したいブランチ] [リモートリポジトリのURL]

この手順を踏むことで、各リポジトリの履歴(subtreeに追加した時点のあるブランチの履歴)を保持しつつ、
モノレポ構成に移行することができます!

モノレポ移行後はディレクトリ構成が変わってしまうので必要に応じて.gitignoreを修正し、
各ディレクトリのファイルが全てpushされているか確認することをオススメします。

運用編

クローン時 ※サブモジュールを使用している場合

通常のクローンコマンドを使用するとサブモジュールをクローンしてくれないので、
以下のコマンドでクローンする必要があります。

git clone --recurse-submodules [リポジトリURL]

サブモジュールの最新更新内容を取得したい場合

git submodule update --remote

プルリクエスト作成時

モノレポ構成したことによって、今回の例ではフロントエンドやバックエンドのプルリクエストが
同一リポジトリ内で作成されることになります。ぱっと見でフロントエンドかバックエンドのどちらの
プルリクエストで判断できなくなるため、Github Actionsでプルリクエスト作成時にラベルを自動付与する
手順を紹介したいと思います!
※ワークフローを動かすために、メインブランチで行うようにしてください。

1、指定したディレクトリに変更があった場合をトリガにします。

.github/labeler.yml

[タグ名]:
  - changed-files:
    - any-glob-to-any-file: 
      - '[トリガとなるディレクトリ]/**/*'

例)

frontend:
  - changed-files:
    - any-glob-to-any-file: 
      - 'frontend/**/*'

backend:
  - changed-files:
    - any-glob-to-any-file: 
  - 'backend/**/*'

2、ラベルを付与するワークフローを作成します。

.github/workflows/labeler.yml

name: "Pull Request Labeler"
on:
- pull_request_target

jobs:
  labeler:
    permissions:
      contents: read
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
    - uses: actions/labeler@v5

3、GitHubのGUIでラベルを作成しておきます。


4、作成したワークフローをプッシュします。

上記の手順でプルリクエスト作成時や変更時にラベルが付与されるようになりました!
frontendとbackendのどちらも修正した場合はfrontend・backendの2つのラベルが付与されます!

devcontainerを使用する場合

devcontainerとはVSCodeの拡張機能で
コンテナ(Docker)上にライブラリやVSCodeの拡張機能を詰め込んでくれるものです。
メリットとしては開発者が同じ環境で作業ができることです。

生成AIを活用する場合docs等に設計書やドメインを格納し、
フロントエンド、バックエンドの双方から取得したい場合があるのではないでしょうか??

project/
├── docs  ←docsをfrontendやbackendのコンテナで見たい。
├── frontend/
│   └── .devcontainer
└── backend/
    └── .devcontainer 

しかしながら、フロントエンドやバックエンドでdevcontainerを立ち上げた場合、
ルートディレクトリがfrontend(バックエンドの場合backend)になるため、
デフォルト設定だとdocsフォルダをコンテナ上で確認することができません。

手順としては.devcontainer.jsonに以下の内容を追記します。

  "mounts": [
    {
      "source": "${localWorkspaceFolder}/../docs",
      "target": "${containerWorkspaceFolder}/docs",
      "type": "bind",
      "consistency": "cached"
    }
  ]

説明

  • source:参照したいローカルのパス(devcontainer.jsonからの相対パス)
  • target:指定したディレクトリがコンテナ上に作成(マウント)される

コンテナ上にマウントしたファイル(今回の例だとdocs)は
直接編集してコミットすると、ローカル上のproject/docsにも反映されるので便利です!

最後に

AI駆動開発をスムーズに行うためには、「生成AIが動きやすくなるためにはどうすればいいか?」の視点が重要だと感じています!
生成AIの進化はものすごいですが、開発者の環境もうまく変化させていきながら、良いAI駆動開発ができればいいなと思います。