Как удалить старую историю из репозитория git? - PullRequest
180 голосов
/ 23 декабря 2010

Боюсь, я не смог найти ничего похожего на этот конкретный сценарий.

У меня есть git-репозиторий с большой историей: 500+ веток, 500+ тегов, начиная с середины 2007 года. Он содержит ~ 19 500 коммитов. Мы хотели бы удалить всю историю до 1 января 2010 года, чтобы сделать ее меньше и легче иметь дело (мы сохраним полную копию истории в архивном хранилище).

Я знаю, что коммит, который я хочу получить, стал корнем нового хранилища. Однако я не могу найти правильный git mojo для усечения репо, чтобы начать с этого коммита. Я угадываю какой-то вариант

git filter-branch

с привлечением трансплантатов; может также понадобиться обработать каждую из 200+ веток, которые мы хотим сохранить отдельно, а затем соединить репо (что я делаю знаю, как сделать).

Кто-нибудь когда-нибудь делал что-то подобное? У меня есть git 1.7.2.3, если это имеет значение.

Ответы [ 10 ]

104 голосов
/ 05 февраля 2011

Просто создайте графт родительского элемента вашего нового корневого коммита без родительского коммита (или с пустым коммитом, например, с реальным корневым коммитом вашего репозитория). Например. echo "<NEW-ROOT-SHA1>" > .git/info/grafts

После создания трансплантата он вступает в силу сразу же; Вы должны быть в состоянии посмотреть на git log и увидеть, что ненужные старые коммиты исчезли:

$ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts
$ git log --decorate | tail --lines=11
commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c
Author: Your Name <your.email@example.com>
Date:   Fri May 24 14:04:10 2013 +0200

    Another message

commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <your.email@example.com>
Date:   Thu May 23 22:27:48 2013 +0200

    Some message

Если все выглядит так, как задумано, вы можете просто сделать git filter-branch -- --all, чтобы сделать его постоянным.

ВНИМАНИЕ: после выполнения шага filter-branch все идентификаторы коммитов будут изменены, поэтому любой, использующий старое репо, никогда не должен сливаться с кем-либо, использующим новое репо.

86 голосов
/ 16 января 2016

Возможно, уже слишком поздно отправлять ответ, но поскольку эта страница является первым результатом Google, она все равно может быть полезна.

Если вы хотите освободить место в своем git-репо, но не хотите перестраивать все свои коммиты (перебазировать или прививать), и при этом иметь возможность толкать / извлекать / объединять людей, имеющих полное репо, вы используйте клон git shallow clone ( - глубина параметр).

; Clone the original repo into limitedRepo
git clone file:///path_to/originalRepo limitedRepo --depth=10

; Remove the original repo, to free up some space
rm -rf originalRepo
cd limitedRepo
git remote rm origin

Вы можете обуздать существующее репо, выполнив следующие действия:

; Shallow to last 5 commits
git rev-parse HEAD~5 > .git/shallow

; Manually remove all other branches, tags and remotes that refers to old commits

; Prune unreachable objects
git fsck --unreachable ; Will show you the list of what will be deleted
git gc --prune=now     ; Will actually delete your data

Ps: Старые версии git не поддерживали клонирование / push / pull от / до мелких репо.

53 голосов
/ 21 мая 2014

Этот метод прост для понимания и отлично работает.Аргумент скрипта ($1) - это ссылка (тег, хэш, ...) на коммит, начиная с которого вы хотите сохранить свою историю.

#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m "Truncated history" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch

# The following 2 commands are optional - they keep your git repo in good shape.
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

NOTE старые теги все еще будут присутствовать;поэтому вам может потребоваться удалить их вручную

примечание: Я знаю, что это почти то же самое, что и @yoyodin, но здесь есть несколько важных дополнительных команд и информации.Я попытался отредактировать ответ, но, поскольку это существенное изменение в ответе @ yoyodin, мое редактирование было отклонено, поэтому вот информация!

47 голосов
/ 25 июля 2011

Попробуйте этот метод Как усечь историю git :

#!/bin/bash
git checkout --orphan temp $1
git commit -m "Truncated history"
git rebase --onto temp $1 master
git branch -D temp

