В чем разница между HEAD, рабочим деревом и индексом в Git?

488

Может кто-нибудь сказать мне разницу между HEAD, рабочим деревом и индексом в Git?

Из того, что я понимаю, это все названия для разных веток. Правильно ли мое предположение?


редактировать

я нашел это

Один репозиторий git может отслеживать произвольное количество веток, но ваше рабочее дерево связано только с одной из них (ветвью «текущая» или «извлеченная»), и HEAD указывает на эту ветку.

Значит ли это, что HEAD и рабочее дерево всегда одинаковы?

Джойс Бабу
источник
26
Что касается вашего редактирования: абсолютно нет. HEADэто коммит на кончике текущей ветки. Если вы только что извлекли ветку, то есть не имеют измененных файлов, то ее содержимое соответствует рабочему дереву. Как только вы что-то измените, оно больше не будет совпадать.
Каскабель
6
Я думаю, что вы должны прочитать это: think-like-a-git.net
Анджей Ду
5
Я также добавил бы Staging Areaк этому списку. Что HEAD, Working Tree, IndexиStaging Area
зеленый
2
Последнее предложение @ Jefromi's было бы более ясным, как:> Как только вы что-то измените, рабочее дерево больше не будет соответствовать
коммиту
3
Для любого чтения этого в будущем лучший способ действительно понять некоторые из этих ответов состоит в том, чтобы видеть и чувствовать и визуально осмысливать то, что происходит: это лучший инструмент для изучения git когда-либо: onlywei.github.io/explain-git-with -d3 / # fetchrebase
BKSpurgeon

Ответы:

579

Несколько других хороших ссылок на эти темы:

альтернативный текст

Я использую индекс в качестве контрольной точки .

Когда я собираюсь внести изменения, которые могут пойти не так, как надо, - когда я хочу исследовать какое-то направление, в котором я не уверен, смогу ли я довести до конца или даже буду ли это хорошая идея, например, концептуально требующий рефакторинг или изменение тип представления - я проверяю свою работу в индексе. Если это первое изменение, которое я сделал со времени моего последнего коммита, то я могу использовать локальный репозиторий в качестве контрольной точки, но часто у меня есть одно концептуальное изменение, которое я внедряю в виде набора маленьких шагов. Я хочу проверять точку после каждого шага, но сохраняю коммит, пока не вернусь к работающему, проверенному коду.

Ноты:

  1. рабочее пространство является дерево каталогов (источник) файлы , которые можно просматривать и редактировать.

  2. Индекс представляет собой один большой двоичный файл в <baseOfRepo>/.git/index, в котором перечислены все файлы в текущей ветви, их SHA1 контрольные суммы, метки времени и имя файла - это не другой каталог с копией файлов в нем.

  3. Локальный репозиторий находится скрытый каталог ( .git) , включая objectsкаталог , содержащий все версии каждый файл в репозитории (местные филиалы и копию удаленных филиалов) в качестве сжатого файла «Blob».

Не думайте о четырех «дисках», представленных на рисунке выше, как об отдельных копиях файлов репо.

альтернативный текст

Они в основном называются ссылками для коммитов Git. Существует два основных типа ссылок: метки и заголовки.

  • Теги - это фиксированные ссылки, которые отмечают определенный момент в истории, например, v2.6.29.
  • Напротив, руководители всегда двигаются, чтобы отразить текущую позицию развития проекта.

альтернативный текст

(примечание: в комментировал по Тимо Huovinen , эти стрелки не то , что коммиты указывают на это, это порядок документооборота , в основном , демонстрирующая стрелки , как , 1 -> 2 -> 3 -> 4где 1это первое обязательство и 4последний)

Теперь мы знаем, что происходит в проекте.
Но чтобы знать, что происходит прямо здесь, прямо сейчас есть специальная ссылка под названием HEAD. Он служит двум основным целям:

  • он сообщает Git, с какого коммита брать файлы при оформлении заказа, и
  • он говорит Git, куда помещать новые коммиты, когда вы делаете коммит.

При запуске git checkout refон указывает HEADна ссылку, которую вы определили, и извлекает из нее файлы. При запуске git commitон создает новый объект фиксации, который становится дочерним по отношению к текущему HEAD. Обычно HEADуказывает на одну из головок, поэтому все работает просто отлично.

альтернативный текст

