Gitサブモジュールの基本と実践
こちらをMarioさんが書いてくれています。すごくわかりやすかったので是非参考にしてみてください。
上記のMarioさんの記事の知識を前提として、Gitサブモジュールを実際に使う際に、引っかかるポイントについて補足記事として紹介したいと思います。
上の記事の中で
サブモジュールを更新する基本の流れ
で以下のようにあります。
1. サブモジュールのフォルダに入る
2. コードを編集する
通常のリポジトリと同様に、ファイルを編集します
3. サブモジュール内でコミット&プッシュする
4. メインプロジェクトに戻る
5. サブモジュールの参照を更新してコミットする
このときの
3. サブモジュール内でコミット&プッシュする
普通にやると例えば以下のように怒られたりするときがあります。
$ git push origin
fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use
git push origin HEAD:<name-of-remote-branch>
うーん。何を怒られているのか、どうすればいいのか、わからん。。。
しかし、よく考えると
サブモジュールを引っ張ってきたときには
そのサブモジュールは、branchを特定せず、コミットで特定されているだけなのですね。
つまり、そのサブモジュールは
どのブランチにも属さず、コミットが指定されているだけなのです。
サブモジュール内でgit statusするとわかります。例えば。。
$ git status
HEAD detached at 36d42f4
nothing to commit, working tree clean
上のように、コミットのハッシュ値は 36d42f4 として出ていますがブランチは出てきません。
このことを前提として考えると、上で出たエラーメッセージは、pushしたときに、
お前は、現在、(ローカルで)ブランチ上にいないぞ。
現在の状態までの履歴をpushするためには(リモートブランチ上のどのブランチにpushするか指定しろ。)
git push origin HEAD:<name-of-remote-branch>
こんな感じでね。
と言われているらしいのです。
HEADは、ローカルリポジトリ上で現在作業している位置、<name-of-remote-branch>はリモートリポジトリ上のブランチですね。
こんなことがおこる原因は、サブモジュールをひっぱってきたとき、コミットが指定されているだけでブランチが指定されていないからです。
どうしてサブモジュールのコミットだけ指定されているのか?
サブモジュールに参照先としてブランチだけ指定すると、そのサブモジュールのブランチが勝手に先に進んでしまうと、参照しているコードが変わってしまい、サブモジュールを取り込んでいるリポジトリで不整合が起こってしまいます。
このコードが参照しているサブモジュールはサブモジュールのこのコミットのときのものだと、固定する必要があるんですね。
サブモジュールはコミットを指定する必要があり、そうするとブランチ指定は必要がない。
ブランチだけを指定すると不整合が起こる。
ということでした。
上のエラーが出たときは
git push origin HEAD:main
としてやるか、サブモジュール上で、mainをcheckoutしてコミットしなおし、pushするようにしてください。