Новое репо с копией истории только отслеживаемых файлов
В нашем текущем репо есть десятки тысяч коммитов, а свежий клон передает почти гигантские данные (есть много файлов jar, которые с тех пор были удалены в истории). Мы хотели бы сократить этот размер, создав новое репо, которое хранит полную историю только для файлов, которые в настоящее время активны в репо, или, возможно, просто изменит текущее репо, чтобы очистить историю удаленных файлов. Но я не уверен, как это сделать в практической усадьбе.
Я пробовал script в Удалить удаленные файлы из истории git:
for del in `cat deleted.txt`
do
git filter-branch --index-filter "git rm --cached --ignore-unmatch $del" --prune-empty -- --all
# The following seems to be necessary every time
# because otherwise git won't overwrite refs/original
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --aggressive --prune=now
done;
Но учитывая, что у нас есть десятки тысяч удаленных файлов в истории и десятки тысяч коммитов, запуск script займет целую вечность. Я начал запускать это только для ОДНОГО удаленного файла 2 часа назад, и команда filter-branch все еще работает, и каждый из 40 000+ совершает одно за другим, и это работает на новом Macbook pro с накопителем SSD.
Я также прочитал страницу https://help.github.com/articles/remove-sensitive-data, но это работает только для удаления отдельных файлов.
Кто-нибудь мог это сделать? Я действительно хочу сохранить историю отслеживаемых файлов, я не уверен, будет ли экономия на экономии пространства стоить создания нового репо, если мы не сможем сохранить историю.
Ответы
Ответ 1
Удалить все и восстановить то, что вы хотите
Вместо того, чтобы удалять этот список файлов по одному, делать почти противоположное, удалять все и просто восстанавливать файлы вы хотите сохранить:
$ git checkout master
$ git ls-files > keep-these.txt
$ git filter-branch --force --index-filter \
"git rm --ignore-unmatch --cached -qr . ; \
cat $PWD/keep-these.txt | xargs git reset -q \$GIT_COMMIT --" \
--prune-empty --tag-name-filter cat -- --all
Это может быть быстрее выполнить.
Шаги очистки
Как только весь процесс завершится, очистка:
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
# optional extra gc. Slow and may not further-reduce the repo size
$ git gc --aggressive --prune=now
Сравнивая размер репозитория до и после, следует указать значительную
сокращение и, конечно, только фиксирует, что касается сохраненных файлов, плюс слияние
фиксирует - даже если пустой (потому что то, как работает -pune-empty работает), будет в истории.
$GIT_COMMIT?
Использование $GIT_COMMIT
, по-видимому, вызвало некоторую путаницу, из документации по ветвям фильтра git (выделено мной):
Аргумент всегда оценивается в контексте оболочки с помощью команды eval (с заметным исключением фильтра фиксации по техническим причинам). До этого переменная среды $GIT_COMMIT будет установлена так, чтобы содержать идентификатор переписываемой фиксации.
Это означает, что git filter-branch
предоставит переменную во время выполнения, она не предоставляется вами перед началом работы. Это можно продемонстрировать, если есть какие-либо сомнения при использовании этой команды ветвления фильтра no-op:
$ git filter-branch --index-filter "echo current commit is \$GIT_COMMIT"
Rewrite d832800a85be9ef4ee6fda2fe4b3b6715c8bb860 (1/xxxxx)current commit is d832800a85be9ef4ee6fda2fe4b3b6715c8bb860
Rewrite cd86555549ac17aeaa28abecaf450b49ce5ae663 (2/xxxxx)current commit is cd86555549ac17aeaa28abecaf450b49ce5ae663
...
Ответ 2
База на AD7six, с сохраненной историей переименованных файлов. (вы можете пропустить предварительный дополнительный раздел)
Дополнительно
удалите все пульты:
git remote | while read -r line; do (git remote rm "$line"); done
удалить все теги:
git tag | xargs git tag -d
удалите все остальные ветки:
git branch | grep -v \* | xargs git branch -D
удалить все блокировки:
git stash clear
удалить всю конфигурацию и кеширование подмодулей:
git config --local -l | grep submodule | sed -e 's/^\(submodule\.[^.]*\)\(.*\)/\1/g' | while read -r line; do (git config --local --remove-section "$line"); done
rm -rf .git/modules/
Обрезка истории необработанных файлов, сохранение истории отслеживаемых файлов и переименований
git ls-files | sed -e 's/^/"/g' -e 's/$/"/g' > keep-these.txt
git ls-files | while read -r line; do (git log --follow --raw --diff-filter=R --pretty=format:%H "$line" | while true; do if ! read hash; then break; fi; IFS=$'\t' read mode_etc oldname newname; read blankline; echo $oldname; done); done | sed -e 's/^/"/g' -e 's/$/"/g' >> keep-these.txt
git filter-branch --force --index-filter "git rm --ignore-unmatch --cached -qr .; cat \"$PWD/keep-these.txt\" | xargs git reset -q \$GIT_COMMIT --" --prune-empty --tag-name-filter cat -- --all
rm keep-these.txt
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
- Первые две команды состоят в том, чтобы перечислить файлы с отслеживаемыми файлами и отсканированные старые файлы, используя кавычки для сохранения путей с пробелами.
- Третья команда состоит в том, чтобы переписать фиксации только для этих файлов.
- Последующие команды должны очистить историю.
Дополнительно (не рекомендуется)
repack (from the-woes-of-git-gc-aggressive):
git repack -a -d --depth=250 --window=250
Ответ 3
Выполнить git ветвь фильтра только один раз
script в вопросе будет обрабатывать тысячи коммитов, тысячи раз - и он делает разные (очень медленные) вещи один раз за итерацию, которые обычно вы будете делать только в конце. Это действительно навсегда.
Вместо этого запустите script один раз, удалив все файлы за один раз:
del=`cat deleted.txt`
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch $del" \
--prune-empty --tag-name-filter cat -- --all
Как только процесс завершится, очистка:
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
# optional extra gc. Slow and may not further-reduce the repo size
git gc --aggressive --prune=now
Если вышеописанное не удается из-за количества файлов
Если в файле deleted.txt достаточно файлов, так что указанная выше команда слишком велика для запуска, ее можно переписать как-то так:
git filter-branch --force --index-filter \
'cat /abs/path/to/deleted.txt | xargs git rm --cached --ignore-unmatch' \
--prune-empty --tag-name-filter cat -- --all
(шаги очистки одинаковы)
Это идентично версии выше, но команда для удаления файлов делает это по одному, а не сразу.