Объедините первые две записи репозитория 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

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

Ответ 1

Используйте git rebase -i --root с Git версия 1.7.12.

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

pick f4202da A
squash bea708e B
pick a8c6abc C

Это объединит две коммиты A и B с одной фиксацией AB.

Найден в этот ответ.

Ответ 2

Вы пробовали:

git rebase -i A

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

edit e97a17b B
pick asd314f C

затем запустите

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

Готово.

Ответ 3

A был начальным коммитом, но теперь вы хотите, чтобы B являлся первоначальной фиксацией. git commits - это целые деревья, а не различия, даже если они обычно описываются и просматриваются в терминах 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

Ответ 4

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

pick A
pick B
pick C

чтобы стать:

pick A
squash B
pick C

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

Ответ 5

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

git rebase -i --root

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

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

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

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

Ответ 7

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

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

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