VonC
источник
20
Прочитав много раз о git lot, я никогда не понимаю этого полностью, я очень расстроился и хочу использовать слово f; Но я в сообществе! Вы упомянули головы, но на изображениях выше всегда есть одна ГОЛОВА, где находятся оставшиеся головы **? «Обычно HEAD указывает на одну из головок, поэтому все работает отлично». Прошу объяснить это, Ура заявление.
Necktwi
12
@neckTwi HEAD - это текущий коммит, с которым вы работаете ( stackoverflow.com/a/964927/6309 ). Обычно это один из «заголовков веток» (один из коммитов, на которые ссылаются ветки, представляющий верхушку указанных ветвей). Но вы можете проверить (и работать над) любой коммит. Если вы извлекаете коммит, который не является одним из (ветвлений) заголовков, вы находитесь в режиме «отсоединенного HEAD»: stackoverflow.com/a/3965714/6309
VonC
1
@ Я хочу согласиться, но именно так я и нашел эти фотографии 5 лет назад ( hades.name/blog/2010/01/28/… )
VonC
11
Что касается индекса, я думаю, что наиболее полезная вещь, которую можно сказать: «Индекс - это просто другое название области подготовки», как сказал @ ashraf-alam. Я чувствую, что большую часть времени в обсуждении это называется областью подготовки, поэтому я не установил автоматически, что это то же самое, что и индекс.
Пит
1
@ Пит, я согласен. Подробнее о разнице между кешем и индексом см. В моем другом ответе stackoverflow.com/a/6718135/6309
VonC
137

Разница между HEAD (текущая ветвь или последнее зафиксированное состояние в текущей ветке), индексом (или промежуточной областью) и рабочим деревом (состояние файлов в извлечении) описана в разделе «Три состояния» «Основы 1.3 Git » глава книги Pro Git Скотта Чакона (лицензия Creative Commons).

Вот изображение, иллюстрирующее это из этой главы:

Локальные операции - рабочий каталог и промежуточная область (индекс) против git-репозитория (HEAD)

На приведенном выше изображении «рабочий каталог» аналогичен «рабочему дереву», «область подготовки» - это альтернативное имя для git «index», а HEAD указывает на текущую извлеченную ветвь, которая указывает на последний коммит в « git directory (репозиторий) "

Обратите внимание, что git commit -aвнесет изменения и зафиксировать в один шаг.

Якуб Наребски
источник
1
"Одна картинка стоит тысячи слов". Спасибо Якуб .. И спасибо за ссылку.
Джойс Бабу
5
Примечание: working treeкажется, предпочтительнее в working directoryнастоящее время. См. Github.com/git/git/commit/…
VonC
3
Это изображение не совсем точное, поскольку промежуточная область содержится в одном файле с именем «index» - и этот индексный файл находится в корне каталога .git. Поэтому, если вы определите репо как каталог .git, техническая область находится внутри репо. Третий столбец лучше обозначить как «Объект корневого дерева HEAD», чтобы указать, что извлеченные файлы поступают из объекта фиксации и что фиксация записывает новое дерево в объект фиксации - оба объекта фиксации указываются HEAD.
Джазимов
@Jazimov Вы, вероятно, правы, но, как он написал, он взял эту фотографию из известной книги Pro Git, и он дал ссылку. Таким образом, если картина может быть улучшена или даже неправильна, кто-то должен сказать авторам этой книги ... В общем, я был бы готов сделать это, но, если честно, я все еще начинающий и не знаю понял, что вы сказали, так что я определенно не тот человек в этом случае.
Бинарус
@Binarus: Опасность при оптовом воспроизведении таких изображений заключается в том, что они служат для распространения «искажения», сделанного одним автором / книгой. Я думаю, что это случай буквального и функционального толкований: в буквальном смысле индекс фактически содержится в репо, если вы определяете репо как все, что находится в папке .git. Однако в функциональном смысле индекс помогает Git поддерживать DAG в репо и может рассматриваться как существо, внешнее по отношению к нему.
Джазимов
64

Ваше рабочее дерево - это то, что на самом деле находится в файлах, над которыми вы сейчас работаете.

HEADявляется указателем на ветвь или коммит, который вы в последний раз извлекли, и который будет родителем нового коммита, если вы его сделаете. Например, если вы находитесь на masterветке, то HEADбудет указывать master, и когда вы фиксируете, этот новый коммит будет потомком ревизии, на которую он masterуказывал, и masterбудет обновляться, чтобы указывать на новый коммит.

