Ваш чертеж вводит вас в заблуждение.
Запомните следующее:
- "Истинное имя" коммита - это его идентификатор хеша.
- Каждый коммит хранит хэшИдентификатор его родительского коммита или для коммита слияния всех его родителей.
- Никакой коммит нельзя изменить вообще, но коммиты можно скопировать в новые замены.
Если это помогает, думайте о коммитах как о больших, прочных вещах: например, кирпичах и балках, составляющих здание.(Как и кирпичи Lego негабаритного размера, каждый кирпич имеет некоторый соединитель (и) с каким-то другим кирпичом, и мы соединяем наши кирпичи вместе для создания цепочек. Эти соединения проходят через хэш-идентификаторы: они выходят из дочернего коммита и указывают на родительский.)
Ветвь Имена , с другой стороны, являются очень легкими предметами.Они как липкие заметки, которые вы надеваете на коммит, затем снимаете с себя и затем надеваете на другой коммит.
Так что, если у вас есть это:
A <-B <-C <-E <-F <-- integration
\
G <-H <-I <-- feature
, вы не можете получить свой второйизображение, потому что существующий коммит G
записывает A
хэш-идентификатор.Вы не можете иметь G
, у которого F
в качестве родителя.Вы также не должны не рисовать коммит дважды, если это вообще возможно: коммиты уникальны, есть только один коммит G
.
git cherry-pick
является строительным блоком для копирование коммитов
Часто мы попадаем в ситуацию, в которой у нас есть коммит, например G
, который в порядке, но нам бы хотелось, чтобы он был больше, если бы он был немного другим.Нам нужна новая копия, которая похожа на G
, но имеет F
в качестве родителя и имеет снимок дерева исходного кода, отличный от исходного G
.Давайте назовем новый коммит G'
, чтобы отличить его от G
, но напомним, что он очень много , как G
.Мы хотим, чтобы разница между F
и G'
была такой же, как разница между A
и G
, таким образом учитывая любые изменения, необходимые из-за коммитов B-C-E-F
тоже.Итак, нам нужен граф коммитов, который выглядит следующим образом:
G' <-- new-and-improved-feature
/
A--B--C--E--F <-- integration
\
G--H--I <-- feature
Если мы затем скопируем коммит H
в новый и улучшенный H'
и скопируем I
к новым и улучшенным I'
мы получаем это:
G'-H'-I' <-- new-and-improved-feature
/
A--B--C--E--F <-- integration
\
G--H--I <-- feature
git reset
перемещает метки
Что делает git reset
- ну, один из несколькихвсе, что он может сделать, но это то, что мы делаем с ним сейчас, - это переместить липкие метки с названиями ветвей.
Есть одна липкая метка, на которой мы написали слово feature
.Эта наклейка прикреплена для фиксации I
прямо сейчас.Но мы только что использовали git cherry-pick
три раза, чтобы скопировать последовательность G-H-I
в последовательность G'-H'-I'
, в нашей новой и улучшенной установке.
Если у нас теперь есть Git, то очиститепометить feature
off commit I
и вместо этого вставить его в commit I'
, мы получим следующее:
G'-H'-I' <-- feature (HEAD), new-and-improved-feature
/
A--B--C--E--F <-- integration
\
G--H--I <-- ORIG_HEAD
Чтобы это произошло, мы запускаем: git checkout feature; git reset new-and-improved-feature
.
Команда git reset
устанавливает это специальное имя ORIG_HEAD
, чтобы помнить, куда feature
имел обыкновение идти.Теперь метка feature
прикреплена к коммиту I'
, но есть способы найти I
, включая этот трюк ORIG_HEAD
.
(нам больше не нужна метка «новая и улучшенная функция»)поэтому мы можем удалить его сейчас.)
Обратите внимание, что фиксация не изменилась .Оригинал G
все еще находится в хранилище.Запустив git log ORIG_HEAD
, мы все еще можем увидеть его, по крайней мере, пока не выполним другую команду Git, которая использует ORIG_HEAD
для запоминания какого-либо другого коммита.Мы увидим I
, затем H
, затем G
.Мы также можем использовать reflog для feature
, чтобы найти идентификатор хеша для коммитов G
, H
и I
.Пока у нас есть хэш-идентификатор или имя для хэш-идентификатора, мы можем найти коммит.(Срок действия этих записей reflog истекает - у них есть отметка даты, и через месяц или три Git удаляет запись reflog.)
Если мы используем имя feature
, мы найдем новые копии вместо оригинальных коммитов. Из-за этого кажется, что коммиты изменились, пока мы не уделяем пристального внимания и не замечаем, что на самом деле это new коммиты.
Суть в следующем: После того, как мы скопируем коммиты , если мы используем git reset
, чтобы отказаться от оригиналов в пользу новых и улучшенных копий, мы увидим только новые и-улучшенные копии, и мы можем вести себя как коммиты изменились. Коммиты не изменились, и если кто-то действительно присмотрится, они раскроют наш секрет, но если кто-то еще никогда не знал об оригиналах , он не может обнаружить, что это дешевые подделки улучшенные копии.
git rebase
= вишня плюс сброс
Это подводит нас к выводу: git rebase
по существу git cherry-pick
некоторого набора коммитов , за которым следует git reset
. То есть мы начинаем с копирования коммитов в новые и - мы надеемся - улучшенные версии; затем мы используем git reset
, чтобы попытаться заставить всех использовать улучшенные коммиты вместо оригиналов.
Любой, у кого еще есть оригиналы, не будет одурачен! Если кто-то еще - какой-то другой репозиторий Git - все еще имеет оригинальные коммиты, мы должны убедить них перейти на новый улучшенные коммиты тоже. Но если мы единственные, кто имеет доступ к коммитам, нам нужно только обмануть себя, что, вероятно, проще.