Объединить первые два коммита Git-репозитория?

Предположим, у вас есть история, содержащая три коммита A, B и C:

A-B-C

Я хотел бы объединить два коммита A и B в один коммит AB:

AB-C

Я старался

git rebase -i A

который открывает мой редактор со следующим содержанием:

pick e97a17b B
pick asd314f C

Я меняю это на

squash e97a17b B
pick asd314f C

Тогда Git 1.6.0.4 говорит:

Cannot 'squash' without a previous commit

Есть ли способ или это просто невозможно?

9 ответов

Решение

Использование git rebase -i --root с версии Git 1.7.12.

В интерактивном файле перебазировки измените вторую строку коммита B, чтобы он давил, и оставьте другие строки на пике:

pick f4202da A
squash bea708e B
pick a8c6abc C

Это объединит два коммита A и B в один коммит AB.

Нашел в этом ответе.

Ты пытался:

git rebase -i A

Можно начать так, если вы продолжите с edit скорее, чем squash:

edit e97a17b B
pick asd314f C

затем беги

git reset --soft HEAD^
git commit --amend
git rebase --continue

Готово.

A был первоначальный коммит, но теперь вы хотите B быть начальным коммитом. Коммиты git - это целые деревья, а не diffs, даже если они обычно описываются и рассматриваются в терминах diff, которые они вводят.

Этот рецепт работает, даже если есть несколько коммитов между A и B и B и C.

# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp

В случае, если у вас есть сотни или тысячи коммитов, используйте ответ Костмо

git rebase -i --root

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

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

git checkout --orphan orphan <second-commit-sha>
git commit -m "Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

Документация

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

pick A
pick B
pick C

становиться:

pick A
squash B
pick C

Если A является начальным коммитом, вы должны иметь другой начальный коммит, прежде чем A. Git подумает о различиях, он будет работать на разнице между (A и B) и (B и C). Следовательно сквош не работает в вашем примере.

В связанном вопросе мне удалось придумать другой подход к необходимости раздавливания первого коммита, то есть сделать второй.

Если вам интересно: git: как вставить коммит в качестве первого, сдвинув все остальные?

Команда Git для отряда: git rebase -i HEAD~[количество коммитов]

Допустим, у вас есть история git коммитов:


pick 5152061 feat: добавлена ​​поддержка сохранения изображения. (А)
pick 39c5a04 Fix: исправление ошибок. (В)
выбрать 839c6b3 исправить: конфликт разрешен. (С)

Теперь вы хотите раздавить A и B до AB, выполните следующие шаги:


pick 5152061 feat: добавлена ​​поддержка сохранения изображения. (А)
s 39c5a04 Исправлено: исправление ошибок. (В)
выбрать 839c6b3 исправить: конфликт разрешен. (С)

Примечание: для фиксации сквоша мы можем использовать сквош или s. Конечный результат будет:
pick 5152061 feat: добавлена ​​поддержка сохранения изображения. (АВ)
выбрать 839c6b3 исправить: конфликт разрешен. (С)

Вы должны выполнить немного магии командной строки.

git checkout -b a A
git checkout B <files>
git commit --amend
git checkout master
git rebase a

Это должно оставить вас с веткой, в которой коммиты имеют AB и C.

Мне также интересно, что, если структура похожа

      X-Y------Z
 \-A-B-C/

и я хочу, чтобы окончательная структура была

      X-Y-----Z
 \-AB-C/

Как в этом случае объединить A и B?

Другие вопросы по тегам