Проблема заключается в том, как команды 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)
Это приведет к удалению только отслеживаемых в данный момент файлов (после него останутся файлы, которые были удалены, но когда-то отслеживались в подсказках, которые были нажаты, когда активен сломанный хук).
Одним из решений является изменение текущего рабочего каталога на обычное рабочее дерево и сброс GIT_DIR и GIT_WORK_TREE перед вызовом команд Git.
⋮
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 »?» рекомендует post-update script , который делает именно это , Связанный скрипт также намного безопаснее, так как он делает тайник, если индекс или рабочее дерево загрязнено перед выполнением аппаратного сброса.