В чем разница между HEAD, рабочим деревом и индексом в Git?
Может кто-нибудь сказать мне разницу между HEAD, рабочим деревом и индексом в Git?
Из того, что я понимаю, это все названия для разных веток. Правильно ли мое предположение?
редактировать
я нашел это
Один репозиторий git может отслеживать произвольное количество веток, но ваше рабочее дерево связано только с одной из них (ветвью "текущая" или "извлеченная"), и HEAD указывает на эту ветку.
Значит ли это, что HEAD и рабочее дерево всегда одинаковы?
4 ответа
Несколько других хороших ссылок на эти темы:
Я использую индекс в качестве контрольной точки.
Когда я собираюсь внести изменения, которые могут пойти не так, как надо - когда я хочу исследовать какое-то направление, в котором я не уверен, смогу ли я довести до конца или даже буду ли это хорошая идея, например, концептуально требующий рефакторинг или изменение тип представления - я проверяю свою работу в индексе. Если это первое изменение, которое я сделал со времени моего последнего коммита, тогда я могу использовать локальный репозиторий в качестве контрольной точки, но часто у меня есть одно концептуальное изменение, которое я внедряю в виде набора маленьких шагов. Я хочу проверять точку после каждого шага, но сохраняю коммит, пока не вернусь к работающему, проверенному коду.
Заметки:
рабочая область - это дерево каталогов (исходных) файлов, которые вы видите и редактируете.
Индекс представляет собой один большой двоичный файл в
<baseOfRepo>/.git/index
, в котором перечислены все файлы в текущей ветви, их контрольные суммы sha1, отметки времени и имя файла - это не другой каталог с копией файлов в нем.Локальный репозиторий является скрытым каталогом (
.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 "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 это будет означать, что вы вернулись в предыдущий момент времени и после этого ничего не сделали. см. картинку ниже:
Вывод
Я надеюсь, что теперь вы лучше понимаете эти деревья и имеете прекрасное представление о той силе, которую они дают вам, позволяя изменять файлы в репозитории, чтобы отменить или повторить действия, которые вы сделали по ошибке.