Подтвердить что ты не робот

Новое репо с копией истории только отслеживаемых файлов

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

Кто-нибудь мог это сделать? Я действительно хочу сохранить историю отслеживаемых файлов, я не уверен, будет ли экономия на экономии пространства стоить создания нового репо, если мы не сможем сохранить историю.

4b9b3361

Ответ 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

(шаги очистки одинаковы)

Это идентично версии выше, но команда для удаления файлов делает это по одному, а не сразу.