Странное название ветки после создания ветки от оторванной головы - PullRequest
1 голос
/ 22 января 2020

У меня была проблема с отсоединенной головкой в ​​моем Git. Я сделал проверку на предыдущем коммите. После этого мы сделали коммиты. Итак, после того, как я создал ветку для этого коммита.

git checkout -b detached-head-after-gitlab-crush

Итак, после этого я внес изменения и зафиксировал изменения.

Но теперь, когда я пишу git branch :

* (detached from a71c5ea)
  detached-head-after-gitlab-crush
  master

Итак, я хочу понять, что такое текущая ветвь и как она была создана.

Как я могу внести изменения в последнюю ветку, а также я не могу sh эта текущая ветвь к источнику.

git log --all --decorate --oneline --graph

показывает следующий результат:

* 548af67 (HEAD) Images were changed, and issue with Printing Gate entry records
* be89a73 (origin/detached-head-after-gitlab-crush, detached-head-after-gitlab-c
* 6979cba Files before solving HEAD detached problem
* fb89a62 Rules added, made some changes which I don't remember
| *   d4183f3 (origin/master, origin/HEAD, master) Merged files
| |\
|/ /
| *   3c3cadc Merge branch 'master' of http://gitlab.sdu.edu.kz/sdu/portal

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Давайте начнем с краткого обзора уже известных вам вещей:

  • Базовая c единица хранения в любом репозитории Git - это commit, Внутри коммитов есть более мелкие единицы - например, коммиты содержат файлы, в некоторой степени напоминающие то, как атомы содержат протоны, нейтроны и электроны, - но сам коммит - это контейнер, который вы должны использовать. (В этой аналогии мы хотим заниматься химией, а не ядерной физикой. ?)

  • Каждый коммит имеет свой уникальный идентификатор ha sh. Эти идентификаторы ha sh большие и уродливые и трудные для работы с людьми, поэтому Git иногда сокращает их для отображения: у вас есть, например, 548af67 (что коротко для чего-то гораздо более длинного), be89a73 (снова сокращение от 40 символов) и так далее. Я получил это из вашего git log --all --decorate --oneline --graph вывода. Каждый репозиторий Git везде согласен с тем, что эти идентификаторы ha sh зарезервированы для этих конкретных коммитов, даже если в этом репозитории нет этих коммитов.

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

  • Сам коммит содержит:

    • data: снимок всех ваших файлов. Это не отличается от предыдущего коммита. Это полная копия каждого файла. (Эти файлы хранятся в сжатом, замороженном, только для чтения, Git -только формате. Поскольку они только для чтения, они могут быть общими . Например, если большинство ваших коммитов имеют файл README, и существует только три версии из README за 90 коммитов, с одним изменением каждые 30 коммитов, затем одна внутренняя замороженная копия README в формате Git. обслуживает первые 30 коммитов, другие серверы следующие 30 и т. д.)

    • метаданные: информация о коммит, например: кто это сделал (имя и адрес электронной почты), когда (отметки даты и времени) и почему (сообщение в журнале фиксации). В этих метаданных каждый коммит может перечислять необработанный идентификатор ha sh некоторых предыдущих коммитов.


    В большинстве коммитов указан ровно один предыдущий коммит ha sh ID. Указанный коммит является коммитом parent , т. Е. Коммитом, который приходит непосредственно перед коммитом. Некоторые коммиты содержат более одного предыдущего коммита, т. Е. Имеют более одного родителя. Один коммит в каждом непустом репозитории был первым коммитом в этом репозитории, и поэтому перечисляет нет parent.

Всякий раз Git имеет доступ к одному коммиту, Git может посмотреть на родителя этого коммита (или родителей) и, следовательно, вернуться к предыдущему коммиту. Это дает Git доступ к родительскому коммиту. Так что теперь Git может найти другого родителя - родителя этого родителя, то есть деда коммита, который у нас был минуту назад, и, конечно, у этого коммита есть родитель. Таким образом, Git может найти всю историю , просто начиная с last commit и работая в обратном направлении.

Имена ветвей находят конкретный коммит

Но совершите га sh идентификаторы выглядят случайными и непредсказуемыми. Как вы - и Git - быстро и легко узнать, какой коммит - последний ? Это где имена ветвей входят. Имя ветви как master или detached-head-after-gitlab-crush хранит one commit ha sh ID. Этот идентификатор ha sh по определению является последним коммитом в этой ветви.

Давайте использовать заглавные буквы для обозначения фактических коммитов ha sh ID. Мы закончим довольно быстро, и это одна из причин, по которой Git не использует простые заглавные буквы, но это будет нормально для нашего рисунка. Давайте предположим, что наш репозиторий действительно новый и содержит только три коммита. Самым первым является коммит A, и поскольку он является первым, у него нет родителя:

A

Мы назовем второй коммит B. Он помнит ha sh ID первого коммита как его родителя. Итак, мы скажем, что commit B указывает на commit A, и нарисуем вот так:

A <-B

И, конечно, commit C содержит га sh Идентификатор коммита B, поэтому C указывает назад на B:

A <-B <-C

Чтобы быстро найти C, Git сохраняет свой идентификатор ha sh в name master:

A--B--C   <-- master

(На данный момент мы немного устали и становимся ленивыми и рисуем соединения из commit для коммитов в виде линий, а не стрелок. Просто помните, что они ' все еще стрелки, и они выходят из потомка и указывают на родителя, а не от родителя к потомку. Все части каждого коммита замораживаются навсегда, включая стрелки, выходящие из него, поэтому мы не можем go вернуться назад и добавить стрелку, указывающую вперед, позже: мы делаем коммит, у него есть одна или две стрелки, указывающие назад для его родителей, и с тех пор мы застряли с этим. Дети знают кто их родители, но родители никогда не знают, кто их дети.)

Теперь что у нас есть, давайте добавим еще одно название ветви к этой картинке. Вместо того, чтобы произносить crash как crush, я просто назову это develop:

A--B--C   <-- master, develop

Теперь давайте добавим новый коммит в нашу коллекцию. Мы делаем это, используя обычный процесс Git. Мы назовем новый коммит D, независимо от того, что придет sh ID Git. Новый коммит D укажет на существующий коммит C, потому что мы начнем работать с make D, проверив коммит C. Таким образом, после создания D это будет выглядеть следующим образом:

A--B--C
       \
        D

с D, направленным вверх и влево к C, C, направленным назад к B, и так

Здесь

*1143*

У нас сейчас проблема. У нас есть два имени филиала. Какой должен запомнить новый коммит D?

Чтобы сообщить Git, какой из них, мы добавим специальное имя HEAD во всех заглавных буквах буквы, к одному из двух существующих названий ветвей. Скажем, у нас есть это как договоренность, прежде чем мы сделаем новый коммит D:

A--B--C   <-- master (HEAD), develop

Тогда мы получим это потом:

A--B--C   <-- develop
       \
        D   <-- master (HEAD)

Но если это не то, что мы хотим мы должны git checkout develop в первую очередь. Тогда у нас будет:

A--B--C   <-- master, develop (HEAD)

и когда мы сделаем новый коммит D, мы получим:

A--B--C   <-- master
       \
        D   <-- develop (HEAD)

Мы получим тот же набор коммитов в любом случае. Разница в том, что когда Git делает новый коммит, он записывает ha sh ID из новый коммит для любого имени ветви, к которому присоединено имя HEAD к. Затем это имя ветки автоматически указывает на новый коммит.

Фактически, родительский нового коммита является тем, на которое указывалось имя ветки HEAD, на которое указывал ранее. Это, по определению, коммит , который у нас был. Мы использовали git checkout master или git checkout develop, но в любом случае мы выбрали существующий коммит C.

A detached HEAD происходит, когда HEAD не присоединен к имени ветви

Теперь, когда у нас есть:

A--B--C   <-- master
       \
        D   <-- develop (HEAD)

, мы можем go включить и сделать больше новых коммитов:

A--B--C   <-- master
       \
        D--E--F   <-- develop (HEAD)

например. Но мы могли бы, если захотим, снять нашу ГОЛОВУ. Git имеет режим, в котором мы можем HEAD указать непосредственно для любого существующего коммита. Скажем, например, что по какой-то причине мы хотим, чтобы наша точка HEAD указывала непосредственно на фиксацию E:

A--B--C   <-- master
       \
        D--E   <-- HEAD
            \
             F  <-- develop

Теперь мы можем сделать новый коммит - мы назовем это G - это укажет на существующий коммит E. Git запишет идентификатор нового комита ha sh, каким бы он ни был, в отдельную ГОЛОВУ, давая нам:

A--B--C   <-- master
       \
        D--E--G   <-- HEAD
            \
             F  <-- develop

В этом режиме нет ничего присущего неправильно, но потом все усложняется. Допустим, мы хотим go посмотреть на commit C снова. Мы можем запустить git checkout master. Это добавит имя HEAD к имени master снова:

A--B--C   <-- master (HEAD)
       \
        D--E--G
            \
             F  <-- develop

Как вы найдете коммит G? Мы можем легко найти C: это наш текущий коммит и имена HEAD и master оба найдут его. Мы можем найти B из C, вернувшись назад. Мы не можем найти D из C, но мы можем найти F из имени develop. С F мы можем вернуться к E, а оттуда к D. Но мы не можем шагнуть вперед . Все стрелки Git указывают назад. Больше нет простого способа найти коммит G.

Решение состоит в том, чтобы добавить новое имя ветки до того, как мы переключимся с G. Это то, что вы сделали ранее, когда создали имя detached-head-after-gitlab-crush. Мы можем сделать то же самое по-другому, если мы знаем идентификатор ha sh, равный G (например, если он все еще находится на экране):

git branch save-it <hash-of-G>

добьется цели:

A--B--C   <-- master (HEAD)
       \
        D--E--G   <-- save-it
            \
             F  <-- develop

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

A--B--C--H   <-- master (HEAD)
       \
        D--E--G   <-- save-it
            \
             F  <-- develop

Все, что нам нужно сделать, чтобы вернуться к G, это git checkout save-it, который присоединяет HEAD к имени save-it (которое по-прежнему указывает на G):

A--B--C--H   <-- master
       \
        D--E--G   <-- save-it (HEAD)
            \
             F  <-- develop

Что вам нужно сделать, это выяснить, почему вы продолжаете отключать HEAD

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

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

git checkout --detach master

, например, говорит " Я хочу использовать коммит, обозначенный master, но я хочу сделать это в режиме отсоединенного HEAD ".

Git будет также отсоединять HEAD всякий раз, когда вы просите его проверить (или переключитесь на новую Git 2.23 и более позднюю git switch) фиксацию по необработанному идентификатору ha sh или по любому имени, которое не имя ветви. Сюда входят имена для удаленного отслеживания , такие как origin/master, и имена тегов, такие как v1.2, если вы создали теги.

Некоторые команды, включая, в частности, git rebase, будут временно отсоединить ГОЛОВУ, пока они бегут. Если они не могут fini sh, так что вы находитесь в середине перебазирования, они остановятся и оставят вас в этом отсоединенном режиме HEAD. Затем вы должны выбрать, закончить ли sh перебазирование или полностью завершить его с git rebase --abort. (Если вы не хотите делать ни то, ни другое, вы немного застряли: вам действительно нужно сделать одно из них.)

Итак: выясните, почему вы продолжаете переходить в режим отсоединенного HEAD. Что ты делаешь, что вызывает это? Вы можете создавать новые имена веток для коммитов с git branch, или с git checkout -b (или в Git 2.23 и позже, git switch -c, с c, обозначающим создание), чтобы исправить положение, когда вы находитесь в отсоединенном HEAD режим, или если вам не нужно помнить, где вы сейчас находитесь - если вы намеренно просматриваете исторический коммит, который вы можете, и, вероятно, нашли, например, используя git log - просто используйте git checkout или git switch повторно присоединить вашу ГОЛОВУ к существующему названию ветки. Но за исключением тех особых случаев, когда вы do хотите отсоединить HEAD (чтобы использовать коммит с тегами или посмотреть на исторический коммит), или случаи, когда вы работаете с ребазой, когда вы находитесь в режиме отсоединенного HEAD, пока вы fini sh, вы, вероятно, не хотите, чтобы работал в режиме отсоединенного HEAD. Так что не делай этого!

1 голос
/ 22 января 2020

Исходя из команды git ветви, вы находитесь в отдельном заголовке коммита, и вы создаете только новую ветвь без отдельного коммита.

Чтобы создать ветку из предыдущего коммита, вы есть 3 метода:

  • Вы можете создать ветку через ha sh:

git ответвление ответвления sha1-of-commit

  • Или используя символьную c ссылку:

git ответвление ветви HEAD ~ 5

  • Чтобы оформить ветку при ее создании, используйте

git checkout -b фирменное имя sha1-of-commit или HEAD ~ 3

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