4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Git subtreeを使って複数人開発してみるテストメモ

4
Last updated at Posted at 2019-11-14

前回の記事で、submoduleをサブディレクトリに置いたプロジェクトに対してブランチを切って作業するのは難しいという結論になりましたので、今回はもう一つの手法であるサブディレクトリを別プロジェクトで運用する方法である、subtreeを使って、検証してみたいと思います。

前提

今回はtest_projectという親プロジェクト内にsubtreeを入れてみたい。
リモートリポジトリを視覚化するのに、自前のサーバに入れているGitLab CEを用いました。
作業者はJohnさん(GitLabでは水色アイコン)とPaulさん(GitLabでは赤色アイコン)の二人を仮定します。

実験

subtreeの生成・紐付け

まず、新規リモートリポジトリtest_subtreeをGitLabで作ります(gitlab@hoge:john/test_subtree.gitとします)。
空ファイルsubtree_master1も作って置きました。
image.png

そして、Johnさんのローカルリポジトリにcdして

$ git remote add test_subtree gitlab@hoge:john/test_subtree.git
$ git remote
origin
test_subtree (リモートリポジトリが追加されたことを確認)
$ git subtree add --prefix=subtree_dir test_subtree master
$ ls
commit1_master subtree_dir/ test_submodule/ (subtree_dirが生成される)
$ ls subtree_dir
subtree_master1 (中身もある)
$ git push origin master

リモートリポジトリにpushすると、GitLabの方ではこのように、subtreeがあたかもただのサブディレクトリのように見えます。
image.png

次に、Paulさんのローカルリポジトリでtest_projectpullしてみます。

$ git pull
$ ls
commit1_master subtree_dir/ test_submodule/
$ ls subtree_dir
subtree_master1

となり、正しく反映されています。

masterブランチで編集する

再びJohnさんのローカルリポジトリに移って、新たにsubtreeとして登録したディレクトリに新しい空ファイルsubtree_master2を作ってみます。

$ cd subtree_dir
$ touch subtree_master2
$ git add subtree_master2
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   subtree_master2

$ cd .. (前のディレクトリに戻ってみても)
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   subtree_dir/subtree_master2
(同じ内容がでます)

subtreeのディレクトリだけでなく、親レポジトリでも同様のステータスが表示されます。つまり、本当のサブディレクトリとして扱われているということですね。

$ git commit -m "[add] subtree_master2 by John"
$ git push origin master

リモートリポジトリに反映させた親プロジェクトのDetails画面がこちらです。
image.png
しかし、これはsubtreeのプロジェクトには反映されていません。
image.png
これを反映させるには

$ git subtree push --prefix=subtree_dir test_subtree master

を実行します。すると、subtreeのリモートリポジトリにも反映されました。
image.png

ここで、Johnさんでもう一つのファイルsubtree_master3を作り、親プロジェクトtest_projectにだけpushします。

$ touch subtree_dir/subtree_master3
$ git add subtree_dir/subtree_master3
$ git commit -m "[add] subtree_master3 by John
$ git push origin master

次に、Paulさんのローカルリポジトリでpullってみます。

$ git pull origin master
$ ls subtree_dir
subtree_master1 subtree_master2 subtree_master3

このように、subtreeにpushせずとも、親プロジェクトの内容が保持されています。

Branchを切ってみる

次に、親プロジェクトにて各ユーザーが開発ブランチを切って作業するテストをしてみます。
まずはJohnさんのローカルリポジトリにてfeature branchを切って、subtree_dirにファイルを置いてコミットし、pushします。また、コンフリクトの検証のために、subtree_master1に手を加えてみます。

$ git checkout -b feature_john
$ touch subtree_dir/subtree_feature_john
$ git add subtree_dir/subtree_feature_john
$ git commit -m "[add] subtree_feature_john"
$ echo "Edited by John" > subtree_dir/subtree_master1
$ git add subtree_dir/subtree_master1
$ git commit -m "[mod] subtree_master1 by John"
$ git push origin feature_john

test_projectのリモートリポジトリに反映されています。
image.png

Paulさんのローカルリポジトリでも同様な作業を行います。

$ git checkout -b feature_paul
$ touch subtree_dir/subtree_feature_paul
$ git add subtree_dir/subtree_feature_paul
$ git commit -m "[add] subtree_feature_paul"
$ echo "Edited by Paul" > subtree_dir/subtree_master1
$ git add subtree_dir/subtree_master1
$ git commit -m "[mod] subtree_master1 by Paul"
$ git push origin feature_paul

こちらもtest_projectのリモートリポジトリに反映されています。
image.png

Mergeしてみる

Johnさん,Paulさんふたりとも作業が終わりました。
ここではtarget branchをmaster branchにして、2つのfeature branchをそれぞれMerge requestを出していきます。

まずはJohnさんから
image.png
Merge requestを作って
image.png
Merge出来ました。

次に、Paul
image.png
Merge requestを作ります。
image.png
Conflictが起きているので解消させて
image.png

Mergeしました。
その結果がこちら
image.png

このプロジェクトの中では、まるでただのsub directoryのように扱える事がわかりました。

このようにして開発したmaster branchの中身をsubtreeのリポジトリに反映させます。

$ git subtree push --prefix=subtree_dir test_subtree master

とすると、subtreeリポジトリに反映されました。
image.png

subtreeへのコミットログについて

subtree_dir/subtree_master4 -> project_master1 -> subtree_dir/subtree_master5とファイルを作ってコミットするという作業をして、最後にリモートリポジトリへpushし、subtreeにもpushします。

$ touch subtree_dir/subtree_master4
$ git add subtree_dir/subtree_master4
$ git commit -m "[add] subtree_master4"
$ touch project_master1
$ git add project_master1
$ git commit -m "[add] project_master1"
$ touch subtree_dir/subtree_master5
$ git add subtree_dir/subtree_master5
$ git commit -m "[add] subtree_master5"
$ git push origin master
$ git subtree push --prefix=subtree_dir test_subtree master

この結果、親プロジェクトのリポジトリのコミットログは以下のようになり
image.png
subtreeのリポジトリのコミットログは以下のようになりました。
image.png
subtreeにpushするときに、自動的にfilter-branch的なことをやっているのか、subtree_dirに関連するコミットのみ残りました。

まとめ

subtreeでは一つのプロジェクト内で複数人が開発するときにはsubmoduleのように他人の変更に影響を受けずに、ただのサブディレクトリとして扱うことができる

今回の狙いは

一つのプロジェクトでIssueを立てて開発していき、完成させたサブディレクトリを公開・他のプロジェクトに流用させたい

というものでした。基本的には他のプロジェクトからこのサブディレクトリを編集することはないので、プロジェクトのMaintainerがリリースするときにsubtreeにpushするということを行えば、他のDeveloperに複雑な作業を強いることもなく開発してもらえそうです。

参考

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?