Что такое 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 и до сих пор понял это:

Скажем, текущая ветка является главной.

  1. HEAD - это файл в вашем каталоге.git/, который обычно выглядит примерно так:
% cat .git/HEAD
ref: refs/heads/master
  1. refs / Heads / master сам по себе является файлом, который обычно имеет хеш-значение последней фиксации мастера:
% cat .git/refs/heads/master 
f342e66eb1158247a98d74152a1b91543ece31b4
  1. Если вы выполните журнал 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.

Другие вопросы по тегам