Удаление ненужных файлов из истории, включая все рефы с фильтром-ветвью

Недавно я клонировал репозиторий SVN, в котором раньше было несколько двоичных файлов, которые больше не нужны. К сожалению, я уже отправил его на Github с включенными двоичными файлами. Теперь я хочу удалить их с помощью «git filter-branch», но у меня возникают некоторые проблемы, когда дело доходит до тегов и ветвей.

По сути, я создал простой сценарий оболочки для удаления списка файлов, которые были определены с помощью следующей команды:

git rev-list --objects --all | grep .jar > files.txt

Скрипт для удаления выглядит следующим образом:

#!/bin/sh
while read file_hash file_to_remove
do
    echo "Removing "$file_to_remove;
    git filter-branch --index-filter "git rm --cached --ignore-unmatch $file_to_remove"
    rm -rf .git/refs/original/;
    git reflog expire --all --expire-unreachable=0;
    git repack -A -d;
    git prune
done < $1

У меня есть несколько тегов (все перечислены в .git/packed-refs), один .git/refs/remotes/origin (указывающий на репозиторий Github). Удаление файлов с помощью приведенного выше сценария не дает желаемого эффекта («du -cm» остается для вывода того же размера; «git rev-list» по-прежнему перечисляет файлы), пока я вручную не удалю все ссылки из .git/packed -refs и каталог .git/refs/remotes/origin.

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

Заранее большое спасибо, Маттес


person matthes    schedule 02.04.2013    source источник


Ответы (1)


В итоге я использовал BFG Repo Cleaner на голом клонированном репозитории (git clone -- зеркальный репозиторий). Он проходит через каждую ветку/тег, оставляя каждую работающей, и даже намного быстрее, чем filter-branch. Надеюсь, это поможет другим людям, имеющим аналогичные проблемы.

Вот мой скрипт-оболочка:

#!/bin/bash
#usage: ./remove_files.sh file_list.txt bare-repo-dir
while read file_hash file_to_remove
do
    echo "Removing "$file_to_remove;
    lastFile=`echo $file_to_remove | awk -F/ '{print $NF}'`;
    java -jar bfg.jar --delete-files $lastFile $2;
done < $1

cd $2;
git gc --prune=now --aggressive;
cd ..;
person matthes    schedule 10.04.2013
comment
Очень рады, что вам нравится инструмент @matthes! Ради интереса, сколько разных файлов нужно было удалить? Переключатель --delete-files принимает глобальные выражения, и в целом лучше сделать только один большой запуск The BFG. Например: '--delete-files *.{xml,exe}' - person Roberto Tyley; 15.04.2013
comment
@Roberto: хороший намек. действительно, в конце концов я удалил только (огромный список) файлов .jar из репо. Так что я думаю, что через --delete-files *.jar было бы еще быстрее (и безопаснее?) - person matthes; 16.04.2013
comment
Да, --delete-files *.jar сделает свое дело! (или что-то вроде --strip-blobs-bigger-than 512K). BFG также обновляет все идентификаторы коммитов, которые он находит в ваших сообщениях о коммитах, поэтому лучше сделать это только один раз. Какой бы подход вы ни выбрали, BFG гарантирует, что он ничего не удалит в вашем последнем коммите, поэтому любые jar-файлы, которые вы все еще используете, не будут удалены. - person Roberto Tyley; 16.04.2013