(Примечание: некоторые из них являются общими.)
Дополнительная странность здесь, вероятно, связана с тем, что у каждого рабочего дерева есть свой собственный HEAD
файл. Различные операции могут находить разные файлы HEAD
путем сворачивания регистра: есть файл .git/worktrees/<em>worktree</em>/HEAD
для добавленного рабочего дерева и файл .git/HEAD
для основного рабочего дерева. Если операция A выбирает .git/HEAD
для совпадения head
, а операция B выбирает .git/worktrees/<em>worktree</em>/HEAD
, вы увидите именно это поведение. Использование прописных букв HEAD
должно заставить Git делать правильные вещи.
(В частности, git reset --hard
внутренне использует HEAD
во всех столицах, что будет относиться к дереву для каждой работы HEAD
, в то время как git rev-parse head
использует строчные буквы head
, которые относятся к .git/HEAD
файл.)
Вы можете проверить любой исторический коммит по его необработанному хеш-идентификатору:
git checkout a123456
Результатом является то, что Git называет обособленной HEAD . Обычно специальное имя HEAD
(заглавными буквами) , прикрепленное , к названию филиала:
...--A--B--C--D <-- master (HEAD)
\
E--F--G <-- branch
(заглавные буквы здесь обозначают фактические хеш-идентификаторы коммитов). При таком присоединении HEAD
означает master
, что означает фиксацию D
. Таким образом, ваш текущий коммит теперь соответствует реальному хэш-идентификатору D
. Если вы запустите:
git checkout branch
вы получите:
...--A--B--C--D <-- master
\
E--F--G <-- branch (HEAD)
, что означает, что ваша текущая ветвь равна branch
, а ваш текущий коммит теперь равен G
.
Когда вы выбираете коммит по хеш-идентификатору, хотя, скажем, коммит E
, вы HEAD
указываете непосредственно на этот коммит:
...--A--B--C--D <-- master
\
E <-- HEAD
\
F--G <-- branch
Это то, что Git называет «отделенной головой»; ваш текущий коммит это коммит E
.
Теперь вы не использовали необработанный хэш-идентификатор. Вместо этого вы набрали head^
. Но есть много способов назвать коммиты. Необработанный хеш-идентификатор является способом самого низкого уровня: хеш-идентификатор всегда работает и всегда означает , что один конкретный коммит , но вы также можете сделать так, чтобы Git нашел parent некоторого коммита. Вот что означает HEAD^
: выберите родителя текущего коммита. Предположим, текущий коммит G
, потому что вы на branch
; затем HEAD^
имена совершают F
, а после:
git checkout HEAD^
у вас будет:
...--A--B--C--D <-- master
\
E--F <-- HEAD
\
G <-- branch
Строчная версия head
работает в Windows и MacOS, но не в Linux. Это побочный эффект того факта, что Git иногда сохраняет эти вещи в файлах (например, .git/HEAD
и .git/refs/heads/master
). Используя head
вместо HEAD
, Git может попытаться открыть .git/refs/heads/head
, который не существует, но когда Git пытается открыть .git/head
, он получает .git/HEAD
, который действительно существует , Так что на этих машинах , git checkout head^
означает то же самое, что и git checkout HEAD^
: найти текущий коммит, вернуться к его первому родителю и проверить , что commit.
Чтобы заново прикрепить HEAD
к какой-либо ветке, используйте git checkout <em>branch-name</em>
.
Если вы не используете Windows или MacOS (или даже если это так), обратите внимание, что вы можете также создать ветвь или тег с именем head
. Если вы это сделаете, все станет немного скрупулезно, особенно в Windows и MacOS, поскольку теперь есть два способа разрешения head
: в виде ветви или тега, и как .git/HEAD
. Лучше не делать этого.