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

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

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


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

я нашел это

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

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

4 ответа

Решение

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

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

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

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

Заметки:

  1. рабочая область - это дерево каталогов (исходных) файлов, которые вы видите и редактируете.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Git index

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

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

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

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

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

Это неизбежно длинное, но простое объяснение из книги ProGit:

Git как система в своей нормальной работе управляет тремя деревьями и манипулирует ими:

  • HEAD: последний снимок фиксации, следующий родитель
  • Индекс: Предлагаемый снимок следующей фиксации
  • Рабочий каталог: песочница

Голова

HEAD - это указатель на текущую ссылку на ветку, которая, в свою очередь, является указателем на последний коммит, сделанный в этой ветке. Это означает, что HEAD будет родительским для следующего созданного коммита. Обычно проще всего думать о HEAD как о снимке вашего последнего коммита в этой ветке.

Что в нем содержится?
Чтобы увидеть, как выглядит этот снимок, выполните следующее в корневом каталоге вашего репозитория:

                                 git ls-tree -r HEAD

это приведет к примерно такому результату:

                       $ git ls-tree -r HEAD  
                       100644 blob a906cb2a4a904a152... README  
                       100644 blob 8f94139338f9404f2... Rakefile  
                       040000 tree 99f1a6d12cb4b6f19... lib  

Индекс

Git заполняет этот индекс списком всего содержимого файлов, которые в последний раз были извлечены в ваш рабочий каталог, и того, как они выглядели, когда были изначально извлечены. Затем вы заменяете некоторые из этих файлов новыми версиями, и git commit преобразует их в дерево для новой фиксации.

Что в нем содержится?
Использовать git ls-files -s чтобы увидеть, как это выглядит. Вы должны увидеть что-то вроде этого:

                 100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README   
                 100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile  
                 100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb  

Рабочий каталог

Здесь находятся ваши файлы и вы можете опробовать изменения перед их фиксацией в промежуточной области (индекс), а затем в истории.

Визуализированный образец

Давайте посмотрим, как эти три дерева (как их называет книга ProGit) работают вместе?
Типичный рабочий процесс Git - записывать снимки вашего проекта в последовательно улучшающихся состояниях, манипулируя этими тремя деревьями. Взгляните на эту картинку:

Чтобы получить хорошее визуальное понимание, рассмотрите этот сценарий. Допустим, вы переходите в новый каталог с единственным файлом в нем. Назовите это v1 файла. Он обозначен синим цветом. Бегgit init создаст репозиторий Git со ссылкой HEAD, которая указывает на нерожденную главную ветку

На данный момент содержимое имеет только рабочее дерево каталогов. Теперь мы хотим зафиксировать этот файл, поэтому используемgit add чтобы взять содержимое из рабочего каталога и скопировать его в index.

Затем мы бежим git commit, which takes the contents of the index and saves it as a permanent snapshot, creates a commit object which points to that snapshot, and updates master to point to that commit.

If we run git status, we’ll see no changes, because all three trees are the same.

The beautiful point

git status shows the difference between these trees in the following manner:

  • If the Working Tree is different from index, then git status will show there are some changes not staged for commit
  • If the Working Tree is the same as index, but they are different from HEAD, then git status will show some files under changes to be committed section in its result
  • If the Working Tree is different from the index, and index is different from HEAD, then git statusв результате отобразит некоторые файлы в разделе изменений, не запланированных для раздела фиксации, и некоторые другие файлы в разделе изменений, которые необходимо зафиксировать.

Для более любопытных

Примечание о git resetкоманда
Надеюсь, зная, какreset командные работы еще больше прояснят причину существования этих трех деревьев.

resetКоманда - это ваша машина времени в git, которая может легко вернуть вас во времени и принести вам несколько старых снимков для работы. Таким образом, ГОЛОВА - это червоточина, через которую вы можете путешествовать во времени. Посмотрим, как это работает, на примере из книги:

Рассмотрим следующий репозиторий, в котором есть один файл и 3 коммита, которые показаны разными цветами и разными номерами версий:

Состояние деревьев как на следующей картинке:

Шаг 1: перемещение ГОЛОВКИ (- soft):

Первое, что сделает сброс - переместит то, на что указывает HEAD. Это не то же самое, что изменение самой HEAD (что и делает checkout). reset перемещает ветку, на которую указывает HEAD. Это означает, что если HEAD настроен на основную ветку, запуск git reset 9e5e6a4 начнется с установки главной точки на 9e5e6a4. Если вы позвонитеreset с --soft вариант на этом остановится, не меняя index а также working directory. Теперь наше репо будет выглядеть так:
Примечание: HEAD~ является родительским элементом HEAD.

Посмотрев второй раз на изображение, мы видим, что команда фактически отменила последнюю фиксацию. Поскольку рабочее дерево и индекс такие же, но отличаются от HEAD,git status Теперь изменения будут отображаться зеленым цветом, готовые к фиксации.

Шаг 2: Обновление индекса (--mixed):

Это опция по умолчанию для команды

Бег reset с --mixedопция обновляет индекс содержимым любого снимка, на который указывает HEAD в данный момент, оставляя рабочий каталог нетронутым. При этом ваш репозиторий будет выглядеть так, как будто вы выполнили некоторую работу, которая не является этапной иgit statusэто будет показано красным цветом, поскольку изменения, не предназначенные для фиксации. Эта опция также отменяет последнюю фиксацию, а также отменяет все изменения. Вы как будто внесли изменения, но не позвонилиgit addкоманды пока нет. Теперь наше репо будет выглядеть так:

Шаг 3: Обновление рабочего каталога (--hard)

Если вы позвоните reset с --hardвариант, он будет копировать содержимое снимка, на который указывает HEAD, в HEAD, index и Working Directory. После выполнения команды reset --hard это будет означать, что вы вернулись в предыдущий момент времени и после этого ничего не сделали. см. картинку ниже:

Вывод

Я надеюсь, что теперь вы лучше понимаете эти деревья и имеете прекрасное представление о той силе, которую они дают вам, позволяя изменять файлы в репозитории, чтобы отменить или повторить действия, которые вы сделали по ошибке.

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