Git Интерактивный ребаз сквош в следующий коммит
В Git я могу использовать интерактивную перебазировку для перезаписи истории, это здорово, потому что в моей функциональной ветке я сделал кучу коммитов с частично работающим кодом, когда я исследовал различные рефакторинги и способы сделать это.
Я хотел бы объединить много коммитов вместе перед тем, как перебазировать или объединить ветку с мастером.
Некоторые составляют коммиты в порядке от первого (сверху) до низа (последнего)
1. Initial commit on feature branch "Automatic coffee maker UI"
2. Add hot chocolate as product
3. Add tea as product. Products are now generic
4. Create in memory data store for adapter tests
5. Cry because I can't get entity framework to create a composite key. Integration tests broken.
6. Implemented composite key!!
7. All tests green and feature done!
Допустим, я хочу сохранить коммиты 3, 4 и 7.
Используя rebase, я хочу "раздавить" коммиты
- 1 и 2 входят в 3.
- 4 пребывания
- 5 и 6 входят в 7
В идеале в интерактивном ребазе я бы сделал
1. squash
2. squash
3. pick (contains the work of 1 & 2)
4. pick
5. squash
6. squash
7. pick (contains the work of 5 & 6)
Но это наоборот, потому что сквош объединяет коммит с предыдущим коммитом. Я не могу понять, как заставить его сдавить вперед.
Мне трудно, и должен ли я принять, что это не сработает (я бы предпочел, чтобы это работало), или есть способ сделать это?
Я вызываю эту команду с
git checkout My-feature-branch
git rebase master -i
Затем я редактирую список коммитов и пытаюсь завершить его, сохранив файл и отредактировав редактор, который обычно работает для меня.
6 ответов
Вам также необходимо изменить порядок коммитов, чтобы коммит, который должен быть сохранен, предшествовал коммитам, которые нужно сохранить, если это возможно.
Если это невозможно, потому что вы получите конфликты, которые не хотите разрешать, просто сделайте это
1. pick
2. squash
3. squash
4. pick
5. pick
6. squash
7. squash
Когда сквош завершен, вы можете отредактировать сообщение о коммите, чтобы оно содержало сообщение, которое вы хотели бы получить в финальных коммитах. Проще простого.:-)
Вы могли бы даже быть в состоянии сделать
1. pick
2. fixup
3. squash
4. pick
5. pick
6. fixup
7. squash
Тогда я думаю, что должен быть запущен только один раз редактор сообщений фиксации, так как при исправлении предыдущее сообщение фиксации просто берется без запуска редактора.
На сквоше, когда запускается редактор сообщений о коммитах, вы также получаете оба коммит-сообщения, одно из коммитов, которые должны быть сдавлены, и коммитов, которые вы хотите сдавить, так что вы можете просто удалить сообщение о коммите, которое вам не нужно хранить.
Действительно, во время интерактивной перебазировки можно втиснуть фиксацию в следующую фиксацию и полностью сохранить идентичность второй из этих фиксаций (включая автора, дату и т. Д.).
Однако этот метод несколько сложен, поэтому встроенная поддержка
git rebase -i
тем не менее будет оценен по достоинству.
Я продемонстрирую всего три коммита
aaaaaaa A
,
bbbbbbb B
а также
ccccccc C
, где мы хотим свернуть и сохранить идентичность: (метод легко обобщается на большее количество коммитов)
-
git rebase -i aaaaaaa^
- Измените скрипт редактирования, чтобы он остановился после фиксации и выйдите из редактора:
pick aaaaaaa A edit bbbbbbb B pick ccccccc C
- Когда перебазирование будет остановлено, дважды верните последнюю фиксацию , а затем продолжите:
git revert HEAD git revert HEAD git rebase --continue
и могут быть объединены вместе, чтобы сформировать фиксацию без операции, несущую идентичность фиксации B вперед с отдельнымrebase -i --keep-empty aaaaaaa^
. Это очень полезно и рекомендуется для предотвращения ложных конфликтов слияния, особенно в более сложных случаях. Однако мы пропустим этот шаг и просто сохраним коммиты вместе.
Важная фиксация сейчасRevert "Revert "B""
который будет содержать все изменения, изначально внесенные. - Сейчас
rebase -i aaaaaaa^
снова пройти мимо обоих и, прижимаясь к обоим иA
:pick bbbbbbb B squash b111111 Revert "B" squash a222222 A squash b333333 Revert "Revert "B"" pick c444444 C
B
а такжеRevert "B"
не имеет никакого эффекта, вы можете переместить любые коммиты за его пределы, создавая только тривиально разрешимые конфликты слияния. - Когда перебазирование останавливается из-за конфликта слияния, используйте
git mergetool
с помощью инструмента, который может автоматически разрешать тривиальные конфликты и позволять инструментам делать именно это. - Rebase снова остановится, чтобы вы могли отредактировать сообщение фиксации сжатой фиксации. Отредактируйте на свой вкус.
-
git rebase --continue
и все готово.
Ответ вампира правильный, но я хочу предложить другую точку зрения. Я думаю, что это то, где вы получаете больше, чем нужно: вы начинаете с:
Допустим, я хочу сохранить коммиты 3, 4 и 7.
но затем добавьте:
- 1 и 2 входят в 3.
- 4 пребывания
- 5 и 6 входят в 7
Но это означает, что вы хотите сохранить (содержимое) всех 1, 2, 3, 4, 5, 6 и 7 ... только не как отдельные коммиты. Интерактивный ребаз squash
не означает "выбросить" и даже "выбросить сообщение о коммите", оно просто означает "объединить". Возможно, было бы лучше, если бы глагол был "объединить" или "смешать" или "смешать" или что-то подобное. Таким образом, последовательность (выбор, сквош, сквош) означает: оставьте все три, применяя их в таком порядке, а затем сделайте из них один большой коммит.
Как уже отмечалось, когда Git делает один большой коммит из них, Git дает вам еще один шанс отредактировать три комбинированных сообщения коммита в одно большое сообщение коммита.
Когда перебазирование закончено, вы не сохранили ни одного из оригинальных коммитов. Вместо этого вы сделали новые коммиты. Неважно, как именно ваш первый коммит был собран из частей, только то, каким был конечный источник, и что вы поместили в одно большое сообщение коммита.
Мой способ сделать это - это просто
reset
плюс
commit -C
.
git rebase -i origin/main # or some other commit
Что вызывает ваш редактор, который я делаю следующим образом:
...
pick aafaa Merge me forward
edit bbfbb Into me
...
Затем, когда перебазирование останавливается на
bbfbb
, делать
git reset --soft HEAD^
git commit --amend -C HEAD@{1} # could put an explicit commit here
git rebase --continue
его также можно поместить в единый список задач перебазирования:
...
pick aafaa Squash me forward
pick bbfbb Into me
exec git reset --soft HEAD^ && git commit --amend -C HEAD@{1}
...
Чтобы улучшить ответ golvok , если вы хотите «пересылать» несколько коммитов, вы можете сделать следующее:
(необязательно) Если вы изменили и впоследствии не отследили файл в неотправленных коммитах, обязательно сначала спрячьте или очистите неотслеживаемые файлы.
Запустите ребаз:
git rebase -i origin/destination_branch
Отметить с
fixup
все коммиты между первым и последним, которые вы хотите раздавить, и поместите нижеexec
команда после целевой фиксации:pick a52ff17 Feature A added pick b69a7d9 Feature B WIP fixup da37b5a Feature B WIP fixup 009557e Feature B WIP pick 4857cdd Feature B added exec git reset --soft HEAD^ && git commit --amend -C HEAD@{1} pick 15ffacb Feature C added
Ну вот, полегче.
Вы хотите:
1. pick
2. squash
3. fixup
4. pick
5. squash
6. squash
7. fixup
Затем, когда в редакторе появятся новые комбинированные коммиты, удалите строки для выбранных коммитов и оставьте исправления. Таким образом, итоговые исправления функций должны содержать сообщение о фиксации последней фиксации в серии.