Проверяете старую фиксацию и поддерживаете голову в главной ветке?

85

В настоящее время для переключения на другой коммит git (в той же ветке ... фактически, в главной ветке!) Я выполняю команду

git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

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

пожирал элизиум
источник
1
После того, как вы выполните эту команду, ваш HEAD ref изменится на этот коммит. Нет смысла хотеть, чтобы ГОЛОВА указывала куда-то еще.
Грег Хьюгилл
Насколько я понимаю из сообщения git, он никуда не указывает , что нежелательно.
пожрал элизиум
1
Появится сообщение Git показывает , когда вы заканчивали специфично совершить так говорит : «Голова теперь в ea3d5ed ...», который говорит вам , что голова будет указывать куда - то. Он просто указывает на то место, у которого нет другого имени, кроме HEAD (на данный момент, поскольку a git checkoutв другое имя фиксации или ветки переместит HEAD в это новое место).
Грег Хьюгилл
Достаточно ли эти ответы объясняют это или есть что-то более ясное? Я буду рад пояснить вам свой ответ, если он не отвечает на ваш вопрос.
Брайан Кэмпбелл,
Если вы пришли сюда в поисках способа проверить другую фиксацию, сохранив при этом HEAD полностью неизменным (например, чтобы вернуться к более старой фиксации): git revert --no-commit 0766c053..HEADсделаете это, где 0766c053находится фиксация, которую вы хотите проверить. Это из stackoverflow.com/a/21718540/525872 .
Jo Liss

Ответы:

193

В большинстве случаев, когда я это делаю, я проверяю временную ветку:

git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

Затем, когда я закончу, я просто удаляю ветку

Ник Канцонери
источник
80

Это зависит от того, что вы хотите сделать, когда проверяете этот коммит. Если все, что вы делаете, это проверяете, чтобы вы могли собрать или протестировать эту ревизию, тогда нет ничего плохого в работе с отсоединенной головкой. Просто не забудьте проверить фактическую ветку, прежде чем делать какие-либо коммиты ( git checkout masterнапример), чтобы вы не создавали коммиты, которые не включены ни в одну ветку.

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

git checkout -b newbranch ea3d5ed

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

Давайте начнем с 3 коммитов master, A, B и C. master- это текущая ветвь, поэтому HEADуказывает master, что указывает на фиксацию C.

ABC
* - * - * <- master <- HEAD

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

ABCD
* - * - * - * <- master <- HEAD

Теперь давайте проверим B, дав нам отдельный HEAD.

ABCD
* - * - * - * <- мастер
   ^
    \-- ГОЛОВА

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

ABCD
* - * - * - * <- мастер
    \
     * <- ГОЛОВА
     E

Если позже мы решим проверить еще masterраз, там не будет ничего, относящегося к E.

ABCD
* - * - * - * <- master <- HEAD
    \
     *
     E

Поскольку на него ничего не ссылается, его может быть сложно найти, и git считает, что коммиты без ссылок должны быть оставлены (они случаются довольно часто, если вы переустанавливаете, или выжимаете патчи, или выполняете другие забавные манипуляции с историей; они обычно представляют собой заброшенные патчи что вас больше не волнует). По прошествии определенного времени git будет считать его мусором, который будет удален при следующем запуске сборки мусора.

Итак, вместо того, чтобы проверять голую ревизию и получать отдельную голову, если вы чувствуете, что собираетесь сделать больше коммитов, вам следует использовать git checkout -b branch Bдля создания ветки и проверки ее. Теперь ваши коммиты не будут потеряны, так как они будут включены в ветку, на которую вы можете легко ссылаться и объединить позже.

ABCD
* - * - * - * <- мастер
   ^
    \ - ветка <- HEAD

Если вы забудете это сделать и создадите коммиты в ветке, не о чем беспокоиться. Вы можете создать ветку, ссылающуюся на головную ревизию, с помощью git checkout -b branch. Если вы уже переключились обратно в masterветку и понимаете, что забыли случайную фиксацию, вы можете найти ее с помощью git reflog, которая покажет вам историю того, на что коммиты HEADуказали за последние несколько дней. Все, что все еще находится в журнале ссылок, не будет собираться мусором, и обычно ссылки хранятся в журнале ссылок не менее 30 дней.