Здесь $1 - это SHA-1 коммита, который вы хотите сохранить, и скрипт создаст новую веткусодержит все коммиты между $1 и master и вся старая история удаляется.Обратите внимание, что этот простой сценарий предполагает, что у вас нет существующей ветви с именем temp.Также обратите внимание, что этот скрипт не очищает данные git для старой истории.Запустите git gc --prune=all && git repack -a -f -F -d после того, как вы убедились, что действительно хотите потерять всю историю.Вам также может понадобиться rebase --preserve-merges, но имейте в виду, что реализация этой функции в git не идеальна.Проверьте результаты вручную, если вы их используете.

32 голосов
/ 26 октября 2012

В качестве альтернативы переписыванию истории рассмотрите возможность использования git replace, как в этой статье из Pro Git book .Обсуждаемый пример включает в себя замену родительского коммита для имитации начала дерева, сохраняя при этом всю историю как отдельную ветвь для безопасного хранения.

21 голосов
/ 09 мая 2016

Если вы хотите сохранить репозиторий upstream с полной историей , но с локальными меньшими извлечениями, сделайте небольшой клон с git clone --depth=1 [repo].

После нажатия коммита вы можете сделать

  1. git fetch --depth=1, чтобы удалить старые коммиты.Это делает старые коммиты и их объекты недоступными.
  2. git reflog expire --expire-unreachable=now --all.Для истечения срока действия всех старых коммитов и их объектов
  3. git gc --aggressive --prune=all для удаления старых объектов

См. Также Как удалить локальную историю мерзавцев после фиксации? .

Обратите внимание, что вы не можете перенести этот «мелкий» репозиторий куда-либо еще: «мелкое обновление не разрешено».См. Удаленный отклонен (мелкое обновление не разрешено) после изменения удаленного URL Git .Если вы хотите этого, вы должны придерживаться прививки.

14 голосов
/ 01 мая 2017

Мне нужно было прочитать несколько ответов и другую информацию, чтобы понять, что я делаю.

1.Игнорировать все, что старше определенного коммита

Файл .git/info/grafts может определять поддельных родителей для коммита.Строка с просто идентификатором коммита говорит, что у коммита нет родителя.Если мы хотим сказать, что мы заботимся только о последних 2000 коммитах, мы можем набрать:

git rev-parse HEAD~2000 > .git/info/grafts

git rev-parse дает нам идентификатор коммита 2000-го родителя текущего коммита.Приведенная выше команда перезапишет файл трансплантатов, если он присутствует.Проверьте, есть ли он там первым.

2.Переписать историю Git (необязательно)

Если вы хотите сделать этого привитого поддельного родителя реальным, выполните:

git filter-branch -- --all

Он изменит все идентификаторы коммитов.Каждую копию этого хранилища необходимо принудительно обновлять.

3.Очистить дисковое пространство

Я не выполнил шаг 2, потому что я хотел, чтобы моя копия оставалась совместимой с исходной версией.Я просто хотел сэкономить место на диске.Чтобы забыть все старые коммиты:

git prune
git gc

Альтернатива: мелкие копии

Если у вас есть мелкая копия другого хранилища и вы просто хотите сохранить дискпробел, вы можете обновить .git/shallow.Но будьте осторожны, чтобы ничто не указывало на коммит из ранее.Таким образом, вы можете запустить что-то вроде этого:

git fetch --prune
git rev-parse HEAD~2000 > .git/shallow
git prune
git gc

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

Если у вас все еще есть старые ссылки (теги, ветви, удаленные заголовки), которые указывают на более старые коммиты, они не будут очищеныи вы не сэкономите больше места на диске.

2 голосов
/ 03 января 2017

Когда rebase или нажмите на head / master эта ошибка может произойти

remote: GitLab: You are not allowed to access some of the refs!
To git@giturl:main/xyz.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@giturl:main/xyz.git'

Для решения этой проблемы в git dashboard необходимо удалить главную ветку из «Защищенные ветви»

enter image description here

тогда вы можете запустить эту команду

git push -f origin master

или

git rebase --onto temp $1 master
0 голосов
/ 07 августа 2017

вы можете удалить каталог, файлы, а также всю историю, связанную с dir или файлом, используя нижеприведенный jar [download it] и команды

файл bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/

git clone --bare repo-url cd repo_dir java -jar bfg.jar - имя папки удаленных папок git reflog expire --expire = сейчас --all && git gc --prune = сейчас --aggressive git push --mirror repo_url

0 голосов
/ 22 января 2015
  1. удалить данные git, rm .git
  2. git init
  3. добавить git remote
  4. принудительный толчок
...