Как использовать git merge --squash?


1211

У меня есть удаленный сервер Git, вот сценарий, который я хочу выполнить:

  • Для каждой ошибки / функции я создаю отдельную ветку Git

  • Я продолжаю фиксировать свой код в этой ветке Git с неофициальными сообщениями Git

  • В верхнем репозитории мы должны сделать один коммит для одной ошибки с официальным сообщением Git

Итак, как я могу объединить свою ветку с удаленной веткой, чтобы они получили только один коммит для всех моих проверок (я даже хочу предоставить сообщение о коммите для этого)?


1
Я не уверен, что полностью вас понял, но вы можете захотеть "слияния осьминогов".
MatrixFrog

27
Обычно я использую git rebase -i, чтобы свести все мои коммиты в один коммит и переписать сообщение коммита. Тогда я отправляю это вверх по течению.
Эдвард Фальк

17
git merge --squashделает все это в командной строке одним выстрелом, и вы просто надеетесь, что это сработает. git rebase -iвызывает редактор и позволяет точно настроить ребаз. Это медленнее, но вы можете видеть, что вы делаете. Кроме того, существуют различия между rebase и слиянием, которые слишком малы, чтобы их можно было использовать в комментарии.
Эдвард Фальк

4
проблема со всеми этими ответами заключается в том, что вы должны находиться в основной ветке локально и выполнить команду merge --squash ... Я хочу запустить слияние --squash из ветви функций, а не из главной ветви .. так что когда я закончу, я могу передать ветку функции на удаленный компьютер и отправить PR, это возможно?
Александр Миллс

2
@AlexanderMills, я думаю, вам просто нужна вторая ветвь функций (клонированная из основной ветки). Выполните переход merge --squashот старого к новому, а затем объедините новую ветку с мастером. Старая ветка устаревает.
Gyromite

Ответы:


2002

Скажем, ваша ветка исправления ошибок называется, bugfixи вы хотите объединить ее в master:

git checkout master
git merge --squash bugfix
git commit

Это возьмет все коммиты из bugfixветви, раздавит их в 1 коммит и объединит его с вашей masterветкой.


Пояснение :

git checkout master

Переключается на вашу masterветку.

git merge --squash bugfix

Принимает все коммиты из bugfixветви и объединяет их с вашей текущей веткой.

git commit

Создает один коммит из объединенных изменений.

Пропуск -mпараметра позволяет вам изменить черновик коммита, содержащий каждое сообщение из ваших сдавленных коммитов, прежде чем завершить коммит.


222
Если вы хотите сохранить ссылки на старые сообщения коммита, вы можете написать git commit(без -mпараметров), и вы сможете модифицировать черновик коммит-сообщения, содержащий все сообщения коммита, которые вы сжатые.
Алекс

12
Вы можете достичь того же, сделав git commit --amend -m '...'позже.
Януш Ленар

19
В случае возникновения конфликтов слияния и разрешения этих конфликтов git commitбольше не будет отображаться полезное сообщение о фиксации, содержащее все сообщения о фиксации, которые вы подавили. В этом случае попробуйте git commit --file .git/SQUASH_MSG(через stackoverflow.com/a/11230783/923560 ).
Абдул

23
Имейте в виду, что сквош по умолчанию приписывает коммитам сквошер . Чтобы сохранить первоначального автора, вам нужно явно указать его так:git commit -a --author="Author" --message="Issue title #id"
gaborous

5
git merge --squashпозволяет вам создать один коммит поверх текущей ветви, эффект которого такой же, как и слияние другой ветви. Но это не приведет к записи слияния, что означает, что ваш запрос на получение результата не будет иметь изменений, но не будет помечен как объединенный! Итак, вам нужно будет просто удалить эту ветку, чтобы сделать.
am0wa

129

Что наконец прояснило для меня это комментарий, показывающий, что:

git checkout main
git merge --squash feature

эквивалентно выполнению:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

Когда я хочу объединить ветку объектов со 105 (!!) коммитами и объединить их все в один, я не хочу, git rebase -i origin/masterпотому что мне нужно отдельно разрешать конфликты слияния для каждого из промежуточных коммитов (или, по крайней мере, тех, которые мерзавец не может понять сам). Использование git merge --squashдает мне желаемый результат одного коммита для слияния целой ветви функций. И мне нужно сделать не более одного ручного разрешения конфликта.


75
Я настоятельно рекомендую сначала выполнить слияние в ветви функций git merge master, а затем только git merge --squash featureв основной ветви.
Dotancohen

8
@dotancohen Извините, что удалил старый комментарий :) Что вы получаете от слияния в ветви функций перед выполнением git merge --squash featureиз основной ветви?
bitmack

57
Сначала вы хотите объединить мастер с веткой функций и иметь дело с любыми ручными исправлениями в вашей ветке функций. Это также позволяет вам запускать тесты и убедиться, что ваша ветвь функций работает правильно. Затем вы гарантируете, что вы можете сделать автоматическое объединение вашей функциональной ветви с master.
Дэн Кон

4
@dankohn Я предлагаю вам добавить объяснение в комментарии выше в ваш ответ.
Гюнтберт

3
@bitsmack: сначала вы объедините мастер с функцией. Это дает вам возможность разрешать конфликты в функции до ее слияния с мастером
Майк

97

Вы хотите объединить с опцией сквоша. Это если вы хотите сделать это по одной ветке за раз.

git merge --squash feature1

Если вы хотите объединить все ветви одновременно с одиночными коммитами, то сначала интерактивно перебазируйте и раздавите каждую функцию, а затем объедините осьминога:

