Объединить (с помощью сквоша) все изменения из другой ветви как один коммит


479

В Git есть ли способ объединить все изменения из одной ветви в другую, но в то же время объединить в один коммит?

Я часто работаю над новой функцией в отдельной ветке и буду регулярно фиксировать / отправлять - в основном для резервного копирования или переноса того, над чем я работаю, на другую машину. В основном эти коммиты говорят "Feature xxx WIP" или что-то избыточное.

Как только эта работа закончится, и я хочу слить ветку WIP обратно в master, я бы хотел отказаться от всех этих промежуточных коммитов и просто иметь один чистый коммит.

Есть простой способ сделать это?

В качестве альтернативы, как насчет команды, которая уничтожает все коммиты на ветви с момента, когда она была разветвлена?

Ответы:


601

Другой вариант, git merge --squash <feature branch>наконец, сделать git commit.

Из Git слияния

--squash

--no-squash

Создайте рабочее дерево и состояние индекса, как если бы произошло реальное слияние (за исключением информации о слиянии), но на самом деле не выполняйте фиксацию, не перемещайте и HEADне записывайте, $GIT_DIR/MERGE_HEADчтобы следующая git commitкоманда создала коммит слияния. Это позволяет вам создать один коммит поверх текущей ветви, эффект которого такой же, как и слияние другой ветви (или более в случае осьминога).


1
Классная особенность! Я люблю мерзавца Хотя я определенно буду использовать это в будущем сейчас, я все же рекомендую ознакомиться с ребазой -i. Это хороший навык на случай, если вы действительно захотите сделать их больше, чем один коммит.
— Уилл Бак

4
Предостережение: это работает, но сообщение о фиксации по умолчанию включает в себя журнал из объединяемой ветви. Проблема в том, что он похож на формат, который вы обычно видите, когда весь показанный текст на самом деле не становится частью сообщения коммита, но в этом случае это происходит. Поэтому, если вы не хотите всего этого, вам нужно вручную удалить все это из вашего сообщения о коммите. Я должен был проверить это перед использованием ...
— still_dreaming_1

23
Имейте в виду, что ветвь не будет рассматриваться как объединенная. stackoverflow.com/questions/19308790/…
— Райан

3
ИМХО это надо было называтьrebase --squash
— Энди

поэтому (поскольку в действительности это не объединяет ветку объектов), это было бы целесообразно, если вы собираетесь удалить ветвь объектов после принятия. Это верно? (Я не эксперт по
— Эндрю Спенсер

214

Нашел это! Команда слияния имеет --squashопцию

git checkout master
git merge --squash WIP

в этот момент все объединено, возможно, конфликтует, но не зафиксировано. Теперь я могу:

git add .
git commit -m "Merged WIP"

2
что делает git add .?
— Майкл Поттер

1
@MichaelPotter Это добавляет все файлы и изменения
— Дакш Шах

2
git add .добавляет все не проигнорированные файлы в текущем каталоге, я бы с осторожностью выбрал нежелательные файлы таким образом.
— Джейк Кобб

7
В качестве альтернативы git add .вы можете использовать git add -uтолько для добавления файлов, которые уже были добавлены в дерево.
— Брэндон Огл

19
Предполагая, что "мерзавец добавить". быть также сделано сбивает с толку. Когда я делаю "Wit git merge --squash", он уже имеет сжатые изменения в индексе. Все, что нужно, это совершить их. Делать "мерзавец добавить". добавит изменения, которые оказались в рабочем каталоге, но не были частью ветви функции. Вопрос заключался в том, как зафиксировать изменения в ветви функций как один коммит.
— Джон Панкович

30

Попробуйте git rebase -i masterна вашей ветке функции. Затем вы можете изменить все, кроме одного «выбора» на «сквош», чтобы объединить коммиты. Смотрите коммиты на сквош с ребазой

Наконец, вы можете выполнить слияние из основной ветки.


8
Да, это работает, но я не хочу хлопот интерактивной перебазировки. Я просто хочу все, так как ветвь расплющена.
— Брэд Робинсон

2
+1 Это делает для чистой истории. Намного легче идентифицировать и управлять коммитами как отдельными патчами, карточками, историями и т. Д.
— Райан

2

Использование git merge --squash <feature branch>в соответствии с принятым ответом помогает, но объединенная ветвь не будет отображаться как фактически объединенная.

Поэтому еще лучшим решением является:

  • Создать новую ветку от последнего мастера
  • Объединитесь <feature branch>с вышеупомянутым, используяgit merge --squash
  • Объединить вновь созданную ветку в мастер

Эта вики объясняет процедуру подробно.


0

Я создал свой псевдоним git, чтобы сделать именно это. Я звоню git freebase! Он возьмет вашу существующую грязную ветвь объектов без возможности восстановления и заново создаст ее, чтобы она стала новой веткой с тем же именем, а ее коммиты будут сжаты в один коммит и перенесены в указанную вами ветку (master по умолчанию). В самом конце, это позволит вам использовать любое сообщение коммита, которое вам нравится, для вашей новой "бесплатной" ветки.

Установите его, поместив следующий псевдоним в ваш .gitconfig:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Используйте его из вашей ветки функций, выполнив: git freebase <new-base>

Я проверял это всего несколько раз, поэтому сначала прочтите его и убедитесь, что вы хотите запустить его. В качестве небольшой меры безопасности он печатает начальный sha1, чтобы вы могли восстановить старую ветку, если что-то пойдет не так.

Я буду поддерживать его в моем репозитории dotfiles на github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig


работал как блаженство! Вы также можете взглянуть на evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/…
— Илья Ширшофф,

-1

git merge --squash <feature branch> это хороший вариант. "git commit" сообщает вам сообщение о фиксации всех ветвей функций с вашим выбором сохранить его.

Для менее совершенного слияния.

git merge do x times --git reset HEAD ^ --soft, затем git commit.

Риск - удаленные файлы могут вернуться.


-5

Вы можете сделать это с помощью команды «rebase». Давайте назовем ветви "основной" и "особенность":

git checkout feature
git rebase main

Команда rebase воспроизведет все коммиты на «feature» как один коммит с родителем, равным «main».

Возможно, вы захотите запустить его git merge mainраньше, git rebase mainесли «main» изменился с момента создания «feature» (или с момента последнего слияния). Таким образом, у вас все еще будет полная история на случай конфликта слияния.

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

git checkout main
git merge feature

См. Страницу перебазирования в Understanding Git Conceptually для хорошего обзора.


Это не сработало для меня. Я только что создал простое тестовое репо с веткой WIP и попробовал описанное выше, и у меня возникли конфликты слияния (хотя я не вносил никаких изменений в master).
— Брэд Робинсон

Если функция была создана из main (git checkout -b feature main), и у вас было недавнее слияние с main, вы не должны получать конфликты из
— rebase

ОК, попробовал еще раз. На этот раз не было конфликтов, но история не была раздавлена.
— Брэд Робинсон

Если вы посмотрите на документацию git-merge еще раз, вы правы, некоторые коммиты останутся. Если вы выполнили предыдущие слияния из «основного» в «функциональное», то ребаз будет удален из некоторых, но не всех.
— NamshubWriter

Просто помните, что перебазирование может быть довольно опасным, если ветвь функций была ранее опубликована. Больше информации по этому такому вопросу .
— Роберт Россманн
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.