Имеет ли значение ветвь, в которой я использую 'git log', если я использую те же хеши фиксации? - PullRequest
0 голосов
/ 01 мая 2018

Вот! У меня есть следующая структура Git:

A-...-C-D-E      (develop branch)
         \
          X-Y    (feature1 branch)

Где A, B, C, D и E - коммиты в ветви разработки, а X и Y - коммиты в ветви с именем feature1. Коммиты A и C разделены неизвестным количеством коммитов. Давайте также скажем, что коммит А имеет (частичный) хеш коммита b0a710ad5, а коммит Y имеет (частичный) хеш коммита 0fc0d3.

Теперь есть два интересных сценария. Тот, где я оформить заказ и запустить

git log --oneline b0a710ad5..0fc0d3

И второй сценарий, где я вместо этого извлекаю feature1 и выполняю ту же команду:

git log --oneline b0a710ad5..0fc0d3

Если бы мне пришлось угадывать, что возвращали эти сценарии, я бы сказал, что первый вызовет ошибку, поскольку коммит Y не существует в ветви разработки. И я предполагаю, что второй сценарий даст мне законный журнал Git. Тем не менее, я был совершенно ошибочным. Кажется, неважно, в какой ветке я был: обе команды дали мне одинаковые логи. Похоже, что git log может видеть коммиты из других веток, что я никогда не предполагал .

Может ли git log найти коммит в любой ветке в локальном репозитории? Он ищет и находит коммиты удаленно, если не может найти его в каких-либо локальных ветвях? Разве не имеет значения, в какой ветке я работаю, когда запускаю git log .. с хэшами коммитов? Ох, возможности.

1 Ответ

0 голосов
/ 01 мая 2018

Как отмечают спектры в комментарии , хеши действительны везде.

В большинстве случаев Git просто использует имя для поиска хэша. Таким образом, имя ветви, такое как develop или feature1, просто читаемое человеком, и, что важно, изменяемое - имя для какого-то конкретного хеш-идентификатора. Это хеш-идентификатор - это в основном то, что заботит Git. Команда, подобная git log, преобразует имя в хэш-идентификатор и начинает работать с коммитом. Сам коммит содержит еще один хеш-идентификатор для родительского коммита, и git log будет проверять этого коммита, который имеет еще один хэш-идентификатор и т. Д.

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

... <-grandparent <-parent <-0fc0d3   <--branchname

и это по сути то, что делает Git.

При использовании операции с диапазоном, такой как b0a710ad5..0fc0d3, Git идет прямо к хэш-идентификатору: 0fc0d3 является положительной ссылкой , поэтому Git находит этот коммит. Из-за двух точек .. между ними первый хэш-идентификатор b0a710ad5 синтаксически эквивалентен ^b0a710ad5: это отрицательная ссылка . Git также находит этот коммит, но использует его для подавления , показывающего некоторые коммиты. Если b0a710ad5 находится прямо в цепочке, Git останавливается при достижении b0a710ad5. Если b0a710ad5 не в цепочке - например, если цепочки коммитов выглядят примерно так:

    b0a710ad5  ...   <--somename
        /
great-...-grandparent <-... <-parent <-0fc0d3   <--branchname

затем b0a710ad5 подавляет great- n th-grandparent , который Git находит, идя назад от b0a710ad5.

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

Имена иногда делают имеют значение

Обратите внимание, что когда вы делаете новый коммит, вы обычно делаете это, находясь "на" некоторой ветви. Наличие на ветке означает, что Git присоединяет имя HEAD к этой ветке, так что если мы рисуем наши коммиты с именами веток справа, указывая на tip (большинство недавние) коммиты, к одному из этих имен прикреплено HEAD:

...--F--G--H   <-- develop
         \
          I--J   <-- feature1 (HEAD)

(Одиночные заглавные буквы здесь обозначают фактические хеш-идентификаторы, которые слишком громоздки, чтобы их беспокоить.)

Если мы делаем новый коммит сейчас, Git устанавливает новый коммит в хэш-идентификатор текущего коммита J, а затем записывает хэш-идентификатор нового коммита в имя feature1. Это то, что HEAD присоединено к feature1, а feature1 в настоящее время имена передают J, вот как все это работает. Git делает новый коммит K:

...--F--G--H   <-- develop
         \
          I--J   <-- feature1 (HEAD)
              \
               K   [make new commit: parent is HEAD]

затем записывает K в feature1, чтобы получить:

...--F--G--H   <-- develop
         \
          I--J
              \
               K   <-- feature1 (HEAD)

который мы можем перерисовать на меньшее количество строк:

...--F--G--H   <-- develop
         \
          I--J--K   <-- feature1 (HEAD)

Обратите внимание, что HEAD остается подключенным к feature1 на протяжении всей операции; меняется feature1, чтобы сохранить новый хэш-идентификатор.

(Когда вы используете git push, вы также используете эти имена, чтобы идентифицировать коммиты, которые вы хотите отправить в какой-либо другой Git-репозиторий. Вы просите их установить их имена на основе вашего names. Когда вы используете git fetch, некоторые other Git имеют имена, которые указывают на коммиты, имеющие хэш-идентификаторы, а ваш Git копирует commits - который сохраняет тот же хеш ID - но затем записывает новые origin/* имена в ваш репозиторий, чтобы запоминать их имена, не вступая в конфликт с именами ваших ветвей. Таким образом, имена имеют значение и здесь - но хеш-идентификаторы имеют значение, по крайней мере, так же, как и «настоящие имена» фактических коммитов.)

...