Проверять старый коммит и поддерживать голову в основной ветке? - PullRequest
84 голосов
/ 14 апреля 2011

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

git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

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

Ответы [ 6 ]

189 голосов
/ 14 апреля 2011

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

git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

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

78 голосов
/ 14 апреля 2011

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

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

git checkout -b newbranch ea3d5ed

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

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

A  B  C
*--*--* <-- master <-- HEAD

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

A  B  C  D
*--*--*--* <-- master <-- HEAD

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

A  B  C  D
*--*--*--* <-- master
   ^
    \-- HEAD

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

A  B  C  D
*--*--*--* <-- master
    \
     * <-- HEAD
     E

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

A  B  C  D
*--*--*--* <-- master <-- HEAD
    \
     *
     E

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

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

A  B  C  D
*--*--*--* <-- master
   ^
    \-- branch <-- HEAD

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

7 голосов
/ 11 декабря 2013

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

git co <previous-commit-id>

после этой команды вы будете находиться в ветке с именем "(без ветки)".

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

git br

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

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

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

5 голосов
/ 14 апреля 2011

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

Это краткое объяснение. Надеемся, что многословие, приведенное ниже, поможет понять разницу между HEAD и master:

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

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

То есть: «Родитель C - B, а родитель B - A. Ведущий ветки указывает на C, и я в настоящее время проверил содержимое master. Кроме того, когда я фиксирую, мастер обновляется. ”

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

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

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

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

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

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

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

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

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

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

1 голос
/ 10 марта 2015

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

git checkout [commit|branch] -- .

Затем вы можете внести измененияи создайте новый коммит, если хотите.Это иногда очень полезно.

0 голосов
/ 03 октября 2013

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

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

как тег v2.0

шаг 2: git checkout v2.0

вот оно, теперь ваш HEAD указывает на коммит 'v2.0', но мастер все еще указывает на последний коммит.

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

или введите git help

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