15 ответов:
пожалуй, самый простой способ-это просто создать новый репозиторий с текущим состоянием рабочей копии. Если вы хотите сохранить все сообщения, Вы могли бы сначала сделать
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
В последних версиях Git, вы можете использовать
git rebase --root -i.для каждого коммита, кроме первого, изменить
picktosquash.
обновление
я сделал псевдоним
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чтобы создать сироту совершить и пойти с ним.объяснить
создать один коммит через
git commit-treeчто
git commit-tree HEAD^{tree} -m "A new start"это:создает новый объект фиксации на основе предоставленного объекта дерева и выдает новый идентификатор объекта фиксации на stdout. Сообщение журнала является считывание со стандартного входа, если только-m или-F варианты приведены.
выражение
HEAD^{tree}означает объект дерева, соответствующийHEAD, а именно кончик текущая ветка. смотрите Дерево-Объекты и Commit-Objects.сброс текущей ветви к новой фиксации
затем
git resetпросто сбросьте текущую ветку на вновь созданную зафиксировать объект.таким образом, ничего в рабочей области нет прикоснулся, ни там нужно перебазировать / сквош, что делает его очень быстрым. И необходимое время не имеет отношения к размеру репозитория или глубине истории.
вариация: новое РЕПО из шаблона проекта
это полезно для создания "начальной фиксации" в новом проекте с использованием другого репозитория в качестве шаблона/архетипа/семени/скелета. Например:
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или иначе) и сворачивает история РЕПО шаблона в вашу первоначальную фиксацию.
если все, что вы хотите сделать, это раздавить все ваши коммиты до корневого коммита, то в то время как
git rebase --interactive --rootможет работать, это непрактично для большого количества коммитов (например, сотни коммитов), потому что операция перебазирования, вероятно, будет выполняться очень медленно для создания интерактивного списка фиксации редактора перебазирования, а также для запуска самой перебазировки.
вот два более быстрых и эффективных решения, когда вы раздавливаете большое количество коммиты:
альтернативное решение #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документы:
echo "message" | git commit-tree HEAD^{tree}это создаст потерянный коммит с деревом HEAD и выведет его имя (SHA-1) на stdout. Тогда просто сбросьте свою ветку там.
git reset SHA-1
самый простой способ-использовать команду "сантехника"
update-refдля удаления текущей ветви.вы не можете использовать
git branch -Dпоскольку он имеет предохранительный клапан, чтобы остановить удаление текущей ветви.Это возвращает вас в состояние "начальная фиксация", где вы можете начать с новой начальной фиксации.
git update-ref -d refs/heads/master git commit -m "New initial commit"
вот как я закончил это делать, на всякий случай, если это работает для кого-то другого:
помните, что всегда есть риск в таких вещах, и это никогда не плохая идея, чтобы создать ветку сохранения перед запуском.
войдите
git log --onelineпрокрутите до первой фиксации, скопируйте SHA
git reset --soft <#sha#>заменить
<#sha#>w / SHA скопировано из журналаgit statusубедитесь, что все зеленое, в противном случае запустите
git add -Agit commit --amendизменить все текущие изменения на текущую первую фиксацию
теперь принудительно нажмите эту ветку, и она перезапишет то, что есть.
Я читал что-то об использовании трансплантатов, но никогда не исследовал его много.
в любом случае, вы можете раздавить эти последние 2 коммита вручную с чем-то вроде этого:
git reset HEAD~1 git add -A git commit --amend
во-первых, сквош все ваши коммиты в один коммит, используя
git rebase --interactive. Теперь у вас осталось два коммита на сквош. Для этого прочитайте любой из
сквош с помощью трансплантатов
Добавить файл
.git/info/grafts, поместите туда хэш фиксации, который вы хотите стать своим корнем
git logтеперь начнем с этой фиксациичтобы сделать его "реальным" запустить
git filter-branch
"альтернативное решение №1: сиротские ветви" помогает мне.
" git rebase --interactive --root " застрял в конфликте файлов gitignored.
этот ответ улучшает пару выше (пожалуйста, проголосуйте за них), предполагая, что в дополнение к созданию одной фиксации (без родителей без истории), вы и хотите сохранить все коммит-данные этого коммита:
- автора (имя и адрес электронной почты)
- автор дата
- коммитеров (имя и адрес электронной почты)
- совершено дата
- Commmit log message
конечно коммит-ша нового / сингла фиксация изменится, потому что она представляет собой новую (не-)историю, становясь родительской/корневой фиксацией.
Это можно сделать, прочитав
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 ')
Я обычно делаю это так:
убедитесь, что все зафиксировано, и запишите последний идентификатор фиксации в случае, если что-то пойдет не так, или создайте отдельную ветку в качестве резервной копии
выполнить
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в силу изменений
создать резервную копию
git branch backupсброс к указанному commit
git reset --soft <root>добавить все файлы в staging
git add .фиксация без обновления сообщения
git commit --amend --no-editнажмите новую ветку с раздавленными коммитами на репо
git push -f
Comments