Некоторые коммиты git отсутствуют после создания ветки git из идентификатора коммита - PullRequest
0 голосов
/ 15 ноября 2018

Я создаю ветку git из идентификатора коммита. Я ожидаю, что он должен показывать идентификаторы коммитов после указанного идентификатора коммита при создании новой ветки.Но почему-то в недавно созданной ветке git отсутствует несколько коммитов git.

У меня есть основная ветка с несколькими коммитами id:

Main Branch commit ids

Я создалновая ветвь из основной ветки, использующая команду git checkout -b testBranch 3331a4b

Но когда команда fire git log --oneline на этой ветке, я вижу, что некоторые идентификаторы коммитов отсутствуют.Перейдите по ссылкам ниже, чтобы проверить идентификатор фиксации

идентификаторы фиксации testBranch: testBranch commit ids

Отсутствующие идентификаторы коммитов основной ветви: Missing commit ids of main branch

1 Ответ

0 голосов
/ 15 ноября 2018

Примечание: снимки экрана, как правило, являются плохой идеей, поскольку они затрудняют поиск и цитирование.

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

010 final
009 earlier
008 earlier-still
007 ...
...
001 first

, что, начиная с 010 и считая в обратном направлении, даст вам 10 коммитов, а начиная с 009 и считая в обратном направлении, даст вам 9 коммитов.

Это было бы верно, если бы коммиты были линейными, но это не так.

Фактические числа, конечно, не последовательные и не десятичные - это хеш-идентификаторы, например3331a4b (что уже означает что-то гораздо более длинное, чем просто начинается с 3331a4b).Итак, вы уже знаете, что вы не можете просто использовать число в качестве простого индекса.Заменим последовательные числа (от 001 до 010) или хэш-идентификаторы (3331a4b и т. Д.) На заглавные буквы A B ... H, а на самом деле нарисуем коммиты, сделанные внебольшой репозиторий с десятью коммитами, с последним коммитом является слияние коммит:

A  <-B  <-C  <-D  <-----H
           \           /
            E  <-F  <-G

Эти стрелки - те, которые идут от E, указывающие на C и H, указывающие на G, не имеют наконечника стрелки (потому что слишком сложно рисовать в тексте), но эти соединители также являются стрелками - позволяют Git работать в обратном направлении от последнего коммита к первому.

Фактически, каждый коммит Git содержит некоторый набор родительского коммита хеш-идентификаторов.Мы говорим, что коммит указывает на его родителя (со стрелками, как показано выше).Большинство коммитов имеют ровно одного родителя, и эти коммиты образуют простую, обратную, линейную цепочку, например, идущую от C обратно к A.Здесь все хорошо: когда вы начинаете с C, есть только один путь назад к A.

Как минимум один коммит, самый первый из когда-либо сделанных,имеет нет родительского хэша, потому что это был первый сделанный коммит, и более ранний коммит для него не был указан.Это где действие останавливается.Обратите внимание, что действие начинается с end и работает в обратном направлении.

Некоторые коммиты, такие как commit H в приведенном выше примере, имеют двух родителей.Здесь все становится сложнее, потому что Git может идти назад от H до или G, или D.(Вы, возможно, уже видите, куда это идет.) Команда git log использует определенный метод для линеаризации своего обратного хода, к которому мы вскоре перейдем.

A имя ветви как master или develop фактически указывает на коммит - один конкретный коммит - такой как коммит H, поэтому мы можем нарисовать эти вещи немного проще, например, и затем добавить веткуимена в вправо , в конце:

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

, зная, что внутренние ссылки между коммитами являются стрелками назад.(Чтобы не требовать когда-либо изменения коммита, сами стрелки встроены в children , указывающие назад на их родительские коммиты - ничто внутри коммита не может двигаться или изменяться; всеСодержание коммита фиксируется на всю вечность. Дети знают, кто их родители, когда дети рождаются, но пока дети не родятся, родители не могут знать, кем будут их дети, поэтому родители не могут указывать детям вперед.)

Хитрость в том, что имена , такие как master или develop, do , перемещаются: имя master получено здесь посредствомкоманда git merge, возможно, запускается через git pull, или, возможно, запускается напрямую кем-либо, или с помощью кнопки GitHub «merge pull request», или аналогичной.Раньше чертеж выглядел так:

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

CommitH еще не существовало, и, начиная с master и работая в обратном направлении, git log будет перечислять коммиты D, затем C, затем B, затем A;начиная с develop и работая в обратном направлении, git log будет перечислять коммиты G, затем F, затем E, затем C, затем B, затем A.

В этот момент кто-то запустил git checkout master; git merge develop или сделал что-то эквивалентное.Этот создал новый коммит H, указывая на G и D и предоставив нам наш обновленный чертеж.

Теперь предположим, что вы прикрепляете новое имя ветви для фиксации F или E.Если вы просматривали вывод git log на основе master и предполагали, что коммит D предшествует коммиту E, вы можете ожидать, что коммиты начинаются с F или E и работают в обратном направлении черези в том числе D.Но как только мы нарисуем график коммитов и прикрепим метку к F или E, вы увидите, что нам следует не ожидать коммита D дляпоказать:

A--B--C--D------H   <-- master
       \       /
        E--F--G   <-- develop
            .
             .....<-- testBranch

Тот факт, что D достижим с H (master, на данный момент) не означает, что D будет достижим с testBranch.

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

Как git log линеаризует нелинейный граф

Так как git log должен показывать один коммит за раз -по одному на строку с --oneline или с использованием более одной выходной строки без него - требуется очередь в ожидании коммитов .Эта очередь обычно начинается только с одного коммита, который вы называете:

$ git log <hash>

или:

$ git log <branchname>

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

Git затем принимает тот коммит, который находится на фронте очереди ипоказывает что коммит.Этот коммит имеет некоторых родителей;если родитель (ы) еще не были показаны и еще не находятся в очереди, Git помещает их в очередь.

Порядок, в котором отображаются коммиты, зависит от того, куда они попадают в очередь.Когда очередь пуста - как это часто бывает - и есть только один родитель, этот единственный родитель становится единственной записью в очереди и сразу же отображается, удаляя ее из очереди, чтобы очередь снова была пустой.Вот как простая линейная цепочка проявляется как простая линейная цепочка: мы можем поместить коммит G в очередь, затем вынуть его обратно и показать, а F поставить в очередь, затем вывести обратно и показатьэто и помещает E в очередь и т. д.

Если вы запускаете git log с более чем одним коммитом:

$ git log master develop

(при условииимена master и develop указывают на два разных коммита - возможно иметь два имени ветви, указывающих на один и тот же коммит), очередь начнется с более чем одним коммитом, так что еще раз, порядок коммитов в очереди будет иметь значение.Git сначала покажет фиксацию в начале очереди, будь то имя с именем master или имя с именем develop.Показав этот коммит, Git вставит своих родителей в очередь, если это уместно, и только тогда у них будет возможность, в зависимости от того, где сейчас находится другой коммит в очереди, показать other commit васnamed в командной строке.

По умолчанию для порядка вставки очереди используется отметка времени коммита , причем более новая (более поздняя отметка времени) фиксация идет в начало очереди.Вы можете в некоторой степени контролировать этот порядок с помощью --date-order, --author-date-order, --topo-order и --reverse.Используя --graph силы --topo-order.Подробнее см. документацию git log .

...