`git status`を実行すると、後続の `git diff-index`の結果が変わるのはなぜですか?

`git status`を実行すると、後続の `git diff-index`の結果が変わるのはなぜですか?

考慮する:

$ git --version
git version 2.20.1 (Apple Git-117)
$ git diff-index --quiet HEAD ; echo $?
1
$ git status > /dev/null
$ git diff-index --quiet HEAD ; echo $?
0

これは大文字と小文字を区別しないファイルシステムを使用するMacosの場合です。 (関連があるかどうかはわかりません。)この問題が発生するホストには、同じディレクトリがマウントされたdebianを実行するドッカーイメージがあり、ドッカーイメージでは逆の動作が発生します。

$ git diff-index --quiet HEAD ; echo $?
0
# At this point, `git status` was invoked outside the docker image
$ git --version
git version 2.20.1
$ git diff-index --quiet HEAD ; echo $?
1

明確に言えば、ここで実行されるコマンドの順序は、git diff-indexdockerイメージ(0戻り)、git diff-indexホスト(1戻り)、git statusホスト、git diff-indexホスト(0戻り)、git diff-indexdockerイメージ(1戻り)です。

git-statusデフォルトでは、ある環境で実行すると、git diff-indexその環境では成功(0を返す)し、別の環境では失敗します。何が起こっているのか考えていますか?大きな問題ではありません。ファイルシステムの大文字と小文字が区別されないことが原因であると疑われますが、確実な説明があることを願っています。

答え1

私も同様の問題を経験しましgit diff-filesたが、原因は同じようです。 Dockerや大文字と小文字を区別しないファイルシステムを含める必要はありませんが、これは問題を悪化させる可能性があります。

Gitはファイルの内容に関する情報キャッシュを維持します。通常、これは必要に応じてキャッシュを更新するgit statusなどの透明で高レベルのコマンドです。git diff

git diff-indexなどの低レベルのコマンドは、git diff-files高速ですがおおよその結果を返すように設計されています。キャッシュを更新しません。比較される項目が同じであると確信している場合は0を返しますが、1を返すと「これが同じかどうかわかりません」という意味です。キャッシュエントリが古い場合、内容は同じですが、未知のgit diff-xxx可能性があります。

キャッシュがどのように機能するのか正確にはわかりません。最初の実験では、最初の呼び出しでキャッシュエントリが古くなっていることに気づいたようですgit diff-index。その後、キャッシュがgit status更新され、2番目の呼び出しでgit diff-index有効なキャッシュエントリを調べて、ファイルが同じであると結論付けます。 2番目の実験では、git statusDockerコンテナの外部で実行すると、git diff-indexコンテナ内に古いと見なされるキャッシュエントリが生成されるように見えるため、2番目の呼び出しはgit diff-index「不明」を意味する1を返します。

私の解決策は、低レベルのコマンドを忘れてそのコマンドに固執することでしたgit diff --quiet

関連情報