Как исправить состояние «Detached HEAD» в Git

Как исправить состояние «Detached HEAD» в Git

9 ноября 2022 г.

Частый источник путаницы при использовании Git – непонимание того, что все это значит, когда вы видите такой вывод:

You are in 'detached HEAD' state. You can look around, make 
experimental changes and commit them, and you can discard any 
commits you make in thisstate without impacting any branches 
by switching back to a branch.

Что все это значит?

Чтобы действительно понять, что происходит, нам нужно заглянуть внутрь Git.

Коммиты Git неизменяемы — это означает, что вы можете создавать новые, но то, что уже внутри, никогда не изменится. Вот как наш репозиторий обеспечивает безопасность данных для нас. Единственный способ внесения изменений в репозиторий — создание новых коммитов.

Коммиты Git дают нам стабильную и полную историю изменений в репозитории. Поверх этой стабильной базы у нас есть динамическая часть: ветки. Что может поначалу удивить, так это то, что ветки — это просто метки. Они указывают на один коммит. У них буквально нет других данных, кроме имени и его положения.

Все, кроме этого, например

  • специальное значение main или master,
  • шаблоны, такие как feature/<info> или <branch-owner>/<description>, — это просто соглашение, которое используют команды. С точки зрения Git ваша ветка main или master ничем не отличается от ветки lorem-ipsum.

Текущая фиксация

HEAD — это указатель на текущую фиксацию — место, где вы сейчас находитесь в репозитории. Используется как:

  • точка отсчета, когда вы хотите увидеть последние изменения в вашей рабочей копии с помощью git diff
  • коммит, который будет использоваться как родительский при создании нового коммита

Ваш HEAD является центральной частью состояния вашего репозитория.

Нормальное состояние

Типичный рабочий процесс с Git выглядит следующим образом:

  • вы находитесь в какой-то ветке,
  • вы создаете новую фиксацию и
  • Git перемещает вашу ветку в этот новый коммит.

Если вы ограничитесь проверкой только веток, вы никогда не покинете это состояние. Когда вы запускаете git status, он сообщает вам, в какой ветке вы находитесь:

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Отдельная ГОЛОВА

До сих пор HEAD (текущая фиксация) и ветвь находились в нормальном, выровненном состоянии. Все усложняется, когда вы извлекаете что-то, что не является ветвью, например, когда вы переключаетесь на фиксацию по ее идентификатору:

$ git checkout abc01e7

где abc01e7 — идентификатор любого коммита в репозитории — он может быть внутри любой из веток, поверх одной из них или в другом месте истории репозитория.

Поскольку вы больше не находитесь в ветке, git status изменится на:

$ git status
HEAD detached at abc01e7
nothing to commit, working tree clean

Чтобы привлечь ваше внимание к этой ситуации, Git окрашивает HEAD detached в красный цвет.

Почему вы должны переключиться на фиксацию, а не на ветку?

Потому что вы можете, и иногда это может быть полезно. Обычный сценарий — посмотреть, как приложение работало несколькими фиксациями ранее, например, для устранения неполадок. Мы заметили что-то не так, например, функция не работает должным образом, и мы проверяем последний коммит, который, как мы ожидаем, будет работать нормально. Таким образом, мы можем точно определить, когда именно возникла проблема.

Как это влияет на работу?

Поскольку вы не находитесь в ветке, у Git нет ветки, которую нужно обновить при создании нового коммита. Таким образом, все коммиты, которые вы там создаете, хранятся, но остаются висящими: нет никакого способа легко добраться до них, и, как таковые, они считаются неважными. В какой-то момент сборщик мусора навсегда удалит их из репозитория.

Как это произошло?

Вы покинули ветку и переместили HEAD в другое место. Это может случиться:

  • путем извлечения ссылки, не относящейся к филиалу:
  • git checkout <идентификатор фиксации> — см. выше
  • git checkout HEAD^ — последняя фиксация
  • git checkout <tag>: теги похожи на ветки, но они должны быть неизменяемыми и не обновляются как ветки.
  • когда ваш git rebase остановился на полпути — из-за конфликта или для того, чтобы вы могли внести изменения в коммиты,
  • во время git bisect

Как это исправить

К счастью, вы получаете некоторые инструкции непосредственно в интерфейсе командной строки, когда проверяете ссылку, не относящуюся к ветке:

$ git checkout abc01e7
Note: switching to 'abc01e7'.

You are in 'detached HEAD' state. You can look around, make 
experimental changes and commit them, and you can discard any 
commits you make in this state without impacting any branches 
by switching back to a branch.

If you want to create a new branch to retain commits you 
create, you may do so (now or later) by using -c with the 
switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable 
advice.detachedHead to false

Создать новую ветку

Вы можете создать новую ветку точно в том месте, где вы находитесь, включая все коммиты, которые вы, возможно, создали оттуда. Вы можете создать ветку со следующим синтаксисом:

git switch -c <new-branch-name>

или в командной форме Git версии старше 2.23:

git checkout -b <new-branch-name>

Эти команды создают новую ветку и устанавливают ее в качестве текущей ветки.

Кроме того, вы можете просто создать новую ветку для текущего коммита и остаться в состоянии HEAD:

git branch <new-branch-name>

Переключитесь на ветку и объедините свои коммиты

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

Как это выглядит в инструментах

Помимо статуса git, как можно увидеть это состояние?

Вы можете увидеть это на древовидной диаграмме Git

Если вы используете git log --oneline --graph --decorate --all (что-то Я рекомендую определить как псевдоним git tree), он по-другому покажет ваш HEAD. Когда это на ветке, вывод выглядит так:

$ git tree
* abc01e7 (HEAD -> main, origin/main) Add lorem ipsum to readme
* edd3504 Add readme

HEAD указывает стрелкой на ветку, на которой вы находитесь. Когда вы находитесь в состоянии "detached HEAD", main и HEAD отображаются отдельно как несвязанная ссылка:

$ git tree
* abc01e7 (HEAD, origin/main, main) Add lorem ipsum to readme
* edd3504 Add readme

Разница незначительна, но очевидна, если знать, почему на нее следует обращать внимание.

GitHub для рабочего стола

В ветке main:

Image description

Состояние "Отсоединенная голова":

Image description

Вы видите разницу в средней части заголовка? Один показывает «Текущая ветка»; в то время как другой «ОТСОЕДИНЕННАЯ ГОЛОВА».

Исходное дерево

В ветке main:

Image description

Состояние "Отсоединенная голова":

Image description

Отображается как текущая ветка HEAD.

Хотите узнать больше?

В Git есть много запутанных частей, когда вы начинаете его использовать, но он становится намного проще, когда вы лучше понимаете, как он работает. хранит свои данные. Если вы хотите узнать больше о Git, зарегистрируйтесь здесь, чтобы получать обновления о моем контенте, посвященном Git.< /p>

:::информация Первоначально опубликовано здесь.

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE