Как удалить старую историю git?

У меня есть репозиторий git со многими, многими (2000+) коммитами, например:

                 l-- m -- n   
                /
a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- k
                     \
                      x -- y -- z

и я хочу обрезать историю старого журнала - удалить все фиксации из истории журнала, начиная с (например) commit "f", но в качестве начала репозитория.

Как это сделать?

Ответ 1

Чтобы не потерять некоторую историю; лучше сначала возьмите копию своего репозитория:). Здесь мы идем: (<f> является шахом фиксации f, которым вы хотите стать новым корневым фиксатором)

git checkout --orphan temp <f>      # checkout to the status of the git repo at commit f; creating a branch named "temp"
git commit -m "new root commit"     # create a new commit that is to be the new root commit
git rebase --onto temp <f> master   # now rebase the part of history from <f> to master onthe temp branch
git branch -D temp                  # we don't need the temp branch anymore

Если у вас есть пульт дистанционного управления, где вы хотите иметь одинаковую усеченную историю; вы можете использовать git push -f. Предупреждение это опасная команда; не используйте это легко! Если вы хотите быть уверены, что ваша последняя версия кода остается прежней; вы можете запустить git diff origin/master. Это не должно меняться (поскольку изменилась только история, а не содержимое ваших файлов).

git push -f  

Следующие 2 команды являются необязательными - они сохраняют ваш репозиторий git в хорошей форме.

git prune --progress                 # delete all the objects w/o references
git gc --aggressive                  # aggressively collect garbage; may take a lot of time on large repos

Ответ 2

Возможное решение вашей проблемы обеспечивается git clone с помощью --shallow-since. Если с f существует только небольшое количество коммитов, и нет никаких проблем с их подсчетом, вы можете использовать опцию --depth.

Второй вариант (--depth) клонирует только указанную ветку. Если вам нужны дополнительные ветки, вы можете добавить исходное репо в качестве удаленного и использовать git fetch и получить их.

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

Этот подход имеет преимущество в размере и скорости. Новое репо содержит только те коммиты, которые вам нужны, и нет необходимости запускать git prune или git gc для удаления старых объектов (потому что их там нет).