Видаліть великий .pack файл, створений git


112

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

Я видалив усі файли за допомогою, git rm -rf xxxxxxа також запустив --cachedваріант.

Хтось може сказати мені, як я можу видалити великий .pack файл, який зараз знаходиться в наступній папці:

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

Чи потрібно просто видалити гілку, яку я все ще маю, але більше не використовую? Або ще щось мені потрібно бігти?

Я не впевнений, наскільки це різниця, але він показує замок проти файлу.

Дякую


EDIT

Ось кілька уривків з моєї bash_history, які мають дати уявлення про те, як мені вдалося потрапити в цей стан (припустимо, на даний момент я працюю над гіткою git під назвою "моя-гілка" і в мене є папка, що містить більше папок / файли):

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, я додав сценарії історії башів, які, сподіваюся, допоможуть.
користувач1116573

Відповіді:


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, щоб змусити закінчити термін дії всіх посилань на файл та видалити його з файлу packfile. У цих командах нічого не потрібно замінювати.

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

12

Сценарій A : Якщо ваші великі файли були додані лише до гілки, вам не потрібно запускати git filter-branch. Вам просто потрібно видалити гілку та запустити збір сміття:

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

Сценарій В : Однак, виходячи з вашої історії башів, схоже, що ви зробили зміни в головний. Якщо ви ні з ким не поділилися змінами ( git pushще ні ). Найпростіше було б скинути master назад до об'єднання з гілкою, яка мала великі файли. Це призведе до виключення всіх комісій з вашої філії та всіх зобов'язань, зроблених для керування після злиття. Таким чином, ви можете втратити зміни - окрім великих файлів -, яких ви, можливо, хотіли:

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

Потім виконайте кроки зі сценарію А.

Сценарій C : Якщо в результаті об'єднання, яке ви хочете зберегти, відбулися інші зміни в гілці або зміни в магістралі, найкраще буде перезавантажити головний і вибірково включити потрібні комісії:

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

У своєму редакторі видаліть рядки, які відповідають комісіям, які додали великі файли, а все інше залиште таким, як є. Збережіть і закрийте. Ваша головна гілка повинна містити лише те, що ви хочете, і не має великих файлів. Зауважте, що git rebaseбез -pусунення комірок злиття, тому вам залишиться лінійна історія для master після <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.

Потім запустіть команди зі сценарію А.


Там є варіант сценарію А тут с, однак, додатковий несподіване запитання.

Сценарій Вирішена проблема з моєю видаленням великої кількості файлів тимчасової упаковки. Репозиторієм керував сервер збирання, і це викликає небажане створення файлів у папці .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 repo, як повинна виглядати команда?
Ангел Тодоров

5

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

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

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


Привіт Майкл, я спробував запустити git gcі дійшов до декількох пакувальних файлів, але великий все ще один з них, і я просто хотів би позбутися від нього, щоб я міг зробити резервну копію папки зовнішньо (ZIP раніше було 1 -2Mb, зараз 55Mb). Якщо хтось не може щось запропонувати, я думаю, що мені доведеться створити свіжий git. Я припускаю, що це означає, що я втрачу доступ до гілок, які у мене зараз є тощо ...?
користувач1116573

2
Я відмовився від спроби і просто видалив папку .git і створив нове сховище git, як ви сказали. Я вважатиму це вивченим уроком. Дякую Майклу.
користувач1116573

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

Нарешті з 2-ї частини я отримав репост 28G до 158M. Майже нічого в Google не працювало. Дякую.
Шрідхар Сарнобат

Я дотримувався вищезазначених кроків і натиснув, як "git push origin --force --all", і все ж мої віддалені відділення (майстер, розробка та функція / ASD-1010) не очистилися. Коли я свіжий клонувався з віддаленого репо, файли в ньому .pack все ще були присутні. Як я можу відобразити це очищення до всіх віддалених гілок git ??
Сембіт Свен

1

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


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

-3

це скоріше зручне рішення, ніж кодування. зафіксуйте файл. Відкрийте блискавку у форматі перегляду файлів (відмінний від розпакування). Видаліть .pack файл. Розпакуйте та замініть папку. Працює як шарм!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.