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

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команда создала коммит слияния. Это позволяет вам создать один коммит поверх текущей ветви, эффект которого такой же, как и слияние другой ветви (или более в случае осьминога).

fseto
источник
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на вашей ветке функции. Затем вы можете изменить все, кроме одного «выбора» на «сквош», чтобы объединить коммиты. Смотрите коммиты на сквош с ребазой

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

fseto
источник
8
Да, это работает, но я не хочу хлопот интерактивной перебазировки. Я просто хочу все, так как ветвь расплющена.
Брэд Робинсон
2
+1 Это делает для чистой истории. Намного легче идентифицировать и управлять коммитами как отдельными патчами, карточками, историями и т. Д.
Райан
2

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

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

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

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

raratiru
источник
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 для хорошего обзора.

NamshubWriter
источник
Это не сработало для меня. Я только что создал простое тестовое репо с веткой WIP и попробовал описанное выше, и у меня возникли конфликты слияния (хотя я не вносил никаких изменений в master).
Брэд Робинсон
Если функция была создана из main (git checkout -b feature main), и у вас было недавнее слияние с main, вы не должны получать конфликты из
rebase
ОК, попробовал еще раз. На этот раз не было конфликтов, но история не была раздавлена.
Брэд Робинсон
Если вы посмотрите на документацию git-merge еще раз, вы правы, некоторые коммиты останутся. Если вы выполнили предыдущие слияния из «основного» в «функциональное», то ребаз будет удален из некоторых, но не всех.
NamshubWriter
Просто помните, что перебазирование может быть довольно опасным, если ветвь функций была ранее опубликована. Больше информации по этому такому вопросу .
Роберт Россманн