Что такое HEAD в Git?
Вы видите документацию Git, в которой говорится что-то вроде
Ветка должна быть полностью объединена в HEAD.
Но что такое Git HEAD
именно так?
28 ответов
Вы можете думать о ГОЛОВЕ как о "текущей ветви". Когда вы переключаете ветви с git checkout
версия HEAD изменяется, чтобы указывать на вершину новой ветви.
Вы можете увидеть, на что указывает HEAD:
cat .git/HEAD
В моем случае вывод:
$ cat .git/HEAD
ref: refs/heads/master
HEAD может ссылаться на конкретную ревизию, которая не связана с именем ветви. Эта ситуация называется отдельной головой.
Цитировать других людей:
Голова - это просто ссылка на объект фиксации. У каждой головы есть имя (название ветви или имя тега и т. Д.). По умолчанию в каждом репозитории есть заголовок с именем master. Хранилище может содержать любое количество головок. В любой момент времени в качестве "текущей головы" выбирается одна голова. Эта голова имеет псевдоним HEAD, всегда заглавными буквами ".
Обратите внимание на это различие: "голова" (в нижнем регистре) относится к любой из названных голов в хранилище; "ГОЛОВА" (верхний регистр) относится исключительно к текущей активной голове. Это различие часто используется в документации Git.
Другой хороший источник, который быстро охватывает внутреннюю работу git (и, следовательно, для лучшего понимания head /HEAD), можно найти здесь. Ссылки (ref:) или заголовки или ветки могут рассматриваться как заметки, прикрепленные к коммитам в истории коммитов. Обычно они указывают на вершину серии коммитов, но их можно перемещать с помощью git checkout
или же git reset
и т.п.
В этих ответах есть, возможно, тонкое, но важное заблуждение. Я думал, что добавлю свой ответ, чтобы прояснить это.
Что такое
HEAD
?
ГОЛОВА ТЫ
HEAD
символическая ссылка, указывающая на то, где вы находитесь в истории коммитов. Он следует за вами, куда бы вы ни пошли, что бы вы ни делали, как тень. Если вы делаете коммит, HEAD
поедет. Если вы что-то заказываете, HEAD
поедет. Что бы вы ни делали, если вы переехали куда-то новое в историю ваших коммитов, HEAD
переехал вместе с вами. Чтобы устранить одно распространенное заблуждение: вы не можете оторваться от HEAD
, Это не то, что состояние отделенного HEAD. Если вы когда-нибудь обнаружите, что думаете: "О, нет, я нахожусь в отдельном состоянии ГОЛОВА! Я потерял свою ГОЛОВУ!" Помните, это ваша голова. ГОЛОВА это ты. Вы не отсоединились от ГОЛОВОЙ, вы и ваша ГОЛОВА отошли от чего-то другого.
К чему может присоединиться ГОЛОВА?
HEAD
может указывать на коммит, да, но обычно это не так. Позвольте мне сказать это снова. типично HEAD
не указывает на коммит. Это указывает на ссылку ветви. Он привязан к этой ветви, и когда вы делаете определенные вещи (например, commit
или же reset
), присоединенная ветвь будет двигаться вместе с HEAD
, Вы можете увидеть, на что он указывает, заглянув под капот.
cat .git/HEAD
Обычно вы получите что-то вроде этого:
ref: refs/heads/master
Иногда вы получите что-то вроде этого:
a3c485d9688e3c6bc14b06ca1529f0e78edd3f86
Вот что происходит, когда HEAD
указывает непосредственно на коммит. Это называется отдельной головой, потому что HEAD
указывает на что-то, кроме ссылки на ветку. Если вы делаете коммит в этом состоянии, master
больше не привязан к HEAD
больше не будет двигаться вместе с вами. Неважно, где находится этот коммит. Вы можете использовать тот же коммит, что и ваша основная ветка, но если HEAD
указывает на коммит, а не на ветку, он отсоединен, и новый коммит не будет связан со ссылкой на ветку.
Вы можете посмотреть на это графически, если попытаетесь выполнить следующее упражнение. Запустите это из репозитория git. Вы получите что-то немного другое, но они будут иметь ключевое значение. Когда пришло время извлекать коммит напрямую, просто используйте любой сокращенный хеш, который вы получите из первого вывода (здесь это a3c485d
).
git checkout master
git log --pretty=format:"%h: %d" -1
# a3c485d: (HEAD -> master)
git checkout a3c485d -q # (-q is for dramatic effect)
git log --pretty=format:"%h: %d" -1
# a3c485d: (HEAD, master)
Итак, здесь небольшая разница в выводе. Проверка коммита напрямую (вместо ветки) дает нам запятую вместо стрелки. Как вы думаете, мы находимся в отдельном состоянии головы? HEAD все еще ссылается на конкретную ревизию, связанную с именем ветви. Мы все еще в основной ветке, не так ли?
Теперь попробуйте:
git status
# HEAD detached at a3c485d
Нету. Мы находимся в состоянии "отсоединенная ГОЛОВА".
Вы можете увидеть то же представление (HEAD -> branch)
против (HEAD, branch)
с git log -1
,
В заключение
HEAD
это ты. Это указывает на то, что вы проверили, где бы вы ни находились. Обычно это не коммит, а ветка. Если HEAD
указывает на коммит (или тег), даже если это тот же коммит (или тег), на который указывает ветка, вы (и HEAD
) были отделены от этой ветви. Поскольку к вам не прикреплена ветка, ветка не будет следовать за вами, когда вы делаете новые коммиты. HEAD
Впрочем, будет.
HEAD - это просто специальный указатель, который указывает на локальную ветку, в которой вы находитесь.
Из книги Pro Git, глава 3.1 Ветвление Git - ветви в двух словах, в разделе Создание новой ветки:
Что произойдет, если вы создадите новую ветку? Ну, это создает новый указатель для вас, чтобы двигаться. Допустим, вы создаете новую ветку под названием "Тестирование". Вы делаете это с помощью команды git branch:
$ git branch testing
Это создает новый указатель на тот же коммит, на котором вы сейчас находитесь
Как Git узнает, в какой ветке вы сейчас находитесь? Он хранит специальный указатель под названием HEAD. Обратите внимание, что это сильно отличается от концепции HEAD в других VCS, к которым вы можете привыкнуть, таких как Subversion или CVS. В Git это указатель на локальную ветку, в которой вы находитесь. В этом случае вы все еще на мастере. Команда git branch только создала новую ветку - она не переключалась на эту ветку.
Я рекомендую это определение от разработчика github Скотта Чакона [ видео ссылка]:
Голова это твоя текущая ветка. Это символическая ссылка. Это ссылка на ветку. У вас всегда есть HEAD, но HEAD будет указывать на один из этих других указателей, на одну из ветвей, на которой вы находитесь. Это родитель вашего следующего коммита. Это то, что должно быть последним извлеченным в вашем рабочем каталоге... Это последнее известное состояние вашего рабочего каталога.
Все видео даст хорошее представление о всей системе git, поэтому я также рекомендую вам посмотреть все, если есть время.
Если предположить, что это не особый случай, называемый "отсоединенная ГОЛОВА", то, как указано в книге О'Рейли Гит, 2-е издание, с.69, HEAD
средства:
HEAD
всегда ссылается на самый последний коммит в текущей ветке. Когда вы меняете филиалы,HEAD
обновляется для ссылки на последний коммит новой ветки.
так
HEAD
является "наконечником" текущей ветви.
Обратите внимание, что мы можем использовать HEAD
ссылаться на самый последний коммит и использовать HEAD~
в качестве коммита перед кончиком, и HEAD~~
или же HEAD~2
как коммит еще раньше и пр.
HEAD
относится к текущему коммиту, на который указывает ваша рабочая копия, т.е. к коммиту, который вы в данный момент извлекли. Из официальной документации Linux Kernel по указанию ревизий Git:
HEAD
называет коммит, на котором вы основали изменения в рабочем дереве.
Обратите внимание, однако, что в следующей версии Git 1.8.4, @
может также использоваться как сокращение для HEAD
Как отметил участник Git Джунио С. Хамано в своем блоге Git Blame:
Вместо того, чтобы вводить "HEAD", вы можете сказать "@", например, "git log @".
Пользователь VonC Stack Overflow также нашел интересную информацию о том, почему @
был выбран в качестве стенографии в ответе на другой вопрос.
Также интересно, что в некоторых средах нет необходимости использовать заглавные буквы HEAD
особенно в операционных системах, использующих файловые системы без учета регистра, особенно в Windows и OS X.
Посмотрите на Создание и игра с ветками
HEAD - это файл, содержимое которого определяет, куда ссылается переменная HEAD:
$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed
В этом репозитории содержимое файла HEAD ссылается на второй файл с именем refs /head / master. Файл refs /head / master содержит хэш самого последнего коммита в ветке master.
В результате HEAD указывает на коммит главной ветки из файла .git/refs/head / master.
Иллюстрация, показывающая, что такое HEAD, включая параллельное сравнение различий в манипулировании HEAD в прикрепленном или отсоединенном состоянии.
Распространенное заблуждение состоит в том, что сообщение " Вы находитесь в состоянии" отключена HEAD " имеет ошибочный тон, хотя на самом деле оно просто описывает, как HEAD ссылается на текущий моментальный снимок.
Чтобы перейти из отсоединенного состояния в присоединенное, вы можете либо создать новую ветку с того места, где вы находитесь, либо переключиться на существующую ветвь. Обратите внимание, что любые коммиты, созданные в отсоединенном состоянии, в конечном итоге будут отброшены, если вы переключитесь на другую существующую ветвь.
Прочитав все предыдущие ответы, я все еще хотел большей ясности. Этот блог на официальном сайте Git http://git-scm.com/blog дал мне то, что я искал:
HEAD: указатель на последний моментальный снимок, следующий родитель
HEAD в Git - это указатель на текущую ссылку на ветвь, которая, в свою очередь, является указателем на последний сделанный вами коммит или последний коммит, который был извлечен в ваш рабочий каталог. Это также означает, что это будет родитель следующего коммита, который вы делаете. Как правило, проще всего думать об этом, поскольку HEAD - это снимок вашего последнего коммита.
Я просто хотел бы подробно рассказать о нескольких вещах в принятом ответе Грега Хьюджила. Согласно Git Pocket Guide
Ветка:
Сама ветвь определяется как все точки, достижимые в графе коммитов из именованного коммита ("кончик" ветки).
ГОЛОВА: особый тип Реф
Специальный ref HEAD определяет, на какой ветке вы находитесь...
Refs
Git определяет два вида ссылок или именованных указателей, которые он называет "refs":
- Простая ссылка, которая указывает непосредственно на идентификатор объекта (обычно коммит или тег)
- Символическая ссылка (или symref), которая указывает на другую ссылку (простую или символическую)
Как упомянул Грег, HEAD может находиться в "обособленном состоянии". Таким образом, HEAD может быть либо простым ref (для отдельного HEAD), либо symref.
если HEAD является символической ссылкой для существующей ветви, то вы находитесь "на" этой ветви. Если, с другой стороны, HEAD - это простой реф, непосредственно именующий коммит его идентификатором SHA-1, то вы находитесь не в "любой" ветви, а в режиме "отсоединенного HEAD", который происходит, когда вы проверяете некоторые ранее. поручить изучить.
Я думаю, что "HEAD" - это текущий коммит. Другими словами, "HEAD" указывает на коммит, который в данный момент извлечен.
Если вы только что клонировали и не проверили, я не знаю, на что это указывает, возможно, какое-то неверное местоположение.
Отличный способ отразить правильные ответы - это запуститьgit reflog HEAD
, вы получаете историю всех мест, на которые указал HEAD.
Голова указывает на верхушку проверенной ветки.
В вашем репозитории есть папка.git. Откройте файл в этом месте: .git\refs\head. Код (sha-1 hash) в этом файле (в большинстве случаев master) будет самым последним коммитом, т. Е. Кодом, отображаемым в выходных данных команды. git log
, Дополнительная информация о папке.git: http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html
Такое чувство HEAD
это просто тег для последнего зафиксированного вами коммита.
Это может быть верхушка определенной ветви (например, "master") или некоторая промежуточная фиксация ветви ("detached head")
HEAD почти буквально является главой ветки. Поэтому, когда вы наблюдаете за веткой, вы смотрите на последний коммит, который является тем же самым главой ветки. Однако вы можете указать себе, что смотрите на другую фиксацию, расположенную дальше в истории этой ветки, и когда вы это делаете, вы перемещаете HEAD на предыдущую фиксацию. Поскольку HEAD естественным образом принадлежал последнему коммиту в ветке, он считается отсоединенным.
Визуальное представление. Каждая ветвь — это гусеница, а каждый коммит — это сегмент существа. Таким образом, ГОЛОВА будет находиться в сегменте, который больше всего впереди. Если вы переместите ГОЛОВКУ из этого в другой сегмент, который будет использоваться, вы отсоедините головку от естественного сегмента. Надеюсь, это имеет смысл.
Теперь, если вы отсоедините HEAD в основной ветке, затем проверите newFeature и снова проверите main, HEAD все равно будет отсоединен поверх другого коммита. Я вижу ГОЛОВУ как зеркало, которое вы можете указать, куда хотите.
В репозитории может быть несколько голов. И общее количество голов всегда равно общему количеству веток, присутствующих в репозитории, что означает, что головы - это не что иное, как последние коммиты каждой ветки.
Но для репозитория будет только одна HEAD.HEAD - это ссылка, которая ссылается на последнюю фиксацию, выполненную в текущей ветке.
Это похоже на глаз пользователя git: на какую бы фиксацию ни ссылается HEAD, репозиторий начинает отражать состояние репозитория во время этого конкретного коммита.
Основная природа HEAD - всегда ссылаться на последнюю фиксацию текущей ветки, но мы можем переместить HEAD в любую фиксацию текущей ветки, используя git checkout «commit-hash»
Примечание: мы можем легко получить хэш фиксации, используя команду git log --oneline
Git
все о коммитах.
А такжеHead
указывает на фиксацию, которую вы в настоящее время извлекли.
$ git cat-file -t HEAD
commit
Каждый раз, когда вы проверяете ветку, HEAD указывает на последнюю фиксацию в этой ветке. Содержимое HEAD можно проверить, как показано ниже (для основной ветки):
$ cat .git/refs/heads/master
b089141cc8a7d89d606b2f7c15bfdc48640a8e25
Чтобы понять, что такое HEAD, давайте возьмем практический пример с двумя разными ветвями и от двух разных разработчиков Dev1 и Dev2, работающих над одним и тем же проектом.
Случай 1 с веткой Dev1:
name~/repo (main)
$ ls -al
total 9
drwxr-xr-x 1 AlphaLy 197121 0 Dec 22 15:09 ./
drwxr-xr-x 1 AlphaLy 197121 0 Dec 21 20:35 ../
drwxr-xr-x 1 AlphaLy 197121 0 Dec 22 15:09 .git/
-rw-r--r-- 1 AlphaLy 197121 20 Dec 21 20:35 README.md
-rw-r--r-- 1 AlphaLy 197121 0 Dec 22 15:09 test.txt
Далее1
name~/repo (main)
$ cd .git/
name~/repo/.git (GIT_DIR!)
$ ls
COMMIT_EDITMSG description HEAD index logs/ ORIG_HEAD refs/
config FETCH_HEAD hooks/ info/ objects/ packed-refs
Далее2
name~/repo/.git (GIT_DIR!)
$ cat HEAD
ref: refs/heads/main
Мы можем ясно видеть, что HEAD — это файл со строкой, указывающей на файл с именем, расположенный внутриrefs/heads
каталог (это каталог внутри каталога). Обратитесь к шагу Next1, чтобы найти каталог
Теперь давайте перейдем к шагу Next1 иcd
вrefs
директории и найдите файл внутриheads
каталог и посмотреть, что он содержит
name~/repo/.git (GIT_DIR!)
$ cd refs
name~/repo/.git/refs (GIT_DIR!)
$ ls
heads/ remotes/ tags/
name~/repo/.git/refs/ (GIT_DIR!)
$ cd heads/
name~/repo/.git/refs/heads (GIT_DIR!)
$ ls
main maxi
name~/repo/.git/refs/heads (GIT_DIR!)
$ cat main
8b25d89f3396177416c055ab07ebf778616eecdd
8b25d89f3396177416c055ab07ebf778616eecdd
является текущим коммитом. Итак, мы можем сказать, что HEAD относится к файлу с именемmain
(всегда именуется в честь текущей ветки), который содержит текущую фиксацию (40-значный символ выше). Итак, HEAD относится к текущему коммиту.
Случай 2 с веткой Dev2
Здесь единственная разница будет в шаге Next2.
name~/repo/.git (GIT_DIR!)
$ cat HEAD
ref: refs/heads/feature1
и следующее:
name~/repo/.git (GIT_DIR!)
$ cat feature1
03fbf973ac1014085864234010b82393208ebbd6
03fbf973ac1014085864234010b82393208ebbd6
текущий коммит наfeature1
ветвь. Итак, здесь снова HEAD ссылается на файл с именем feature1 (названный в честь текущей ветки), который содержит текущую фиксацию (символ из 40 цифр выше).
Заключение:
HEAD относится к текущему коммиту, а не к текущей ветке. Это просто совпадение, что файл, содержащий этот текущий коммит, назван в честь текущей ветки, о которой мы склонны говорить, что «HEAD относится к текущей ветке».
В дополнение ко всем определениям у меня в голове застряло то, что когда вы делаете коммит, GIT создает объект фиксации в репозитории. У объектов коммитов должен быть родитель (или несколько родителей, если это коммит слияния). Теперь, как git узнает родителя текущего коммита? Таким образом, HEAD является указателем на (ссылку на) последний коммит, который станет родителем текущего коммита.
Я также все еще разбираюсь во внутренностях git и до сих пор понял это:
Скажем, текущая ветка является главной.
- HEAD - это файл в вашем каталоге.git/, который обычно выглядит примерно так:
% cat .git/HEAD
ref: refs/heads/master
- refs / Heads / master сам по себе является файлом, который обычно имеет хеш-значение последней фиксации мастера:
% cat .git/refs/heads/master
f342e66eb1158247a98d74152a1b91543ece31b4
- Если вы выполните журнал git, вы увидите, что это последняя фиксация для мастера:
% git log --oneline
f342e66 (HEAD -> master,...) latest commit
fa99692 parent of latest commit
Поэтому я считаю, что файл HEAD - это удобный способ отслеживать последнюю фиксацию вместо запоминания длинных хеш-значений.
Эти двое могут сбить вас с толку:
голова
Указывая на именованные ссылки ветка недавно представленная. Если вы не используете ссылку на пакет, заголовки обычно хранятся в $ GIT_DIR/refs/head /.
ГОЛОВА
Текущая ветвь или ваше рабочее дерево обычно генерируется из дерева, на которое указывает HEAD. ГОЛОВА должна указывать на голову, за исключением того, что вы используете отдельную ГОЛОВУ.
Я сам еще не понял этого, но ссылка Silfheed на определение « заметки, прилепленные к узлу » — лучшее, что я нашел до сих пор .
Хочу поделиться своими впечатлениями от поиска определения, иначе зачем держать это при себе. Я понимаю это действительно как стикеры, приклеенные к текущему положению в пространстве дерева Git . Мне не хватает именно такого термина — текущей позиции в дереве GIT , у которого есть свои атрибуты , указывающие, где мы находимся.
Мне непонятны такие понятия, как " ссылка " или " указатель ". Мне кажется, они подразумевают новый уровень абстракции, изнутри которого мы на что-то «обращаемся». Это может быть неправдой, но так я это вижу до сих пор.
Как только вы создаете фиксацию, появляется указатель с именем head, который указывает на эту фиксацию, как только вы делаете следующую фиксацию, переключение головы с первой фиксации на другую сделанную вами фиксацию.
HEAD на самом деле просто файл для хранения информации о текущей ветке
и если вы используете HEAD в своих командах git, вы указываете на свою текущую ветку
вы можете увидеть данные этого файла поcat .git/HEAD
Ветвь фактически является указателем, который держит совершить ID, такие как 17a5.HEAD - это указатель на ветку, над которой в данный момент работает пользователь.
В HEAD есть справочная карта, которая выглядит так:
ссылка:
Вы можете проверить эти файлы, открыв .git/HEAD
.git/refs
которые находятся в репозитории, в котором вы работаете.
Взгляните на http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is
Рисунок 3-5. Файл HEAD, указывающий на ветку, в которой вы находитесь.
Как концепция, глава является последней ревизией в отрасли. Если у вас есть более одного заголовка на именованную ветвь, вы, вероятно, создали его при выполнении локальных коммитов без слияния, фактически создавая неназванную ветвь.
Чтобы иметь "чистый" репозиторий, вы должны иметь одну головку на каждую именованную ветвь и всегда сливаться с именованной ветвью после локальной работы.
Это также верно для Mercurial.