2023年11月6日月曜日

gitのsubmoduleを配置できないときの対応


背景

バージョン管理プログラムのgitには、管理中のリポジトリにgitで管理する他のリポジトリを配置するsubmoduleという機能があります。
そのsubmoduleを利用してリポジトリを管理していたところ、ディレクトリ構成に齟齬が発生してsubmoduleのディレクトリをダウンロードできなくなり手間取りました。
調べつつ試行錯誤した末に期待通りに動く状態にできたので、遭遇した不具合と対応方法を記事に残します。

使ったもの

git
ubuntu22.04で動くversion 2.34.1を利用しました。

設定やファイルを消す前に試すべきsubmoduleのコマンド

submodule updateによる設定済みsubmoduleの初期設定

リポジトリのディレクトリ内で下記のコマンドを実行すると、設定済みのsubmoduleのファイルのダウンロード(clone)と配置が行われます。
git submodule update --init --recursive

構成が壊れていなければ上記のコマンドでsubmoduleに関するファイルが配置されます。

submodule addのforce実行

submodule addコマンドを実行すると下記のようなエラーが出る場合があります。
git submodule add https://repository-url-for/project-a.git
fatal: A git directory for 'project-a' is found locally with remote(s):
origin https://repository-url-for/project-a.git
If you want to reuse this local git directory instead of cloning again from
https://repository-url-for/project-a.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.

これは.git/modulesにclone済みのsubmodule向けリポジトリが存在している場合に発生します。
上記エラーの中でも説明されている通り--forceを付けて実行すると期待通りにaddできることがあります。
git submodule add --force https://repository-url-for/project-a.git

注意点として--forceはaddとgitのurlの間への配置が必要です。
コマンドの末尾に--forceを付けると「--force」というディレクトリ名でsubmoduleが配置されてややこしくなります。

間違って--forceディレクトリを作ってしまった場合は削除対象を「./--force」とすると--forceをコマンドではなくパスと認識させて消せます。
rm ./--force -r
合わせて.gitmodulesの--forceディレクトリの設定も削除してください。

submoduleのディレクトリと.gitmodulesと.git/modulesの削除の後に再配置

今回はproject-aをsubmoduleとして配置したはずなのに動かない場合を例として対応します。

期待するファイル構成
リポジトリのディレクトリ
|- .git # gitの管理ディレクトリ 通常は触りません
  |- .gitmodules # submoduleの配置を記述するファイル
|- project-a # 配置したリポジトリ
|- project-aの中身のファイル

.gitmodules
[submodule "project-a"]
path = project-a
url = https://repository-url-for/project-a.git

submoduleとして配置したはずのproject-aディレクトリにファイルが配置(ダウンロードやclone)されなくて困っている場合が、今回紹介する手順の対象です。

submoduleのディレクトリ削除

project-aをsubmoduleとして配置しているディレクトリを消します。
何も配置されずに困っている場合は空だと思いますが、後でsubmoduleを再配置する時に同じ名前のディレクトリがあると厄介なので消しておきます。

rm -r project-a

.gitmodulesの該当する設定を削除

project-aに関する設定を.gitmoduleから消します。

下記の設定を削除します。
.gitmodulesにsubmoduleの設定が複数ある場合は、対象の設定だけを削除します。
.gitmodulesにsubmoduleの設定が1つしかないのなら、.gibmodulesファイル自体の削除でも良いです。
.gitmodules
[submodule "project-a"]
path = project-a
url = https://repository-url-for/project-a.git

.git/modulesの該当ディレクトリ削除

この手順がこの記事の肝です。

.git/modulesにclone済みのsubmoduleのリポジトリが配置されるので、問題が発生しているsubmoduleのディレクトリがあるなら削除します。
削除には管理者権限が必要です。
sudo rm -r .git/modules/project-a

.gitディレクトリ内の他のファイルを消すとgitのバージョン管理が壊れる可能性があるので、対象となるパスに注意して削除してください。

削除したらcommitして再配置

.gitmodulesに削除の変更があるとsubmoduleの追加を行えないので、変更したファイルとディレクトリをcommitします。
git add .gitmodules project-a
git commit -m 'Remove submodule setting for project-a'

上記のcommitで.gitmodulesに削除の変更がなくなり、submoduleの追加が可能になるので配置したいsubmoduleを再度配置します。
git submodule add https://repository-url-for/project-a.git

配置できたら、対象の.gitmodulesの設定とディレクトリをコミットします。
git add .gitmodules project-a
git commit -m 'Add project-a as a submodule'

自分の遭遇した不具合では上記の操作でsubmoduleのファイル(project-a)を配置できました。

おわり

submoduleの扱いに四苦八苦しましたが、関連する設定とディレクトリの削除後にコミットした後submodule addし直したら正常に戻りました。
なお、この記事を書いて理解が進んだことで、addの「--force」の位置がgitのurlの前だと把握したので、自分が遭遇した不具合は正しい場所に--forceを書けば直ったのかもしれません。

ともあれ、submoduleを期待通りに配置できて良かったです。

参考

How do I remove a submodule?

0 件のコメント :