Git - サブモジュールがdirtyだと言われたので直した(コミットハッシュが"XXX-dirty")
Gitの本を出しておきながらアレだけど、サブモジュールのことをちゃんとしっかりはよく分かってない。ある日、いつものように git status
したらサブモジュールに差分があるではないか。
※本記事でとりあげる例において、スーパープロジェクト*1から見たbats/lib/bats
がサブモジュールである(GitHub - bats-core/bats-core: Bash Automated Testing Systemおよびその兄弟的なリポジトリたちを使っている)。
$ git status On branch pyrsia-1448 Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) (commit or discard the untracked or modified content in submodules) modified: bats/lib/bats (modified content) no changes added to commit (use "git add" and/or "git commit -a")
差分を見ると
$ git diff diff --git a/bats/lib/bats b/bats/lib/bats --- a/bats/lib/bats +++ b/bats/lib/bats @@ -1 +1 @@ -Subproject commit c97b3a1b8644ddede18bff6bc035c12e9f50be78 +Subproject commit c97b3a1b8644ddede18bff6bc035c12e9f50be78-dirty
何もしてないのにdirtyだなんて失礼しちゃう・・・意味を調べた。
結論
サブモジュール内のファイルに変更を加えてしまっている(何もしてないわけがない)。
解決策 - 差分自体をなくす
git status
が言う通りgit restore / checkout
して消してしまえば良い。ただ、サブモジュール側のGitディレクトリに対する操作となるようなので、カレントディレクトリを変更してから実行するか下記のように環境変数を使って場所を指定すれば良い。
$ GIT_DIR=bats/lib/bats/.git git restore .
解決策 - 同様の差分はそもそも無視する
基本的にサブモジュールに変更を加えたいことはない(よね?)と思っているので、見つけたら上記のような対処をしてしまうのがいい気がするものの、無視する方法もあるらしい。
git diff
やgit status
に--ignore-submodule
あるいは--ignore-submodules=dirty
(この場合はdirty
のときだけ無視。none
, all
, dirty
, untracked
のいずれかが使える)というオプションをつけるとサブモジュール内の変更は表示されない。
コマンド実行時にいちいち指定したくない場合、git config diff.ignoreSubmodules dirty
と設定変更しておけば毎度無視されるらしい。どういうモチベでオンにするのか正直よく分からないのはサブモジュール経験値が低いからか。
さらに、.gitmodules
ファイルにignore = dirty
って書くという方法(↓例)もあるが、チーム全体で無視しよう!とはなかなかならないような?(基本的に無視に否定的…)
[submodule "bats/lib/bats"] path = bats/lib/bats url = https://github.com/bats-core/bats-core.git ignore = dirty
だらだらと詳細
dirtyなんて失礼しちゃうと思ったところからの調べものメモ。差分が検知されたサブモジュールのGitディレクトリで改めてステータスを確認するとこうなった。
$ git status HEAD detached at c97b3a1 Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: test/file_setup_teardown.bats no changes added to commit (use "git add" and/or "git commit -a")
該当ファイルの差分はこんな感じで、ローカルで末尾のスペースが削られていた。
これを見てひらめいた。多分、ShellCheck(ShellscriptのLintツール)をプロジェクト全体にかけちゃったからだ・・・。
やはりサブモジュールに変更を加えたいことってあんまりない気がするから見つけたらちゃんと確認するのが良さそう。やりたいタイミングとして思いつくのはサブモジュールとして依存しているライブラリのバグを踏んだときの動作確認とかかな?それ以外は正規の更新手順を踏むんじゃなかろうか。
ちなみに、スーパープロジェクトで実行したgit status
の結果(冒頭の例)だが、ファイル編集・削除を行った場合は modified: bats/lib/bats (modified content)
、追加すると modified: bats/lib/bats (untracked content)
という表示になるようだ。dirty
にはこれらすべてが含まれ、 untracked
は追加のみを指すらしい。
参考文献 - 公式docありがとう
- Git - gitsubmodules Documentation
- Git - gitmodules Documentation
- Git - git-status Documentation
- Git - Environment Variables
*1:親にあたるリポジトリをこう呼ぶみたい。https://git-scm.com/docs/gitsubmodules/2.19.2