Брайан Кэмпбелл
источник
Мне не совсем понятно, почему, когда вы проверяете старую фиксацию, голова отделяется . Может проблема в том, что значит оторванная голова? С другой стороны, если проверка старого коммита с отделенной головой приведет к его потере, зачем кому-то это делать? Просто чтобы поваляться и попробовать? Почему Git вообще это позволяет?
пожрал элизиум
5
@devoured elysium «отделенная голова» означает, что у вас есть HEADссылка, которая указывает прямо на SHA-1 коммита, а не на ветку, которая, в свою очередь, указывает на фиксацию. Поскольку ваша голова не ссылается на ветку, Git не знает, какую ветку обновлять, когда вы добавляете новые коммиты. Как я объяснил в начале своего ответа, совершенно нормально иметь отделенную голову, если вы возвращаетесь к старой версии только для сборки или тестирования кода; вы всегда можете вернуться в ветку с помощью git checkout masterи т.п. Это проблема только в том случае, если вы совершаете коммит, когда у вас оторвана голова.
Брайан Кэмпбелл
@BrianCampbell - После совершения коммитов в ветке (где сейчас находится ваша голова) вы затем объединяете ветку в B и объединяете B в мастер. Что делать дальше?
amey1908
Ваше объяснение заставило меня "щелкнуть" по множеству других вещей. Спасибо. Возможно, теперь я наконец понял мерзавца ...
Джо
8

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

git co <previous-commit-id>

после этой команды вы попадете в ветку под названием «(без ветки)».

Подтвердите это

git br

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

git co <the-branch-you-were-on>

«(Без ветки)» будет удален автоматически. Таким образом, вам не нужно создавать временную ветку.

Зак Сюй
источник
5

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

Это краткое объяснение. Мы надеемся, что приведенное ниже подробное описание поможет понять, чем отличаются HEAD и master:

Обычно все выглядит так:

C ← refs/heads/master ← HEAD 
↓
B
↓
A

То есть: «Родителем C является B, а родительским элементом B - A. Мастер ветки указывает на C, и в настоящее время я проверил содержимое мастера. Кроме того, когда я совершаю коммит, мастер должен быть обновлен ».

Здесь подразумеваются некоторые предположения, необходимые для полного понимания графа фиксации. А именно, коммиты относятся только к своим родителям, а содержимое ветки - это те коммиты (и только те коммиты), к которым можно получить доступ, следуя по родительским ссылкам. (Немодифицированное) содержимое рабочего дерева и индекса должно соответствовать фиксации, названной HEAD, косвенно («символически») или прямо («отсоединенной»).

Таким образом, если вы хотите проверить старую фиксацию, необходимо обновить HEAD, чтобы указать на желаемую фиксацию. git-checkoutделает именно это:

C ← refs/heads/master 
↓
B ← HEAD
↓
A

Итак, вы оставили свою ветку позади, так как вы смотрите на что-то старое. Это совершенно нормально, поскольку совет «оторванной головы» спокойно говорит вам (выделено мной):

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

С другой стороны, хотя сброс вашей ветки также приводит к тому, что HEAD будет там, где он должен быть, это будет иметь совсем другой эффект!

C
↓
B ← refs/heads/master ← HEAD
↓
A

Фиксация C станет мусором, поскольку вы заявили, что больше не хотите, чтобы она была частью основной ветки.

Короче говоря, все, что вам нужно сделать, это понять, что git означает «HEAD» - это то место, где вы находитесь, а не какая-либо конкретная ветвь. И если вы находитесь не в том месте, где находится ветвь, нет другого выбора, кроме как использовать отдельную HEAD.

(Возможно, также загляните в GitHub, gitk или gitweb, чтобы просмотреть историю коммитов, если срыв HEAD продолжает вас раздражать.)

Джош Ли
источник
1

Вопрос немного расплывчатый, но если вы хотите просто изменить файлы в своем рабочем дереве, вы можете просто сделать это:

git checkout [commit|branch] -- .

Затем вы можете подготовить изменения и создать новую фиксацию, если хотите. Иногда это бывает очень полезно.

Лари Хотари
источник
0

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

Шаг 1: создайте тег старого коммита, который вы хотите вернуть.

как тег v2.0

шаг 2: git checkout v2.0

вот он, теперь ваша ГОЛОВА указывает на фиксацию «v2.0», но мастер все еще указывает на последнюю фиксацию.

C:\Program Files\Git\doc\git\html\git-checkout.html этот документ может помочь вам

или введите git help <checkout>

Лев Лай
источник