# Gitのサブツリーのマージについて

複数のプロジェクトを単一のリポジトリで管理する必要がある場合、 "サブツリー マージ" を使ってすべての参照を扱うことができます。

## サブツリーのマージについて

通常、サブツリーのマージはリポジトリ内にリポジトリを格納するために使われます。 「サブリポジトリ」はメインのリポジトリのフォルダー内に格納されます。

サブツリーマージは、例で説明するのが最も分かりやすいでしょう。 以下のように進めます:

* プロジェクトを表す `test` という空のリポジトリを作成します。
* 別のリポジトリを `Spoon-Knife` というサブツリーとして、そこにマージします。
* `test` プロジェクトでは、そのサブプロジェクトを同じリポジトリの一部であるかのように使います。
* `Spoon-Knife` から `test` プロジェクトに更新プログラムを取り込みます。

## サブツリーマージのための空のリポジトリのセットアップ

複数のOSを扱うターミナルを開く

1. 新しいディレクトリを作成し、そこに移動します。

   ```shell
   mkdir test
   cd test
   ```

2. 新しい Git リポジトリを初期化します。

   ```shell
   $ git init
   > Initialized empty Git repository in /Users/octocat/tmp/test/.git/
   ```

3. 新しいファイルを作成してコミットします。

   ```shell
   $ touch .gitignore
   $ git add .gitignore
   $ git commit -m "initial commit"
   > [main (root-commit) 3146c2a] initial commit
   >  0 files changed, 0 insertions(+), 0 deletions(-)
   >  create mode 100644 .gitignore
   ```

## 新しいリポジトリをサブツリーとして追加

1. 関心のある別個のプロジェクトを指す新しいリモート URL を追加します。

   ```shell
   $ git remote add -f spoon-knife https://github.com/octocat/Spoon-Knife.git
   > Updating spoon-knife
   > warning: no common commits
   > remote: Counting objects: 1732, done.
   > remote: Compressing objects: 100% (750/750), done.
   > remote: Total 1732 (delta 1086), reused 1558 (delta 967)
   > Receiving objects: 100% (1732/1732), 528.19 KiB | 621 KiB/s, done.
   > Resolving deltas: 100% (1086/1086), done.
   > From https://github.com/octocat/Spoon-Knife
   >  * [new branch]      main     -> Spoon-Knife/main
   ```

2. `Spoon-Knife` プロジェクトをローカルの Git プロジェクトにマージします。 こうしてもローカルではファイルはまったく変更されませんが、Git は次のステップに備えることになります。

   Git 2.9 以降を使用している場合:

   ```shell
   $ git merge -s ours --no-commit --allow-unrelated-histories spoon-knife/main
   > Automatic merge went well; stopped before committing as requested
   ```

   Git 2.8 以前を使用している場合:

   ```shell
   $ git merge -s ours --no-commit spoon-knife/main
   > Automatic merge went well; stopped before committing as requested
   ```

3. **spoon-knife** というディレクトリを新たに作成し、`Spoon-Knife` プロジェクトの Git 履歴をそこへコピーします。

   ```shell
   $ git read-tree --prefix=spoon-knife/ -u spoon-knife/main
   > fatal: refusing to merge unrelated histories
   ```

4. 変更をコミットして安全にします。

   ```shell
   $ git commit -m "Subtree merged in spoon-knife"
   > [main fe0ca25] Subtree merged in spoon-knife
   ```

ここでは 1 つのサブプロジェクトを追加しただけですが、Git リポジトリには任意の数のサブプロジェクトを取り込むことができます。

> \[!TIP]
> 将来このリポジトリのクローンを新しく作成した場合、追加したリモートは作成されません。
> [
> `git remote add` コマンド](/ja/enterprise-server@3.22/get-started/git-basics/managing-remote-repositories)を使用して、もう一度追加する必要があります。

## 更新と変更に同期する

サブプロジェクトが追加された場合、そのサブプロジェクトは上流の変更と自動的には同期されません。 以下のコマンドで、サブプロジェクトを更新する必要があります。

```shell
git pull -s subtree REMOTE-NAME BRANCH-NAME
```

上の例では、以下のようになるでしょう:

```shell
git pull -s subtree spoon-knife main
```

## 参考資料

* [
  *Pro Git* 書籍の「高度なマージ」章](https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging)
* [サブツリー マージ戦略の使用方法](https://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html)