0
0

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 submoduleを複数人でいじったときの挙動を確かめるメモ

0
Last updated at Posted at 2019-11-13

Gitのsubmoduleを個人で使ってはいるのですが、複数人で作業をすることになった時にどのような挙動になるのかが分からなくなってきたので、備忘録として実験してみたことをまとめてみます。
というのも、現在複数人で作業しているプロジェクトがあるのですが、ある一部のディレクトリをsubmoduleとして抜き出して、そのsubmoduleを公開し、大本のプロジェクトは開発プロジェクトとしてこれからも使っていきたいという経緯があります。Issueは残しておきたいし、今後とも開発時にはIssueを立ててsubmoduleの中身も変更していきたいからです。

確かめたいと思っていること

  • branchの扱い
  • 複数のプロジェクトでの使い回し方
  • 複数のユーザーはどのようなコマンドを使わなければならないか

前提

リモートレポジトリの置き場として、自前のサーバに立てているGitLab CEを用います。
あるプロジェクト"test_project"と、submoduleにするプロジェクト"test_submodule"を作ります。
二人のユーザー, "John"さんと"Paul"さんが開発を行います。

いざ実験

まず"test_project"をGitLab上(ホスト名はhoge,名前はjohn)で作り、cloneして"commit1_master"というファイルをmaster branchにcommitします。

$ git clone gitlab@hoge:john/test_project.git
$ cd test_project
$ touch commit1_master
$ git add commit1_master
$ git commit -m "[add] commit1 master"
$ git push origin master

当然、こんな感じに。
image.png

そして、submodule用のレポジトリtest_submoduleをpublic権限で用意しておきます1submodule_master1, submodule_master2というファイルをmaster branchに別々にcommitしておきます。

こうして出来たsubmoduleをtest_projectに取り込みます。
test_projectのディレクトリにて

$ git submodule add gitlab@hoge:john/test_submodule.git
$ ls test_submodule/
submodule_master1 submodule_master2 ("submodule_master2"までのcommitが反映されている)
$ git commit -m "[add] submodule"
$ git push origin master

これでこのリポジトリ内にsubmoduleが取り込まれました。
image.png

次に、submoduleとして取り込んでいるディレクトリでsubmodule_master3を作るという操作をしてみます。

$ cd test_submodule
$ touch submodule_master3
$ git add submodule_master3
$ git commit -m "[add] submodule_master3 commit @ submodule dir"
$ git push origin master

すると、test_submoduleプロジェクトは正しく更新されました。
image.png

けれども、親リポジトリであるtest_projectには、このコミットは反映されていません。
image.png

これをリモートリポジトリへ反映させるのに、commitをします。

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

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   test_submodule (new commits)

no changes added to commit (use "git add" and/or "git commit -a")
$ git add test_submodule
$ git commit -m "[mod] update test_submodule (submodule_master3)"
$ git push origin master

すると、test_submodule3が反映されたコミットを参照するようになりました。
image.png

他のユーザーで操作してみる

次に、他のユーザーがsubmoduleを書き換えたときの挙動を実験してみます。
test_projectに他のユーザーを招待して、Cloneします。

$ git clone gitlab@hoge:john/test_project.git
$ cd test_project
$ ls test_submodule
$

親プロジェクトをクローンしただけではsubmoduleの中身までは取れていません。

$ git submodule
-6c9751e0... test_submodule

のように、存在は知っています(test_project/.gitmodulesに書かれているので)
このsubmoduleを取ってくるにはsubmodule initをしなければなりません。

$ git submodule init
$ git submodule update
$ ls test_submodule
submodule_master1  submodule_master2  submodule_master3

と、無事に取ってくることができました。

ここで、個別のプロジェクトでgitのユーザーを変えるため、こちらを参考にユーザーを変更する設定をします(これは親のプロジェクトとsubmoduleの両方で行わなくてはなりません)。ここではuser "paul"とします。

$ git config user.name "paul"
$ git config user.email "paul@hoge.com"

そして、submodule側でファイルsubmodule_master4を作ります。

$ touch submodule_master4
$ git add submodule_master4
$ git commit -m "[add] submodule_master4 by another user" 
$ git push origin master

これで、submoduleに別ユーザーでリモートリポジトリにコミットできました。
image.png

しかし、親プロジェクトの方にはコミットしていません。

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

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   test_submodule (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

そして、submoduleがアップデートされたかはPaulさんが親プロジェクトでsubmoduleの参照コミットが変わったことをコミットしないといけないということです。
これをJohnさんのローカルリポジトリで反映させるには

$ git submodule foreach git pull origin master

を実行します。

でも、これはきちんとsubmoduleにコミットした人が親プロジェクトにもちゃんとコミットする方が良さそうですね。他のユーザーがsubmoduleへ変更を加えたもので依存関係が崩れる可能性があるからです。
そこで、やはりブランチを切って作業をしたくなります。

親プロジェクトのブランチを切って作業する

親プロジェクトに何らかのfeature branchを切って、それぞれの人がsubmoduleをいじりながら作業をしてメインのbranchにmergeするのが一連の流れです。
基本的にはGitLabでIssueを立てて、そのIssueを行うBranchを切って作業を行います。ここでsubmoduleにコミットした場合の挙動をテストします。

ここでは、Johnさんがfeature_johnブランチを、Paulさんがfeature_paulブランチを切って親プロジェクト、及びsubmodule中のファイルを変更し、先にJohnさんがmasterブランチにMergeし、後にPaulさんがMergeする状況を作ってみます。

まず、Johnさんのローカルリポジトリでsubmoduleに対してsubmodule_feature_johnファイルを作り、submodule_master3の内容を変更する作業をします。

$ git checkout -b feature_john
$ cd test_submodule
$ touch submodule_feature_john
$ git add submodule_feature_john
$ git commit -m "[add] submodule_feature_john
$ git push
$ echo "edited by John" > submodule_master3 (同じファイルをいじってみてコンフリクトのテストもする)
$ git commit -m "[mod] submodule_master3 by John"
$ git push
$ cd .. (親プロジェクトに戻る)
$ git commit -m "[mod] submodule dir @ feature_john"
$ git push origin feature_john

次に、Paulさんも別の作業をしたいとします。

$ git checkout -b feature_paul
$ cd test_submodule
$ touch submodule_feature_paul
$ git add submodule_feature_paul
$ git commit -m "[add] submodule_feature_paul
$ git push
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'gitlab@hoge:john/test_submodule.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

この時点でコンフリクトが起きてしまいました。それもその筈。submodule上ではmasterブランチで作業していることになっているからです。
そうするとなると、submoduleに対してそれぞれfeatureブランチを切って作業しなければならないのでしょうか。完全に二度手間です。
Issueとの紐付けのために親プロジェクトのブランチを切って作業を行う時に
「このIssueを解決するのには、ぶら下がっているsubmoduleもいじらないとなぁ」
となることは多々あると思うのですが、その時にsubmodule側でもbranchを切らなければならないのは混乱がありそうな気がするのです。
それか、submoduleの方でもIssueを立てた方が良いのか。

結論

submoduleをいじる前提でのプロジェクト開発においては、複数人でBranchを切って作業するのには向かない

次は、subtreeを使ったテストを行いたいと思います。

  1. public accessで良いのかは検討です
    image.png

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?