Help us understand the problem. What is going on with this article?

既存のリポジトリからサブモジュールを分離する

More than 3 years have passed since last update.

はじめに

プロジェクトを進めていくと、「あっ! この機能、別のプロジェクトに流用できる!」と気づく瞬間ってありますよね。でも、不用意に特定のファイルだけをコピペしちゃうと、片方でその機能を更新してももう片方に反映されません。同じ機能を使っているので、ここはgitで一元管理したいところですよね。

それを可能にしてくれるのがサブモジュールです。この記事では、既存のリポジトリからサブモジュールを切り出して、複数のプロジェクトで共有する方法を紹介します。

具体的には、以下のような状態から

以下のような状態にするということです。

ここでは GitHub との連携を念頭に置いて説明していきますが、 GitLab でも同じようにできます。

ステップ0:前提

例として、以下のような状況を考えます。

$ tree
.
├── project_a
│   ├── main_a.py
│   ├── submodule_a1
│   │   └── sa1.py
│   └── submodule_to_be_split
│       └── stbs.py
└── project_b
    ├── main_b.py
    └── submodule_b1
        └── sb1.py

ここから、 submodule_to_be_split を切り出してみます。

ステップ1:切り出し用リポジトリの作成

まず、名前衝突が起きない場所に、もう一つ project_agit clone してきます(これをsomewhere/project_a とします)。これが、サブモジュール切り出し用のリポジトリになります。

ステップ2:サブモジュールに切り出し

次に、somewhere/project_a 下で、

git filter-branch --prune-empty --subdirectory-filter submodule_to_be_split  master

と打ちます(ブランチ名が master でない場合は適宜読み替えてください)。

すると、以下のようなメッセージが出て、リポジトリの情報が書き換わります。

Rewrite 58df845db323b991b17ec6369389f7e46cce4eed (1/1) (0 seconds passed, remaining 0 predicted)    
Ref 'refs/heads/master' was rewritten

これで、 somewhere/project_a がサブモジュールとして切り出せました。こうすることのメリットは、過去のlogを引き継げるというところです。

試しにディレクトリの中身を見ると、

somewhere/project_a
$ ls
stbs.py

と、切り出したいサブモジュールの中身だけになっています。

ステップ3:サブモジュールを GitHub に反映

somewhere/project_a の名前を submodule_to_be_split と変更します。個人的には、これは git の側でマネージしてほしかったですが、手動です。

GitHub 側にも submodule_to_be_split というプロジェクトを作り、ここに push します。ただし、以下のコマンドで確かめられるように、今の状態では remote name は project_a と同じままです。

$ git remote -v
origin  git@github.com:username/project_a.git (fetch)
origin  git@github.com:username/project_a.git (push)

なので、以下のコマンドで remote name を書き換えます。

git remote set-url origin git@github.com:username/submodule_to_be_split.git

もう一度確認します。

$ git remote -v
origin  git@github.com:username/submodule_to_be_split.git (fetch)
origin  git@github.com:username/submodule_to_be_split.git (push)

これで正しく push できるようになりましたので、

$ git push -u origin master

とすれば、サブモジュールが GitHub に push されます。

ステップ4:サブモジュールの取り込み

まずは project_a から submodule_to_be_split を削除しましょう。そして、削除されたことをリポジトリに教えるために、 git add -A の後に git commit しておきます。

ここまでくれば、あとは project_aproject_b の中で

git submodule add git@github.com:username/submodule_to_be_split.git

とすれば、submodule_to_be_split がディレクトリの中にクローンされます。このサブモジュールのディレクトリ名を変えたいときは、

git submodule add git@github.com:username/submodule_to_be_split.git directory_name

と、最後にディレクトリ名を引数として追加すればOKです。

サブモジュールを取り込んだあとも忘れずにコミットしておきましょう。モジュールを追加した直後は以下の 2 つのファイルが追加されているはずです(サブモジュールとして追加した場合は submodule_to_be_split はディレクトリ扱いされません)。

$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitmodules
    new file:   submodule_to_be_split

これで、2 つのプロジェクトに同じサブモジュールが取り込まれました(試しに project_b のほうは submodule_renamed と名前を変えてみました)。

$ tree
.
├── project_a
│   ├── main_a.py
│   ├── submodule_a1
│   │   └── sa1.py
│   └── submodule_to_be_split
│       └── stbs.py
└── project_b
    ├── main_b.py
    ├── submodule_b1
    │   └── sb1.py
    └── submodule_renamed
        └── stbs.py

参考記事

今回はサブモジュールを取り込むところまでしか説明していませんが、サブモジュールの更新にまつわる 大変な 色々なこともさまざまな記事でカバーされています。

Git - サブモジュール
Splitting a subfolder out into a new repository - User Documentation
Git submodule の基礎 - Qiita
Git submoduleの抑えておきたい理解ポイントのまとめ - Qiita

horiem
好きなもの:物理学、機械学習、数理モデリング、金融、構造解析、自然言語処理など。 http://blog.physips.com/ にて、物理学やその他もろもろに関するTipsを紹介するブログをやってます。趣味は作曲、お酒、登山。未踏アドバンスト2017。
https://yellowshippo.github.io/
ricos
FEMによる構造解析、機械学習の専門家集団。計算資源のクラウド提供もしています。
https://www.ricos.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした