Удалите большой файл .pack, созданный git


112

Я проверил загрузку файлов в ветке и объединил их, а затем пришлось удалить их, и теперь у меня остался большой файл .pack, от которого я не знаю, как избавиться.

Я удалил все файлы с помощью git rm -rf xxxxxxи также запустил эту --cachedопцию.

Может ли кто-нибудь сказать мне, как я могу удалить большой файл .pack, который в настоящее время находится в следующем каталоге:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

Мне просто нужно удалить ветку, которая у меня еще есть, но больше не используется? Или мне нужно что-то еще запустить?

Я не уверен, насколько это важно, но он показывает замок напротив файла.

Спасибо


РЕДАКТИРОВАТЬ

Вот несколько отрывков из моей bash_history, которые должны дать представление о том, как мне удалось попасть в это состояние (предположим, что на данный момент я работаю над веткой git под названием 'my-branch', и у меня есть папка, содержащая больше папок / файлы):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

Я думал, что также выполнил следующее, но оно не отображается в bash_history с другими:

git rm -rf --cached unwanted_folder/

Я также подумал, что запустил несколько команд git (например git gc), чтобы попытаться привести в порядок файл пакета, но они также не отображаются в файле .bash_history.


Можете уточнить, как вы их удалили? Если они все еще находятся в истории коммитов, значит, они все еще находятся в ваших файлах пакета.
loganfsmyth

Привет @loganfsmyth, я добавил сценарии истории bash, которые, надеюсь, помогут.
user1116573

Ответы:


201

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

То, что вы хотите сделать, называется перезаписью истории, и в ней задействована git filter-branchкоманда.

У GitHub есть хорошее объяснение проблемы на своем сайте. https://help.github.com/articles/remove-sensitive-data

Чтобы ответить на ваш вопрос более прямо, вам в основном нужно запустить эту команду с unwanted_filename_or_folderсоответствующей заменой:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

Это удалит все ссылки на файлы из активной истории репо.

Следующий шаг, чтобы выполнить цикл GC, чтобы все ссылки на файл истекли и были удалены из файла упаковки. В этих командах ничего заменять не нужно.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
Я пометил его как принятый, если это облегчит любому, кто придет к этому вопросу в будущем, хотя я фактически решил свою проблему в то время, создав свежий
репозиторий

3
Я не знаю, как ты это сделал, но ... Ты мужчина. Спасибо.
Иезекииль Виктор

5
Этот ответ указал мне правильное направление. Но для фактического удаления файлов необходимы еще 3 команды 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod

3
Мне bfgгораздо проще пользоваться. Это также рекомендуется в официальных документах на github: help.github.com/articles/…
Тимо

2
@Timo Хорошо бы добавить новый ответ, если со временем что-то изменилось. Действуй!
loganfsmyth 03

12

Сценарий А. Если ваши большие файлы были добавлены только в ветку, запускать не нужно git filter-branch. Вам просто нужно удалить ветку и запустить сборку мусора:

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

Сценарий B : Однако, судя по вашей истории bash, вы действительно слили изменения в master. Если вы никому не поделились изменениями ( git pushпока нет ). Проще всего было бы сбросить мастер обратно до слияния с веткой, в которой были большие файлы. Это устранит все коммиты из вашей ветки и все коммиты, сделанные для мастера после слияния. Таким образом, вы можете потерять изменения - в дополнение к большим файлам - которые вы действительно хотели:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

Затем выполните шаги из сценария A.

Сценарий C : если после слияния были другие изменения из ветки или изменения на главном сервере, которые вы хотите сохранить, было бы лучше перебазировать мастер и выборочно включить те коммиты, которые вы хотите:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

В своем редакторе удалите строки, соответствующие коммитам, добавившим большие файлы, но оставьте все остальное как есть. Сохранить и выйти. Ваша основная ветка должна содержать только то, что вы хотите, и никаких больших файлов. Обратите внимание, что git rebaseбез -pисключения коммиты слияния будут исключены, поэтому после этого у вас останется линейная история для мастера <commit hash>. Возможно, это нормально для вас, но если нет, вы можете попробовать -p, но git help rebaseговорит combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Затем запустите команды из сценария A.


Там есть вариант сценария А здесь с, однако, дополнительный неожиданный вопрос.

