問題は、フック スクリプト用に作成された環境と通常の環境での Git コマンドの動作の違いです。
まず、フック スクリプトは、現在の作業ディレクトリを Git ディレクトリ自体 (つまり、.git/
ベア リポジトリ以外のディレクトリ) に設定して実行します。次に、GIT_DIR 環境変数が設定され、Git リポジトリ (ここでも.git/
非ベア リポジトリのディレクトリ) を指すフック スクリプトが実行されます。
git reset --hard
通常、ディレクトリから実行しようと.git/
すると、次のメッセージが表示されて終了します。
fatal: This operation must be run in a work tree
しかし、GIT_DIR が設定されている場合、Git コマンドは現在のディレクトリが作業ツリーであると想定します。フックが実行されるときの現在のディレクトリは.git/
ディレクトリであるため、実際には作業ツリー ファイルを親ディレクトリではなくgit reset --hard
直接「チェックアウト」しています(つまり、バージョン管理されたコンテンツのコピーがディレクトリにあります)。.git/
.git/
Git が Git リポジトリ自体で使用するパス名と一致するパス名が、リポジトリ内のバージョン管理されたコンテンツにないことを願っています。それらが一致する場合git reset --hard
は、リポジトリの内部構造の一部が上書きされているため、おそらく他のリポジトリから再クローンする必要があります。バージョン管理されたコンテンツのいずれも Git の内部パス名と競合しないと確信している場合は、次の方法でクリーンアップできる可能性があります。
# make a backup of your repository first!
(cd .git && GIT_DIR=$PWD git ls-files -cz | xargs -0 rm)
これにより、現在追跡されているファイルのみが削除されます (その後削除されたが、壊れたフックがアクティブな間にプッシュされたヒントコミットで一度追跡されたファイルが残ります)。
1 つの解決策は、Git コマンドを呼び出す前に、現在の作業ディレクトリを通常の作業ツリーに変更し、GIT_DIR と GIT_WORK_TREE の設定を解除することです。
⋮
test "${PWD%/.git}" != "$PWD" && cd ..
unset GIT_DIR GIT_WORK_TREE
# you can now safely use Git commands
⋮
別の解決策は、明示的に GIT_DIR をリセットし、そこに GIT_WORK_TREE と chdir を設定することです。Git FAQ 「「git push」後にリモート リポジトリに変更が表示されないのはなぜですか?」</a> では、これを行う更新後スクリプトを推奨しています。リンクされたスクリプトは、ハード リセットを実行する前にインデックスまたは作業ツリーが汚れている場合にスタッシュを作成するため、はるかに安全です。