git checkout feature1
git rebase -i master

Сквош в один коммит, затем повторите для других функций.

git checkout master
git merge feature1 feature2 feature3 ...

Последнее слияние является «слиянием осьминога», потому что оно объединяет множество веток одновременно.

Надеюсь это поможет


3
Почему ты ребазируешь?
Умайр А.

12
@UmairAshraf это интерактивная перебазировка, которая дает вам возможность сделать сквош в вашей ветке.
andho

1
Перебазирование - плохая идея. Не рекламируйте уже опубликованные коммиты
Sebi2020

1
@ Sebi2020 git merge --squash перебазирует ваши уже опубликованные коммиты способом, который хуже интерактивного перебазирования. Интерактивная перебазировка (в ветви функций) практически не имеет побочных эффектов.
Xiix

1
@xiix Это верно только в том случае, если вы единственный, кто работает с веткой функций. Это не предположение, которое вы можете сделать. Я рекомендую прочитать страницы, связанные с перебазированием на Git-SCM . В нем говорится: « Не перебазируйте коммиты, которые существуют за пределами вашего репозитория, и люди могут основываться на них». И если вы не знаете наверняка, работают ли люди уже на основе опубликованных коммитов (чего вы не можете знать из-за децентрализованного природа мерзавца) ты не должен этого делать.
Sebi2020

23

Если у вас есть уже git merge bugfixна main, вы можете раздавить ваше слияние совершить в один с:

git reset --soft HEAD^1
git commit

git reset --soft HEAD^1кажется, отменяет последний коммит, выполненный перед слиянием, по крайней мере, в случае быстрого слияния.
Джеспер Маттисен

@JesperMatthiesen в случае ускоренной перемотки вы не получите коммит слияния, так что вы бы сделали git reset --soft HEAD^<number-of-commits-to-squash>.
qwertzguy

Это помогло мне объединить все в один коммит после слияния вниз по течению.
killjoy

18

Объединить newFeatureветку masterс пользовательским коммитом:

git merge --squash newFeature && git commit -m 'Your custom commit message';

Если вместо этого вы делаете

git merge --squash newFeature && git commit

вы получите сообщение о коммите, которое будет включать все newFeature коммиты ветки, которые вы можете настроить.

Я подробно объясняю это здесь: https://youtu.be/FQNAIacelT4


10

Я знаю, что этот вопрос не касается конкретно Github, но, поскольку Github очень широко используется, и это ответ, который я искал, я поделюсь им здесь.

Github имеет возможность выполнять слияние сквоша, в зависимости от параметров слияния, включенных для хранилища.

Если слияние в сквош включено, опция «Сквош и слияние» должна появиться в раскрывающемся списке под кнопкой «Слияние».

Снимок экрана функции "Сквош и слияние" на Github


GitHub использует электронную почту по умолчанию, связанную с вашей учетной записью. Если у вас есть несколько адресов электронной почты, и вам нужно использовать дополнительный, вы не можете использовать GH UI.
Лука Гуиди

4

Предположим, вы работали в feature / task1 с несколькими коммитами.

  1. Перейдите в ветку вашего проекта (project / my_project)

    git checkout project/my_project
    
  2. Создать новую ветку (feature / task1_bugfix)

    git checkout -b feature/task1_bugfix
    
  3. Мардж с --squashопцией

    git merge --squash feature/task1
    
  4. Создать один коммит

    git commit -am "add single comments"
    
  5. Раздвинь свою ветку

    git push --set-upstream origin feature/task1_bugfix
    

1

Для Git

Создать новую функцию

через терминал / оболочку:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

Это не фиксирует это, позволяет вам сначала просмотреть его.

Затем зафиксируйте и завершите функцию из этой новой ветки, а также удалите / проигнорируйте старую ветку (ту, на которой вы создали dev).


@Melebius Единственная ссылка на «SourceTree» находится в вашем предложении, если это был тег или предыдущий вопрос: он больше не существует.
Джордан Стефанелли

1
@JordanStefanelli SourceTree был использован в оригинальной версии этого ответа . Спасибо, что сообщили, что это исправлено!
Мелебиус

1

если вы получили ошибку: фиксация невозможна, потому что у вас есть файлы без слияния.

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

исправлены все файлы конфликтов

git add . 

Вы также можете использовать

git add [filename]

0

Чтобы раздавить свою местную ветку, прежде чем нажать ее:

  1. Проверьте ветку, в которой вы хотите работать, если она еще не проверена.

  2. Найдите ша самого старого коммита, который вы хотите сохранить.

  3. Создайте / извлеките новую ветку (tmp1) из этого коммита.

    git checkout -b tmp1 <sha1-of-commit>

  4. Слейте оригинальную ветвь в новую.

    git merge --squash <original branch>

  5. Зафиксируйте изменения, которые были созданы слиянием, с сообщением сводной фиксации.

    git commit -m <msg>

  6. Оформить оригинальную ветку, которую вы хотите раздавить.

    git checkout <branch>

  7. Восстановите исходный коммит, который хотите сохранить.

    git reset --soft <sha1>

  8. Перебазируйте эту ветку на основе новой ветки tmp1.

    git rebase tmp1

  9. Вот и все - теперь удалите временную ветку tmp1, как только вы убедитесь, что все в порядке.


0

Вы можете использовать инструмент, который я создал, чтобы упростить этот процесс: git-squash . Например, чтобы раздавить все коммиты в ветви функций, которая была отделена от основной ветви, напишите:

git squash master
git push --force
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.