Как раздавить все git коммиты в один? - PullRequest
396 голосов
/ 01 ноября 2009

Как вы сократите весь свой репозиторий до первого коммита?

Я могу вернуться к первому коммиту, но это оставило бы меня с 2 коммитами. Есть ли способ ссылаться на коммит до первого?

Ответы [ 14 ]

575 голосов
/ 13 февраля 2012

В последних версиях git вы можете использовать git rebase --root -i.

Для каждого коммита, кроме первого, измените pick на squash.

269 голосов
/ 06 мая 2014

Обновление

Я сделал псевдоним git squash-all.
Пример использования : git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

Предостережение : не забудьте предоставить комментарий, в противном случае будет использоваться сообщение о фиксации по умолчанию "Новое начало".

Или вы можете создать псевдоним с помощью следующей команды:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

Один вкладыш

git reset $(git commit-tree HEAD^{tree} -m "A new start")

Примечание : здесь "A new start" - только пример, не стесняйтесь использовать свой собственный язык.

TL; DR

Нет необходимости раздавливать, используйте git commit-tree, чтобы создать осиротевший коммит и идти с ним.

Объясните

  1. создать один коммит через git commit-tree

    Что делает git commit-tree HEAD^{tree} -m "A new start":

    Создает новый объект фиксации на основе предоставленного объекта дерева и отправляет новый идентификатор объекта фиксации на стандартный вывод. Сообщение журнала читать со стандартного ввода, если не указаны опции -m или -F.

    Выражение HEAD^{tree} означает объект дерева, соответствующий HEAD, а именно кончик вашей текущей ветви. см. Tree-Objects и Commit-Objects .

  2. сбросить текущую ветку на новый коммит

    Тогда git reset просто сбрасывает текущую ветку на вновь созданную совершить объект.

Таким образом, ничего в рабочей области не затрагивается, и нет нужно перебазировать / сквош, что делает его очень быстрым. И необходимое время не зависит от размера хранилища или глубины истории.

Вариант: новый репо из шаблона проекта

Это полезно для создания «начального коммита» в новом проекте с использованием другого репозитория в качестве шаблона / archetype / seed / skeleton. Например:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

Это позволяет избежать добавления репозитория в качестве удаленного (origin или иным образом) и сворачивает историю репо в ваш первоначальный коммит.

147 голосов
/ 11 июня 2014

Если все, что вы хотите сделать, это сжать все ваши коммиты до корневого, тогда как

git rebase --interactive --root

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

Вот два более быстрых и эффективных решения, когда вы подавляете большое количество коммитов:

Альтернативное решение № 1: сиротские ветви

Вы можете просто создать новую потерянную ветку на кончике (то есть самой последней фиксации) вашей текущей ветки. Эта сиротская ветвь формирует начальный корневой коммит совершенно нового и отдельного дерева истории коммитов, которое фактически эквивалентно уничтожению всех ваших коммитов:

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

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

Альтернативное решение № 2: программный сброс

Другое эффективное решение - просто использовать смешанный или программный сброс к корневому коммиту <root>:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

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

121 голосов
/ 01 ноября 2009

Возможно, самый простой способ - просто создать новый репозиторий с текущим состоянием рабочей копии. Если вы хотите сохранить все сообщения о коммите, вы можете сначала сделать git log > original.log, а затем отредактировать его для своего исходного сообщения о фиксации в новом хранилище:

rm -rf .git
git init
git add .
git commit

или

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
46 голосов
/ 04 ноября 2009
echo "message" | git commit-tree HEAD^{tree}

Это создаст осиротевший коммит с деревом HEAD и выведет его имя (SHA-1) на стандартный вывод. Тогда просто перезагрузите там свою ветку.

git reset SHA-1
36 голосов
/ 31 октября 2015

Вот как я это сделал, на случай, если это сработает для кого-то другого:

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

Начните с регистрации

git log --oneline

Прокрутите до первого коммита, скопируйте SHA

git reset --soft <#sha#>

Заменить <#sha#> с SHA, скопированным из журнала

git status

Убедитесь, что все зеленое, в противном случае запустите git add -A

git commit --amend

Изменить все текущие изменения в текущем первом коммите

Теперь принудительно нажмите эту ветку, и она перезапишет то, что там.

32 голосов
/ 02 ноября 2009

Самый простой способ - использовать команду update-ref 'сантехника', чтобы удалить текущую ветвь.

Вы не можете использовать git branch -D, так как он имеет предохранительный клапан, чтобы остановить удаление текущей ветви.

Это возвращает вас в исходное состояние фиксации, где вы можете начать со свежего начального коммита.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
29 голосов
/ 01 ноября 2009

Я читал кое-что об использовании трансплантатов, но никогда не исследовал это много.

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

git reset HEAD~1
git add -A
git commit --amend
16 голосов
/ 02 ноября 2009

Во-первых, объедините все свои коммиты в один коммит, используя git rebase --interactive. Теперь у вас осталось два коммита для сквоша. Для этого прочитайте любой из

10 голосов
/ 16 августа 2018

В одной строке 6 слов

git checkout --orphan new_root_branch  &&  git commit
...