Удалить файл из репозитория git (история)
(решено, см. нижнюю часть тела вопроса)
В поисках этого в течение долгого времени, то, что я до сих пор имею:
- http://dound.com/2009/04/git-forever-remove-files-or-folders-from-history/ и
- http://progit.org/book/ch9-7.html
Практически тот же метод, но оба они оставляют объекты в пакетных файлах... Застрял.
Что я пробовал:
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:(
РЕШЕНИЕ: Это самый короткий способ избавиться от файлов:
- проверьте.git / pack-refs - моя проблема была в том, что у меня там был
refs/remotes/origin/master
строка для удаленного репозитория, удалите его, иначе git не удалит эти файлы - (необязательный)
git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5
- проверить на наличие самых больших файлов - (необязательный)
git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98
- чтобы проверить, что это за файлы git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names'
- удалить файл из всех ревизийrm -rf .git/refs/original/
- удалить резервную копию gitgit reflog expire --all --expire='0 days'
- истечь все потерянные предметыgit fsck --full --unreachable
- проверить наличие незакрепленных предметовgit repack -A -d
- переупаковка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