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

197

Предположим, у вас есть история, содержащая три коммита 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

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

Кристиан
источник

Ответы:

169

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

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

pick f4202da A
squash bea708e B
pick a8c6abc C

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

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

kostmo
источник
126

Ты пытался:

git rebase -i A

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

edit e97a17b B
pick asd314f C

тогда беги

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

Готово.

Дэвид Лихтеблау
источник
4
Если вы делаете это, чтобы спокойно исправить суть github, вам нужно добавить -m «initial» в коммит. ;-)
Бруно Броноски
1
git rebase --abortначать все сначала и сделать это правильно (не раздавить первый коммит в редакторе)
oma
66

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
CB Bailey
источник
1
это вызывает массивную интерактивную ребазу, когда я делаюgit rebase --onto tmp <sha1_for_B>
Алекс
Учитывая, что у меня был новый репо с двумя коммитами (которые я хотел свернуть в один), это отлично сработало для меня. Спасибо @CB Bailey
RominRonin
10

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

pick A
pick B
pick C

стать:

pick A
squash B
pick C

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

Loki
источник
9

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

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

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

Сообщество
источник
1

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

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

KCH
источник
Было бы лучше, если бы ответ повторился и здесь? Я не уверен.
0

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

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


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

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


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

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

Sumit
источник
-1

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

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

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

Бомбы
источник
Поскольку старые и новые начальные коммиты не имеют общего предка, вы можете получить некоторые ненужные конфликты, когда git пытается применить всю историю master к a, даже если у них есть общее дерево. Используя опцию --onto для git rebase, вы можете указать git правильное место для начала применения.
CB Bailey