TL; DR: вы, вероятно, хотите, чтобы unset GIT_DIR
был в начале вашего сценария (хорошо, однако Haskell выполняет эту операцию).
Проблема здесь в том, что, хотя /tmp/A
является разумным Git-репозиторием, сам фактический репозиторий находится в подкаталоге .git
. Таким образом, /tmp/A/
- это рабочее дерево , а /tmp/A/.git
- это собственное хранилище .
При нормальной работе мы запускаем git <em>subcommand arguments ...</em>
, например, git status
или git commit -m <em>message</em>
из наших рабочих деревьев . Рабочее дерево содержит каталог .git
или, в некоторых случаях, файл 1 a .git
. Команда верхнего уровня git
проверяет наличие .git
, находит его и сообщает ага, хранилище равно ./.git
. Или он не находит .git
, поэтому он смотрит на один уровень вверх, например, с /tmp/A
он поднялся бы на один уровень до /tmp
сам и проверил там .git
. Это повторяется до некоторой точки остановки. 2
Во всех случаях этот процесс поиска должен либо успешно завершиться - путем нахождения собственного хранилища, либо git <em>subcommand</em>
умрет с сообщением fatal: Not a git repository ...
. Теперь приходит критический и скрытый на виду, секретный: На этом этапе команда верхнего уровня git
устанавливает переменную среды с именем GIT_DIR
для хранения пути к действительному хранилищу. It затем запускает подкоманду, которая использует $GIT_DIR
для поиска хранилища. В нашем обычном сценарии использования, где мы находимся в /tmp/A
, а /tmp/A
содержит каталог .git
, это устанавливает $GIT_DIR
в /tmp/A/.git
, и все подкоманды работают.
Но в вашем случае $GIT_DIR
уже установлен. В частности, он установлен на .
. Так что теперь команда git
верхнего уровня прекращает поиск . Он только проверяет, что $GIT_DIR
является действительным, и называет репозиторий Git, либо умирает с сообщением об ошибке fatal
. Так как /tmp/A
не является хранилищем - это действительно /tmp/A/.git
- это вызывает проблему.
Сброс переменной среды снова включает поиск, устраняя проблему. Вы также можете использовать --git-dir
в качестве аргумента или установить правильное значение в $GIT_DIR
. Обратите внимание, что те же правила применяются с $GIT_WORK_TREE
: аргумент --work-tree
устанавливает $GIT_WORK_TREE
, и если вы не используете его, а $GIT_WORK_TREE
не установлен , то интерфейс * 1082 Команда * использует свой , взбирающийся по дереву файловой системы в каталог .git
или код файла , чтобы найти корень вашего рабочего дерева. Поэтому, если $GIT_DIR
или $GIT_WORK_TREE
установлены при запуске git <em>subcommand</em>
, Git подчиняется им, если вы не переопределите их с помощью --git-dir
и / или --work-tree
.
Крючки всегда имеют $GIT_DIR
набор. Также они могут иметь или не иметь $GIT_WORK_TREE
. Большинство из них работают на верхнем уровне рабочего дерева, но, как и документация githooks заметки, pre-receive
, update
, post-receive
, post-update
и push-to-checkout
все работают в $GIT_DIR
.
1 Уловка .git
-as-a-file используется и подмодулями, и добавленными рабочими деревьями в современном Git. Git 1.7 и более ранние 1.8 оставили подмодули со встроенными каталогами .git
и не поддерживают добавленные рабочие деревья.
2 Очевидная остановка - достижение /
, когда некуда подняться. Однако Git по умолчанию осторожен, по крайней мере, в Unix и Unix-подобных системах, чтобы избежать лазания по точке монтирования . Точки монтирования позволяют вам объединять различные слои файловой системы и / или пулы хранения в единую древовидную иерархию. Обычно /tmp
сама по себе может быть файловой системой памяти, например, и большие системы могут изолировать «системное хранилище» (/
и т.п.) от «пользовательского хранилища» (/home
). Docker использует точки монтирования для реструктуризации файловых систем в образе Docker и т. Д.