Вопрос

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

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

Это было полезно?

Решение

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

Объясните

  1. создайте один коммит с помощью git commit-tree

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

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

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

  2. сбросьте текущую ветвь до новой фиксации

    Затем 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) на стандартный вывод.Затем просто перезагрузите свою ветку.

git reset SHA-1

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

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

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

git log --oneline

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

git reset --soft <#sha#>

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

git status

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

git commit --amend

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

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

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

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

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

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

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

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

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

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

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

git checkout --orphan new_root_branch  &&  git commit

Раздавить с помощью трансплантатов

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

git log теперь начну с этого коммита

Чтобы сделать это «настоящим» запуском git filter-branch

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

git branch backup

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

git reset --soft <#root>

затем добавьте все файлы в промежуточную версию

git add .

зафиксировать без обновления сообщения

git commit --amend --no-edit

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

git push -f

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

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

Конечно, коммит-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
')

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

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

  • Бегать 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 чтобы принудительно отправить ваши изменения

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top