Поиск по сайту:

Как исправить «Отдельный HEAD» в репозитории Git?


Одним из регулярных сообщений об ошибках, с которыми вы, вероятно, столкнетесь в Git, является предупреждение о том, что «вы находитесь в состоянии 'detached HEAD'». Возможно, вы наткнулись на это случайно, но не волнуйтесь — это обычная проблема, и ее можно легко исправить, как только вы поймете, что это значит.

Что такое Git HEAD?

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

Обычно HEAD напрямую не ссылается на один коммит. Вместо этого он указывает на ветку и косвенно ссылается на последнюю фиксацию в этой ветке. Всякий раз, когда вы «выписываете» новую ветку, Git переключает HEAD на эту ветку. Это позволяет вам делать новые коммиты, которые будут добавлены в конец этой ветки.

Однако вы также можете проверить отдельные коммиты. Что, если вы хотите изучить репозиторий в определенный момент времени? Это одно из основных преимуществ Git, но оно создает небольшую проблему в том, как Git структурирует вещи. Поскольку новые коммиты не будут обновлять ветку, любые коммиты, которые вы сделаете после удаления HEAD, станут отсоединенными от всех ссылок на ветки, следовательно, «отсоединенные HEAD».

Это действительно может быть довольно полезно. Скажем, вы переместили HEAD назад на несколько коммитов, а затем сделали несколько экспериментальных обновлений. По сути, вы создаете новую ветку, которая позже может быть объединена с master.

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

Если вы попали сюда случайно

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

Если вы только что извлекли коммит и не трогали репозиторий в противном случае (никаких новых коммитов не было), вы можете просто переместить HEAD туда, где он должен быть, с помощью git checkout:

git checkout master

В основном это похоже на запуск cd в Linux, за исключением того, что Git по-прежнему связывает кэшированные коммиты и изменения со старым HEAD, поэтому вам не нужно проверять, если у вас есть коммиты или изменения, которые останутся висящими.

Если у вас были какие-то изменения, и вы хотите их просто выбросить, вы можете полностью сбросить настройки до master:

git reset --hard origin/master
git clean -d --force

Однако, если вы хотите сохранить свои коммиты, вам нужно будет официально объединить их с временной шкалой Git.

Если вы хотите сохранить изменения

Первое, что вам нужно сделать, если вы хотите сохранить изменения, сделанные вами в отсоединенном состоянии HEAD, — это создать новую ветку. Это связано с тем, что сборщик мусора Git автоматически очищает отсоединенные коммиты, так что вы никогда не захотите их потерять.

git branch detached-branch

Затем вы можете проверить эту ветку, чтобы переместить HEAD, чтобы он больше не был отсоединен, и вместо этого указывал на эту официальную новую ветку:

git checkout detached-branch

После того, как изменения записаны, у вас есть один из двух вариантов. Эта новая ветка представляет собой обычную функциональную ветку, поэтому вы можете использовать git merge или git rebase.

Слияние является простым; мастер проверки и объединить отсоединенную ветку:

git checkout master
git merge detached-branch

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

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

В этом примере фиксация выше отсоединена. Вместо того, чтобы объединять его, он выбирается и перемещается в ветку feature . Это перемещает ветвь HEAD и feature так, чтобы она указывала на последнюю фиксацию без слияния. Затем исходный отсоединенный коммит можно удалить.

Во-первых, вам нужно сделать отдельную ветку, а затем проверить ветку feature, чтобы переместить туда HEAD:

git branch detached-branch
git checkout feature

Затем запустите Git log, чтобы получить список коммитов:

git log --pretty=format:"%h %s" --graph

Затем вы можете выбрать коммит по его идентификатору:

git cherry-pick 1da76d3

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

git branch -D detached-branch

Перебазирование вместо слияния

Вы также можете выполнить перебазирование. Ребазы отличаются от слияний тем, что они переписывают историю ветки, поднимая отсоединенные коммиты и перемещая их в начало ветки.

Однако проблема в том, что у вас по-прежнему остаются две ветки, и вам все равно нужно будет объединить feature и detached-branch вместе, в результате чего у вас останется слияние совершить в любом случае. Но это оставляет репозиторий с более линейной историей Git, что предпочтительнее, чем запуск git merge, если у вас есть на это полномочия.