Существует около трех (или десяти или сотен, в зависимости от того, как вы хотите считать) различных способов сделать это в Git, но, вероятно, самый простой для вашего конкретного случая - это использовать git merge --squash
.
Боковая панель: git merge
часто выполняет коммиты слияния. git merge --squash
никогда совершает коммиты слияния. Это делает git merge --squash
вводящей в заблуждение командой. Git использует слияние machinery , чтобы получить результат, но заставляет вас запускать git commit
вручную в конце, и в этот момент вы можете предоставить совершенно новое сообщение фиксации.
Давайте проиллюстрируем, как именно это работает. Помните, что Git на самом деле все о коммитах - тех сущностях с большими уродливыми хэш-идентификаторами - и его совсем не волнует имена ветвей , такие как master
иfeature/my-feature-name
. Имя действительно содержит только один идентификатор хеша коммита. Каждый коммит содержит другой хеш-идентификатор, 1 его непосредственного родительского коммита, так что коммиты могут быть обработаны, начиная с конца и работая в обратном направлении.
Реальный хешИдентификаторы выглядят случайными и непредсказуемыми. Мы будем использовать одиночные заглавные буквы, такие как H
, чтобы заменить настоящие хеш-идентификаторы, и будем распределять их последовательно, чтобы было легко увидеть, какой коммит мы сделали, когда. Конечно, это сильно ограничит количество коммитов, которые мы можем сделать (что является , почему Git использует такие большие уродливые хэш-идентификаторы). Мы начнем с самого первого коммита:
A <-- master
, у которого нет родителя, потому что ранее не было коммита. Имя master
указывает на этот коммит (имя master
содержит его фактический хэш-идентификатор).
Теперь мы делаем второй коммит. Новый коммит указывает на первый коммит, и Git обновляет имя master
, чтобы оно указывало на второй коммит:
A <-B <-- master
Мы делаем третий, четвертый и т. Д. Коммит и получаемцепочка:
... <-F <-G <-H <-- master
Имя всегда указывает (содержит хэш-идентификатор) на последний коммит в цепочке. Вот и все, что на самом деле представляет собой ветвь в Git: имя, содержащее идентификатор хеша last commit. Каждый коммит содержит хеш-идентификатор коммита на один шаг назад, и именно так Git-репозиторий хранит history .
Давайте немного ленився и перестанем рисовать внутренние стрелки какстрелки. Это не совсем лень, потому что теперь я хочу начать рисовать имя второй ветви. Мы сделаем новое имя, feature/tall
:
...--F--G--H <-- feature/tall (HEAD), master
Обратите внимание, что оба имени указывают на тот же коммит . Все коммиты, которые находятся в ветке master
, находятся в нашей новой ветке, feature/tall
. Мы также добавляем слово HEAD
в скобках, прикрепленное к одному из этих имен, чтобы мы могли помнить, на какой ветке мы находимся.
Теперь мы делаем новые коммиты, некоторые из которых имеют глупые лайки, такие какwip
или my hands are typing words
:
...--F--G--H <-- master
\
I--J--K--L--M--N <-- feature/tall (HEAD)
Мы достигли точки, когда вы хотите получить один единственный коммит, который вы хотите пометить feature/tall-CLEAN
. Итак, сначала нам нужно найти хеш-идентификатор commit H
. Если master
по-прежнему указывает на H
, это простой способ найти его. 2 При условии, что это так, вы можете просто сделать:
git checkout -b feature/tall-CLEAN master
, что дает вам следующее:
...--F--G--H <-- feature/tall-CLEAN (HEAD), master
\
I--J--K--L--M--N <-- feature/tall
Теперь вы можете запустить:
git merge --squash feature/tall
Сравнивает коммит H
- коммит, который вы получили прямо сейчас - с коммитом N
, чтобы увидеть, что изменилось. Затем те же самые изменения применяются к коммиту H
, чтобы подготовиться к созданию нового коммита O
.
Чтобы действительно сделать O
, вы должны выполнить git commit
. Это делает O
и перемещает имя feature/tall-CLEAN
, чтобы указать на новый коммит:
O <-- feature/tall-CLEAN (HEAD)
/
...--F--G--H <-- master
\
I--J--K--L--M--N <-- feature/tall
, и вы получите именно то, что хотели.
1 На самом деле, каждый коммит имеет список таких хеш-идентификаторов. Большинство коммитов имеют только одну запись в списке. В коммите слияния есть две или более записей, а самый первый коммит, который вы (или кто-либо другой) делает в новом, пустом репозитории, имеет пустой список - без родительских коммитов - потому что там есть более ранний коммит.
2 Если master
больше не указывает на H
, вам нужно найти коммит H
. Один из способов - запустить git log --graph --oneline --decorate master feature/tall
и проверить вывод. Затем вы можете вырезать и вставить его сокращенный идентификатор хеша. Другой способ - использовать git merge-base --all master feature/tall
, который должен распечатать хэш-идентификатор H
, который вы снова можете вырезать и вставить.