Сценарий Решенная моя проблема, удаление большого количества временного файла пакета. Репозиторий управлялся сервером сборки, и это вызывает нежелательное создание файлов внутри папки .git / objects / pack. Я мог освободить ценные ГБ со своего диска.
xrissz

7

Как уже было сказано в ответе loganfsmyth , вам нужно очистить историю git, потому что файлы продолжают существовать там даже после удаления их из репо. Официальные документы GitHub рекомендуют BFG, который я считаю более простым в использовании, чем filter-branch:

Удаление файлов из истории

Загрузите BFG с их сайта. Убедитесь, что у вас установлена ​​Java, затем создайте зеркальный клон и очистите историю. Обязательно замените YOUR_FILE_NAMEимя файла, который хотите удалить:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

Удалить папку

То же, что и выше, но используйте --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

Другие варианты

BFG также позволяет использовать еще более изящные варианты (см. Документацию ), например:

Удалите из истории все файлы размером более 100 МБ:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

Важный!

При запуске BFG будьте осторожны, чтобы оба YOUR_FILE_NAMEи YOUR_FOLDER_NAMEдействительно были просто именами файлов / папок. Это не пути , поэтому что-то вроде foo/bar.jpgне сработает! Вместо этого все файлы / папки с указанным именем будут удалены из истории репо, независимо от того, какой путь или ветка они существовали.


Интересно, хочу ли я применить этот bfgинструмент к локальному репозиторию git, как должна выглядеть команда?
Ангел Тодоров

5

Один вариант:

запускать git gcвручную, чтобы сжать несколько файлов пакетов в один или несколько файлов пакетов. Эта операция является постоянной (то есть файл большого пакета сохранит свое поведение при сжатии), поэтому может быть полезно периодически сжимать репозиторий с помощьюgit gc --aggressive

Другой вариант - сохранить где-нибудь код и .git, а затем удалить .git и снова начать использовать этот существующий код, создав новый репозиторий git ( git init).


Привет, Майкл, я попытался запустить git gcи получил всего пару файлов пакета, но большой по-прежнему один из них, и я просто хотел бы избавиться от него, чтобы мне было проще сделать резервную копию папки извне (раньше zip был 1 -2Мб, сейчас 55Мб). Если кто-то не может предложить что-то еще, я думаю, мне придется создать новый git. Я предполагаю, что это означает, что я потеряю доступ к веткам, которые у меня есть, и т. Д.?
user1116573

2
Я отказался от попыток и просто удалил папку .git и создал новый репозиторий git, как вы сказали. Я буду считать это усвоенным уроком. Спасибо, Майкл.
user1116573

4
В этом нет особого смысла. Почему вы не можете просто сказать git, чтобы он консолидировал текущий репозиторий и удалил файлы пакета в процессе?
jml

4

Выполните следующую команду, заменив PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAее путем к файлу, который вы хотите удалить, а не только его именем. Эти аргументы будут:

  1. Заставить Git обрабатывать, но не проверять, всю историю каждой ветки и тега
  2. Удалите указанный файл, а также любые пустые коммиты, созданные в результате
  3. Перезаписать существующие теги
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

Это принудительно удалит все ссылки на файлы из активной истории репо.

Следующий шаг, чтобы выполнить цикл GC, чтобы все ссылки на файл истекли и были удалены из файла пакета. В этих командах ничего заменять не нужно.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

Наконец, со второй части я получил репо с 28G до 158M. Больше ничего в гугле не работало. Спасибо.
Шридхар Сарнобат

Я выполнил вышеуказанные шаги и нажал «git push origin --force --all», но мои удаленные ветки (master, development и feature / ASD-1010) все равно не очистились. Когда я только что клонировал из удаленного репо, файлы .pack все еще присутствовали. Как я могу отразить эту очистку во всех удаленных ветках git?
Самбит Суэйн,

1

Я немного опаздываю на шоу, но если приведенный выше ответ не помог решить вопрос, я нашел другой способ. Просто удалите конкретный большой файл из .pack. У меня была эта проблема, когда я случайно зарегистрировал большой файл размером 2 ГБ. Я выполнил шаги, описанные в этой ссылке: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


После выполнения этого метода он полностью удалит всю историю проекта или просто удалит указанный файл.
Самим Афтаб Ахмед

-3

это больше удобное решение, чем кодирование. заархивируйте файл. Откройте zip-архив в формате просмотра файла (отличном от формата распаковки). Удалите файл .pack. Разархивируйте и замените папку. Работает как шарм!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.