Удалить файл из репозитория git (история) - PullRequest
76 голосов
/ 29 января 2010

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

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

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 ]

64 голосов
/ 01 февраля 2010

Я не могу сказать наверняка без доступа к вашим данным репозитория, но я полагаю, что, вероятно, есть один или несколько упакованных ссылок, которые все еще ссылаются на старые коммиты до того, как вы запустили 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.

15 голосов
/ 02 апреля 2013

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

Вы должны внимательно выполнить следующие шаги: http://rtyley.github.com/bfg-repo-cleaner/#usage - но основной бит такой: скачайте банку 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.

6 голосов
/ 20 марта 2013

Я обнаружил, что это очень полезно для удаления всей папки, так как приведенное выше не очень мне помогло: 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
5 голосов
/ 19 апреля 2012

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

git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags
2 голосов
/ 29 января 2010

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

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

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

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

git gc --prune='0 days ago'
1 голос
/ 26 марта 2013

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

git obliterate <filename>
1 голос
/ 01 февраля 2010

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

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

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

(«очищенный» репо - тот, к которому вы применили filter-branch, а затем gc и prune)

0 голосов
/ 12 марта 2013

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