Индекс является промежуточной областью , где новый фиксации готов. По сути, содержимое индекса - это то, что войдет в новый коммит (хотя, если вы это сделаете git commit -a, это автоматически добавит все изменения в файлы, которые Git знает о индексе перед фиксацией, поэтому он будет фиксировать текущее содержимое вашего рабочего дерева. ). git addдобавит или обновит файлы из рабочего дерева в ваш индекс.

Брайан Кэмпбелл
источник
Большое спасибо за объяснение, Брайан. Итак, рабочее дерево содержит все незафиксированные изменения. Если я фиксирую свои изменения с помощью git commit -a, то в это конкретное время мое Рабочее дерево и Индекс будут одинаковыми. Когда я подтолкну к своему центральному репо, все три будут одинаковыми. Я прав?
Джойс Бабу
3
@ Винод В значительной степени. В вашем рабочем дереве могут быть файлы, о которых Git не знает, и они не будут зафиксированы git commit -a(вы должны добавить их git add), поэтому в вашем рабочем дереве могут быть дополнительные файлы, которые ваш индекс, локальное хранилище или вашего удаленного репо нету.
Брайан Кэмпбелл
2
@Vinod: Рабочее дерево и индекс могут стать одинаковыми без фиксации (git add обновляет индекс из рабочего дерева, а git checkout <path> обновляет рабочее дерево из индекса). HEADотносится к самому последнему коммиту, поэтому, когда вы делаете коммит, вы обновляете его HEADдо нового коммита, который соответствует индексу. Pushing не имеет к этому никакого отношения - он создает ветки в ветвях удаленного соответствия в вашем локальном репо.
Каскабель
45

Рабочее дерево

Ваше рабочее дерево - это файлы, над которыми вы сейчас работаете.

Git index

  • «Индекс» git - это место, куда вы помещаете файлы, которые хотите зафиксировать, в репозиторий git.

  • Индекс также известен как кеш , кеш каталога , текущий кеш каталога , область подготовки , промежуточные файлы. .

  • Прежде чем «фиксировать» (проверять) файлы в репозитории git, вам необходимо сначала поместить файлы в «индекс» git.

  • Индекс не является рабочим каталогом: вы можете ввести команду, например git status, и git скажет вам, какие файлы в вашем рабочем каталоге были добавлены в индекс git (например, с помощью git add filenameкоманды).

  • Индекс не является репозиторием git: файлы в индексе git - это файлы, которые git передал бы в репозиторий git, если бы вы использовали команду git commit.

Ашраф Алам
источник
1
Обратите внимание, что Git 2.5 принесет несколько рабочих деревьев ( stackoverflow.com/a/30185564/6309 ). +1
VonC
3
Я не уверен, что «Индекс не является рабочим каталогом» на 100% правильно. Это должно быть «Индекс не является рабочим каталогом, но он включает в себя весь рабочий каталог + изменения, которые вы хотите зафиксировать следующим». Доказательство? зайдите в репозиторий git, reset --hard HEADчтобы убедиться, что ваш индекс == ваше рабочее дерево. затем: mkdir history && git checkout-index --prefix history/ -aрезультатом будет дублирование всего вашего рабочего дерева в вашем history/каталоге. Ergo git index> = рабочий каталог git
Адам Куркевич
3
Индекс не является рабочим каталогом и не должен включать рабочий каталог. Индекс - это просто файл в репозитории git, в котором хранится информация, которую вы хотите зафиксировать.
Благо
3
«Индекс» содержит моментальный снимок содержимого рабочего дерева, и именно этот моментальный снимок берется в качестве содержимого следующего коммита. Таким образом, после внесения каких-либо изменений в рабочий каталог и перед запуском команды commit вы необходимо использовать команду добавления для добавления любых новых или измененных файлов в индекс "( git-scm.com/docs/git-add )
Anth
3
@AdamKurkiewicz: доказательство не удастся, если вы сначала echo untracked-data > untracked-file, до или после git reset --HARDиgit checkout-index шаги. Вы обнаружите, что неотслеживаемого файла нет в historyкаталоге. Вы также можете изменить индекс и рабочее дерево независимо, хотя изменение индекса без предварительного прикосновения к рабочему дереву затруднительно (требует использования git update-index --index-info).
Торек