Как сквошировать коммиты, между которыми есть слияние-коммит?

Я работаю над функциональной веткой.

  1. Сделал несколько коммитов. Squashed коммиты.
  2. Отправил изменения в удаленную ветку. Есть конфликты.
  3. Merged changes from master, resolved conflicts on feature branch.
    • git fetch origin master
    • git merge FETCH_HEAD
    • Решал конфликты вручную.
    • git commit
    • git push
  4. Я сделал еще одно коммит.

Итак, текущая история коммитов выглядит так. От текущего к старому:

  1. совершить 3
  2. commit M ггг (объединено)
  3. совершить 2

Как мне сжать более 3 коммитов в 1, прежде чем я объединю свою функциональную ветку в master?


person Tyr1on    schedule 09.05.2015    source источник
comment
Просто запустите две команды git merge master git squash master   -  person Happy Patel    schedule 11.05.2021


Ответы (4)


Вы можете rebase -i начать с commit 2 родителя (то есть фиксации на master, от которой вы разветвились. Вероятно, вам придется повторно разрешать конфликты, когда вы перейдете к фиксации слияния.

Итак, если ваша история выглядит как

  * D commit 3 (HEAD)
  * M merge
 /|
| * C commit 2
* | B commit on master
|/
* A (master)

Начните с git rebase -i A. Вы увидите список коммитов, включая master и your_branch, но не коммит слияния. pick первый (B или C, в зависимости от времени) и squash остальные.

person Kristján    schedule 09.05.2015
comment
Это сработало. Но можете ли вы указать мне на теорию, почему это сработало? - person Tyr1on; 10.05.2015
comment
Обязательно прочтите эту статью и прокомментируйте еще раз, если у вас есть некоторые конкретные вопросы. - person Kristján; 10.05.2015
comment
Посмотрев еще раз (и поиграв с игрушечным репо), похоже, что git rebase -i master тоже должен был работать нормально, и он не включил бы master коммит в ваш squash. Это то, что вы пробовали раньше? Что пошло не так? - person Kristján; 10.05.2015
comment
Еще одна вещь - смешивание слияний и перебазов, как правило, хороший способ запутаться в вашем дереве Git. Я бы рекомендовал придерживаться только одного или другого, и, поскольку вы хотите раздавить, это означает, что нужно избегать слияния в пользу перебазирования. В этом случае у вас будет git rebase masterd вместо git merge master, который поднимет каждую фиксацию ветки вверх, как если бы вы начали с commit 2. Затем, когда вы, наконец, раздавите, не будет слияния, которое запутает вас. Однако, если вы передали ветку другим людям, rebase требует принудительного толчка и прерывает их историю, так что приходится идти на компромисс. - person Kristján; 10.05.2015
comment
Спасибо за помощь. Я бы рассмотрел git rebase вместо слияния в будущем. - person Tyr1on; 12.05.2015
comment
Произошел еще один способ, который может вас заинтересовать: git rebase --preserve-merges origin/master из stackoverflow .com / questions / 4783599 / rebasing-a-git-merge-commit. - person Kristján; 12.05.2015
comment
отличное объяснение - person jimh; 04.04.2020

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

https://github.com/sheerun/git-squash

Необходимо только слить основную ветку, а затем запустить команду сжатия:

git merge master
git squash master
person sheerun    schedule 01.06.2020
comment
Это победитель в моих книгах. Однако было бы неплохо, если бы вы также могли включить здесь выполняемые вами команды / процедуры и объяснить, что они делают. Это действительно довольно просто, если посмотреть на код, но было бы неплохо иметь его прямо здесь :) - person fgblomqvist; 05.01.2021
comment
отличный инструмент, спасибо! - person Atais; 26.03.2021
comment
было бы неплохо, если бы он был встроен в git - person Gzorg; 15.04.2021

В моем случае я начал работать с веткой, в которой было несколько коммитов, затем слияние с основной / исходной ветвью, затем еще несколько коммитов, и я хотел раздавить все коммиты, но продолжал сталкиваться с ошибкой из-за фиксации слияния:

ошибка: фиксация - это слияние, но опция -m не указана.

-> C1-> C2-> M (объединить с исходной веткой) -> C3-> C4

Вероятно, есть способ получше (и я с нетерпением жду возможности научиться), но после долгого чтения и проб и ошибок я создал копию ветки для справки, а затем вернул текущую ветку к C1,

reset --hard (хэш C1)

затем выбор вишни C2, C3, C4, затем сжатие, затем перемещение ... в результате:

M->C

(только одна фиксация, которая была перебазирована с исходным кодом!)

Надеюсь, это поможет кому-то еще с той же проблемой.

person user6096790    schedule 05.09.2019

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

Учитывая работу основной ветки и ветки, выполните следующие действия:

git checkout -b work-squashed `git merge-base main work`

Это создает новую ветку из последнего основного коммита, который вы слили с рабочей веткой.

git diff work-squashed...work | patch -p1

Это захватывает и применяет к рабочему каталогу все изменения между последней фиксацией на main, которая была объединена с работой, и вершиной рабочей ветви. Другими словами, вся работа, в том числе и разрешенные конфликты.

На этом этапе вам нужно позаботиться о файлах, добавленных / удаленных в рабочей ветке, потому что patch - это не git. Он не знает, какие файлы отслеживаются git. Итак, вам нужно git add / git rm, пока все файлы не будут учтены. Затем вы просто фиксируете изменения как одну фиксацию.

person Gabriel Schulhof    schedule 11.04.2021