Как раздавить все git commits в один?
Как вы раздавите весь свой репозиторий до первого коммита?
Я могу перебазироваться на первый коммит, но это оставит меня с 2 коммит. Есть ли способ ссылаться на фиксацию перед первым?
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
.
для каждого коммита, кроме первого, изменить pick
to squash
.
обновление
я сделал псевдоним 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
просто сбросьте текущую ветвь на вновь созданную объект фиксации.
таким образом, ничего в рабочей области тронут, и нет нужно для 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
или иначе) и сворачивает история шаблона РЕПО в вашей первоначальной фиксации.
если все, что вы хотите сделать, это раздавить все ваши коммиты до корневой фиксации, то while
git rebase --interactive --root
может работать, это непрактично для большого количества коммитов (например, сотни коммитов), потому что операция rebase, вероятно, будет выполняться очень медленно для создания интерактивного списка коммитов редактора rebase, а также для запуска самой rebase.
вот два более быстрых и эффективных решения, когда вы раздавливаете большое количество commits:
альтернативное решение #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 -A
git commit --amend
изменить все текущие изменения на текущую первую фиксацию
теперь принудительно нажмите эту ветку, и она перезапишет то, что там.
Я читал что-то об использовании трансплантатов, но никогда не исследовал его много.
в любом случае, вы можете раздавить эти последние 2 коммита вручную с чем-то вроде этого:
git reset HEAD~1
git add -A
git commit --amend
во-первых, сквош все ваши коммиты в один коммит, используя git rebase --interactive
. Теперь у вас осталось два обязательства по сквошу. Для этого читать
раздавить с помощью трансплантатов
Добавить файл .git/info/grafts
, поместите туда хэш фиксации, который вы хотите стать своим root
git log
теперь начнется с этого commit
чтобы сделать его "реальным" run git filter-branch
"альтернативное решение №1: сиротские ветви" помогает мне.
" git rebase --interactive --root " застрял в конфликте файлов gitignored.
этот ответ улучшает пару выше (пожалуйста, проголосуйте за них), предполагая, что в дополнение к созданию одной фиксации (без родителей без истории), вы и хотите сохранить все данные фиксации этой фиксации:
- автора (имя и адрес электронной почты)
- автор дата
- Commiter (имя и адрес электронной почты)
- совершено дата
- сообщение журнала Commmit
конечно, commit-SHA нового / сингла фиксация изменится, потому что она представляет собой новую (не-)историю, становясь родительской/корневой фиксацией.
Это можно сделать, прочитав 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
')
Я обычно делаю это так:
убедитесь, что все зафиксировано, и запишите последний идентификатор фиксации в случае, если что-то пойдет не так, или создайте отдельную ветку в качестве резервной копии
Run
git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`
чтобы сбросить голову до первого фиксации, но оставить индекс без изменений. Все изменения с момента первого фиксации теперь будут готовы к фиксации.Run
git commit --amend -m "initial commit"
чтобы изменить фиксацию на первую фиксацию и изменить сообщение коммита, или если вы хотите сохранить сообщение, вы можете работатьgit commit --amend --no-edit
Run
git push -f
в силу изменений
создать резервную копию
git branch backup
сброс до указанной фиксации
git reset --soft <root>
добавить все файлы в staging
git add .
commit без обновления сообщения
git commit --amend --no-edit
нажмите новую ветку с раздавленными фиксациями на репо
git push -f