Всегда ли отображается сообщение «Успешно перебазировано и обновлено refs/heads/master»?

Я работал над основной веткой и попробовал это git rebase -i HEAD~3. На самом деле я пытался удалить коммит из истории коммитов, но понял, что в этом нет необходимости.

После открытия редактора nano я не внес никаких изменений в файл и закрыл его без сохранения. Однако в командной строке отображалось сообщение: «Успешно перебазирован и обновлен refs/heads/master». Что это значит? Я не делал (насколько я знаю) никаких изменений. Когда я посмотрел журнал git и статус git, я не увидел никаких изменений.

После этого я сделал пару коммитов и отправил их на пульт.

Мой вопрос: почему было показано сообщение? Что-то изменилось на самом деле?

Я спрашиваю об этом, потому что на самом деле это общий проект, и я собирался совершить серьезную ошибку, перебазировав что-то, и теперь я беспокоюсь, что мог это сделать. Как вы, наверное, можете сказать, я довольно n00b с git :)

Спасибо за помощь!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
3 281
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем конкретном случае ничего не произошло. Перебазирование прошло успешно — и в процессе было выполнено небольшое количество работы — но все, что оно делало, приводило к точно оригинал коммитов. Следовательно, последняя часть, когда написано updated refs/heads/master, означает: Я изменил имя master с обозначения коммита X на обозначение коммита X. (для некоторого хэш-идентификатора Икс). По сути, он стер старую запись и заменил ее абсолютно, полностью, на 100% идентичной записью.

Что здесь происходит (если вам не все равно)

причина для всего этого немного сложнее. По сути, git rebase выполняет коммиты копировать. Проблема здесь в том, что однажды сделанный коммит замораживается во времени: никакая часть любого существующего коммита никогда не может быть изменена. Если мы сделали коммит, который был плохим или даже просто «не очень хорошим», мы могли бы захотеть заменять с новым и улучшенным коммитом: мы могли бы захотеть извлечь оригинал в рабочую область, внести некоторые изменения в рабочую область. области и сделайте новую фиксацию, которая в основном такая же, но немного отличается.

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

При этом каждый коммит также запоминает хэш-идентификатор. Точнее, каждый коммит запоминает ноль или более хэш-идентификаторов, но обычно ровно один. Обычный хэш-идентификатор, который запоминает коммит, — это хэш-идентификатор коммита, который приходит до к этому конкретному коммиту. Git называет это родитель коммита.

Обратите внимание, что когда дочерний коммит «рождается» (создается), Git знает хэш-идентификатор родителя дочернего элемента (или, для коммитов слияния, родителей, во множественном числе). Таким образом, Git может заполнить этот хэш-идентификатор в дочерним элементом во время создания. Но как только ребенок выписан, он замораживается навсегда. Таким образом, когда этот дочерний элемент позже сам становится родителем, к нему не могут быть добавлены его дочерние элементы. Он может только помнить своих родителей.

Но этого достаточно! Если мы нарисуем эту ситуацию, мы обнаружим, что коммиты образуют красивую простую обратную цепочку:

... <-F <-G <-H

Здесь H означает фактический хэш-идентификатор фиксации прошлой. Commit H — самый дочерний; его родитель G; и H запоминает идентификатор G. Commit G запоминает идентификатор F, а F запоминает другого родителя и так далее, вплоть до начала репозитория.

Таким образом, название филиала, такой как master, должен помнить только идентификатор коммита прошлой, в данном случае H:

...--F--G--H   <-- master

Чтобы добавить новый коммит, Git извлекает последний master, то есть H, в рабочую область. Затем мы работаем над этим и готовим новый коммит. Как только все будет готово (с git add и так далее), запускаем git commit. Теперь Git замораживает все, что мы сказали ему сохранить для нового коммита, добавляет фактический хэш-идентификатор H и записывает новый коммит, который получает новый, уникальный, большой уродливый хэш-идентификатор, который мы просто назовем I:

...--F--G--H   <-- master
            \
             I

