Как сквот всех git фиксируется в одном?

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

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

Ответ 1

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

Ответ 2

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

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

Ответ 3

Update

Я сделал псевдоним 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"

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

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

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, чтобы создать сиротскую фиксацию и пойти с ней.

Объяснить

  • создать единую фиксацию через git commit-tree

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

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

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

  • reset текущая ветвь к новой фиксации

    Затем git reset просто reset текущая ветвь к вновь созданному передать объект.

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

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

Это полезно для создания "первоначального коммита" в новом проекте с использованием другого репозитория в качестве шаблона/архетипа/семестра/скелета. Например:

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 или иначе) и сворачивает историю репо-шаблона в ваш первоначальный коммит.

Ответ 4

Если все, что вы хотите сделать, это сквош всех ваших коммитов до корневой фиксации, а затем

git rebase --interactive --root

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

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

Альтернативное решение №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: soft reset

Еще одно эффективное решение - просто использовать смешанный или мягкий reset для корневой фиксации <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

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

Ответ 5

echo "message" | git commit-tree HEAD^{tree}

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

git reset SHA-1

Ответ 6

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

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

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

git log --oneline

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

git reset --soft <#sha#>

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

git status

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

git commit --amend

Изменить все текущие изменения на текущую первую фиксацию

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

Ответ 7

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

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

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

git update-ref -d refs/heads/master
git commit -m "New initial commit"

Ответ 8

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

Во всяком случае, вы можете скворовать последние два коммита вручную с помощью чего-то вроде этого:

git reset HEAD~1
git add -A
git commit --amend

Ответ 10

Для сквоша с использованием трансплантатов

Добавьте файл .git/info/grafts, поставьте хеш фиксации, который вы хотите стать корнем

git log теперь начнет с этого commit

Чтобы сделать его "реальным" прогоном git filter-branch

Ответ 11

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

git checkout --orphan new_root_branch  &&  git commit

Ответ 12

создать резервную копию

git branch backup

сброс до указанного коммита

git reset --soft <#root>

затем добавьте все файлы в постановку

git add .

совершить без обновления сообщения

git commit --amend --no-edit

толкать новую ветку с раздавленными коммитами в репо

git push -f

Ответ 13

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

  • Автор (имя и адрес электронной почты)
  • Дата создания
  • Commiter (имя и адрес электронной почты)
  • Дата фиксации
  • Сообщать сообщение в журнале

Конечно, commit-SHA нового/одиночного commit будет изменяться, потому что он представляет новую (не) историю, становясь безбортным /root -commit.

Это можно сделать, прочитав git log и установив некоторые переменные для git commit-tree. Предполагая, что вы хотите создать единую фиксацию из master в новой ветке one-commit, сохраняя данные фиксации выше:

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')

Ответ 14

"Альтернативное решение №1: сиротские ветки" помогает мне.

"git rebase --interactive --root" застрял в конфликте с gitignored.

Ответ 15

Обычно я делаю это так:

  • Убедитесь, что все выполнено, и запишите последний идентификатор фиксации в случае, если что-то пойдет не так, или создайте отдельную ветку в качестве резервной копии

  • Запустите git reset --soft 'git rev-list --max-parents=0 --abbrev-commit HEAD' чтобы сбросить вашу голову до первого фиксации, но оставьте свой индекс неизменным. Все изменения с момента первого фиксации теперь будут готовы к фиксации.

  • Запустить git commit --amend -m "initial commit" чтобы внести изменения в вашу фиксацию в первую фиксацию и изменить сообщение коммита, или если вы хотите сохранить существующее сообщение коммита, вы можете запустить git commit --amend --no-edit

  • Запустить git push -f чтобы заставить нажимать ваши изменения