Удалить файл из репозитория git (история)

(решено, см. нижнюю часть тела вопроса)
В поисках этого в течение долгого времени, то, что я до сих пор имею:

Практически тот же метод, но оба они оставляют объекты в пакетных файлах... Застрял.
Что я пробовал:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_name'
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc

Все еще есть файлы в пакете, и вот как я это знаю:

git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3

И это:

git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch file_name" HEAD
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

Такой же...

Пытался git clone уловка, это удалило некоторые из файлов (~3000 из них), но самые большие файлы все еще там...

У меня есть несколько больших старых файлов в репозитории, ~200M, и я действительно не хочу их там... И я не хочу сбрасывать репозиторий в 0:(

РЕШЕНИЕ: Это самый короткий способ избавиться от файлов:

  1. проверьте.git / pack-refs - моя проблема была в том, что у меня там был refs/remotes/origin/master строка для удаленного репозитория, удалите его, иначе git не удалит эти файлы
  2. (необязательный) git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5 - проверить на наличие самых больших файлов
  3. (необязательный) git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98 - чтобы проверить, что это за файлы
  4. git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names' - удалить файл из всех ревизий
  5. rm -rf .git/refs/original/ - удалить резервную копию git
  6. git reflog expire --all --expire='0 days' - истечь все потерянные предметы
  7. git fsck --full --unreachable - проверить наличие незакрепленных предметов
  8. git repack -A -d - переупаковка
  9. git prune - наконец удалить эти объекты

8 ответов

Решение

Я не могу сказать наверняка без доступа к вашим данным репозитория, но я полагаю, что, вероятно, один или несколько упакованных ссылок все еще ссылаются на старые коммиты до того, как вы запустили git filter-branch, Это объясняет, почему git fsck --full --unreachable не называет большой BLOB-объект недостижимым объектом, даже если вы исчерпали свой reflog и удалили исходные (неупакованные) ссылки.

Вот что бы я сделал (после git filter-branch а также git gc было сделано):

1) Убедитесь, что исходные ссылки пропали:

rm -rf .git/refs/original

2) Срок действия всех записей reflog:

git reflog expire --all --expire='0 days'

3) Проверьте старые упакованные ссылки

Это может быть сложно, в зависимости от того, сколько у вас упакованных рефсов. Я не знаю ни одной команды Git, которая автоматизирует это, поэтому я думаю, что вам придется делать это вручную. Сделайте резервную копию .git/packed-refs, Сейчас редактирую .git/packed-refs, Проверьте старые ссылки (в частности, посмотрите, упаковал ли он какие-либо ссылки из .git/refs/original). Если вы найдете старые, которые не должны быть там, удалите их (удалите строку для этой ссылки).

После того, как вы закончите убирать packed-refs файл, посмотрите, если git fsck замечает недоступные объекты:

git fsck --full --unreachable

Если это сработало, и git fsck теперь сообщает, что ваш большой объект недоступен, вы можете перейти к следующему шагу.

4) Упакуйте ваш упакованный архив (ы)

git repack -A -d

Это обеспечит распаковку и недоступность недоступных объектов.

5) обрезать свободные (недостижимые) предметы

git prune

И это должно сделать это. Git действительно должен иметь лучший способ управления упакованными ссылками. Может быть, есть лучший способ, о котором я не знаю. В отсутствие лучшего способа, ручное редактирование packed-refs файл может быть единственным путем.

Я бы порекомендовал использовать BFG Repo-Cleaner, более простую и быструю альтернативу git-filter-branch специально предназначенный для перезаписи файлов из истории Git. Одним из способов облегчения вашей жизни здесь является то, что он фактически обрабатывает все ссылки по умолчанию (все теги, ветви, такие как refs / remotes / origin / master и т. Д.), Но это также в 10-50 раз быстрее.

Вы должны тщательно выполнить следующие шаги здесь: http://rtyley.github.com/bfg-repo-cleaner/ - но основной бит только в этом: загрузите JAR- файл BFG (требуется Java 6 или выше) и выполните эту команду:

$ java -jar bfg.jar  --delete-files file_name  my-repo.git

Любой файл с именем file_name (это не в вашем последнем коммите) будет полностью удалено из истории вашего репозитория. Вы можете использовать git gc чтобы убрать мертвые данные:

$ git gc --prune=now --aggressive

BFG, как правило, гораздо проще в использовании, чем git-filter-branch - параметры адаптированы вокруг этих двух распространенных вариантов использования:

  • Удаление сумасшедших больших файлов
  • Удаление паролей, учетных данных и других личных данных

Полное раскрытие: я являюсь автором BFG Repo-Cleaner.

Я обнаружил, что это очень полезно для удаления всей папки, так как вышеописанное не очень помогло мне: https://help.github.com/articles/remove-sensitive-data.

Я использовал:

git filter-branch -f --force \
--index-filter 'git rm -rf --cached --ignore-unmatch folder/sub-folder' \
--prune-empty --tag-name-filter cat -- --all

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

Я пытался избавиться от большого файла в истории, и вышеупомянутые ответы работали, до определенного момента. Дело в том, что они не работают, если у вас есть теги. Если коммит, содержащий большой файл, доступен из тега, то вам необходимо настроить команду filter-branch таким образом:

git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags

Это должно быть охвачено git obliterate команда в Git Extras ( https://github.com/visionmedia/git-extras).

git obliterate <filename>

У вас есть различные причины все еще большого размера git-репо после git gc, поскольку он не удаляет все незакрепленные предметы.

Я подробно описываю эти причины в " Уменьшить размер репозитория git"

Но один трюк для проверки в вашем случае - клонировать ваше "очищенное" Git-репо и посмотреть, имеет ли клон соответствующий размер.

("очищенным" репо является тот, к которому вы применили filter-branch, а потом gc а также prune)

Смотрите: Как мне удалить конфиденциальные файлы из истории git

Выше не получится, если файл не существует в версии. В этом случае переключатель --ignore-unmatch исправит это:

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD

Затем, чтобы извлечь все свободные объекты из хранилища:

git gc --prune='0 days ago'

У меня была та же проблема, и я нашел отличный учебник по github, который шаг за шагом объясняет, как избавиться от файлов, которые вы случайно зафиксировали.

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

Если у вас есть файл с именем file_to_remove удалить из истории:

cd path_to_parent_dir

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch file_to_remove' \
  --prune-empty --tag-name-filter cat -- --all
Другие вопросы по тегам