Шаг прошлой заключается в том, что git commit записывает этот новый хэш-идентификатор в имя master, так что master теперь запоминает фиксацию I вместо фиксации H. Это нормально, потому что коммит I сам помнит коммит H:

...--F--G--H
            \
             I   <-- master

Если мы решим, что провалили коммит I, мы вообще не можем изменятьI, но мы можем копировать на новую и улучшенную замену, возможно, под названием J:

             J
            /
...--F--G--H
            \
             I   <-- master

Если мы сейчас заставим Git сделать так, чтобы имя master запомнило J хэш-идентификатор, это выглядит как мы каким-то волшебным образом изменили I, пока мы не обращаем никакого внимания на хэш-идентификаторы. (Git, напротив, уделяет очень строгий внимание хеш-идентификаторам. Хэш-идентификаторы — это своего рода его кровь: с ними работает почти все внутри Git.)

С некоторыми видами перебазирования мы хотим скопировать серию коммитов, чтобы они попадали в другое место в цепочке:

...--F--G--H   <-- master
      \
       I--J   <-- feature

Здесь, если мы хотим, чтобы наша функция основывалась на фиксации H вместо фиксации F, нам придется повторно скопировать I и J, чтобы они шли после H, и, возможно, также использовать немного другой исходный код, и тогда у нас будет Git сорвите имя feature с J и сделайте так, чтобы оно указывало на новые копии:

             I'-J'  <-- feature
            /
...--F--G--H   <-- master
      \
       I--J   [abandoned]

В других случаях мы просто хотим сделать небольшое исправление. Например, мы начинаем с:

...--F--G--H   <-- master
            \
             I--J   <-- feature

но решаем, что хотим изменить сообщение журнала (reword в git rebase -i). Это сделает новый и улучшенный I' как прежде. Если все, что мы делаем, это reword, что ж, Jбыло в порядке, но родителем J является I, поэтому нам нужен новый и улучшенный J', родителем которого является копия I':

             I'-J'  <-- feature
            /
...--F--G--H   <-- master
            \
             I--J   [abandoned]

Умная часть git rebase заключается в том, что если вы не скажете ему не делать этого, например, используя --force, он заметит случай, когда на самом деле есть никаких изменений для фиксации I, и просто повторно использует исходную фиксацию I. Это происходит, если:

  • нет никаких изменений ни в одном источнике;
  • имя автора, сообщение в журнале и т. д. не меняются; а также
  • нет никаких изменений в родительском хэш-идентификаторе.

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

Затем, как всегда делает Git после завершения операции перебазирования, Git вставляет хэш-идентификатор последнего скопированного коммита в имя ветки, так что это имя записывает последний коммит в ветке. Это была updated часть.


1Из-за опции --forcegit rebase действительно проверяет это. Если вы сказали rebase, что он абсолютно должен заменяет коммиты, он внесет тривиальное изменение — например, обновит дату автора — так, чтобы новый коммит имел новый и другой хэш-идентификатор.

Команда git filter-branch, которая в остальном похожа на git rebase на стероидах — она копирует основные массивы коммитов, внося в них произвольные изменения на основе аргументов фильтра — не выполняет любые такие проверки. Вместо того, чтобы полагаться на тот факт, что если вы сделаете абсолютно, полностью, 100% побитно идентичный коммит, который соответствует какому-то предыдущему существующему коммиту, вы на самом деле получите оригинальный хэш ID обратно и не сохраните новый объект в базе данных. Если бы у git rebase не было --force, он, вероятно, просто сделал бы это, а не проверял. С git filter-branch, если вы хотите принудительно скопировать, вы должны организовать это в одном из ваших фильтров.

Обратите внимание, что требование 100% совпадения означает, что новый коммит должен иметь:

  • то же исходное дерево
  • те же имена авторов и коммиттеров и даты/время
  • одно и то же сообщение журнала, включая точное написание каждого символа (включая пробел) и ту же кодировку (UTF-8 или что-то еще)
  • те же идентификаторы хэшей родитель, т. е. та же история, ведущая к этой фиксации

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

Другие вопросы по теме