Видалити файл зі сховища git (історія)


78

(вирішено, див. нижню частину корпусу питання)
Шукаю це вже давно, і я маю до цього часу:

Приблизно той самий метод, але обидва вони залишають об'єкти у файлах пакунків ... Застрягли.
Що я спробував:

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 / packed-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 - остаточно видалити ці предмети


zneak - моє питання в заголовку. gbacon - спробував, файли все ще залишаються у файлі пакету ...
Борис Чурзін

Якщо ви подивитесь на статтю, на яку посилаються копії, вона показує, як ущільнити сховище об’єктів після видалення файлу-порушника.
Кайл Батт

1
Це була паличка-виручалочка. Психічне зауваження: завжди додавайте потенційно величезні файли * .log до .gitignore. Після цього перейшов від 800 Мб репо до 6 Мб.
JackCA

1
крок 2 і 3 в одному for i in `git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5` ; do git rev-list --objects --all | grep $(echo $i | sed 's/ .*//g') ; done
geermc4

Відповіді:


65

Я не можу сказати напевно без доступу до даних вашого сховища, але я вважаю, що, ймовірно, є одне або декілька упакованих посилань, які все ще посилаються на старі коміти до того, як ви запускали git filter-branch. Це пояснювало б чомуgit fsck --full --unreachable велика крапка не називається недосяжним об’єктом, навіть якщо ви закінчили термін дії перезапису та видалили оригінальні (розпаковані) посилання.

Ось що я б зробив (після того, як git filter-branchі git gcщо було зроблено):

1) Переконайтесь, що оригінальні посилання зникли:

rm -rf .git/refs/original

2) Термін дії всіх записів перезапису закінчується:

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файлу може бути єдиним шляхом.


1
Так !!! Я тебе люблю ! Проблема була у файлі packed-refs, там був refs / remotes / origin / master ще раз, коли я робив резервну копію на якомусь сервері ... як тільки я видалив це все почало зникати ... Дякую! (оновлення тіла питання з повним рішенням)
Борис Чурзін 02

15

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

Вам слід уважно виконати ці кроки тут: http://rtyley.github.com/bfg-repo-cleaner/#usage - але основний біт якраз такий: завантажте 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.


Чи також це очищає приватні дані з віддалених репозиторіїв після натискання?
Thomas Lauria

@ThomasLauria так, ті самі очищені посилання надсилаються у віддалені репозиторії при натисканні - інструкції на rtyley.github.io/bfg-repo-cleaner/#usage повинні це охоплювати. Якщо у вас є контроль над віддаленим репо, ви також можете запустити на ньому "git gc --prune = now --aggressive" після натискання, щоб забезпечити негайне видалення мертвих об'єктів з нього.
Роберто Тайлі

@RobertoTyley Це може призвести до двох комітів, які з’являються один за одним в історії та мають одне і те ж дерево (якщо один із цих комітів лише додав видалені файли). Чи знаєте ви простий спосіб видалити такі коміти з історії комітів, оскільки вони здаються штучними?
user44400

@RobertoTyley Я думаю, що це стосується іншого питання. У справі, яку я описав, бере участь лише одне сховище. Але, git filter-branch --prune-emptyсхоже, це рішення мого питання (хоча, використовуючи інший інструмент, будь ласка, дайте мені знати, чи зможе BFG Repo-Cleaner зробити те саме).
user44400

6

Я виявив, що це дуже корисно щодо видалення цілої папки, оскільки вищесказане мені насправді не допомогло: 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

Я намагався позбутися великого файлу в історії, і наведені вище відповіді працювали до певного моменту. Справа в тому, що вони не працюють, якщо у вас є теги. Якщо коміт, що містить великий файл, доступний з тегу, то вам потрібно буде таким чином відрегулювати команду filter-branch:

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

2

Дивіться: Як видалити конфіденційні файли з історії git

Вищезазначене не вдасться, якщо файл не існує у версії rev. У такому випадку перемикач '--ignore-unmatch' це виправить:

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

Потім, щоб витягти всі вільні предмети з репості:

git gc --prune='0 days ago'

Так, спробував цей, файли все ще є в пачці, і розмір не сильно змінився ...
Борис Чурзін

Я просто зробив пісочницю git і спробував. Тут теж нічого хорошого. Давайте подивимось, що я можу зрозуміти.
Wayne Conrad

Той, що у відповіді? :) Це те саме, що я розмістив, і він все одно залишає файл у пакеті ... спробуйте пісочницю git, виконуючи git gc, щоб він запакував файл, а потім запустив це ...
Борис Чурзін

О, вільні предмети? Дивись вище. Я був би схильний просто дозволити їм збирати сміття за два тижні (за замовчуванням для gc); вбивати всі вільні предмети - це все одно, що звільнити сміття - я втрачаю можливості повернути все, що випадково видалив.
Wayne Conrad

:) спробував і цей ... позбувся деяких файлів, але найбільші все ще там ...
Борис Чурзін

2

У вас є різні причини для великого розміру репозиторію git після git gc, оскільки він не видаляє всі вільні об'єкти .

Я детально описую ці причини в " зменшенні розміру сховища git "

Але одним трюком для перевірки у вашому випадку було б клонування вашого "очищеного" репозиторію Git і перевірку, чи має клон відповідний розмір.

("" очищений "репо - це той, де ви застосовували filter-branch, а потім gcі prune)


Так, протестував вже і перевірив ще раз зараз, це зменшило сховище на 2k :) і файли все ще там ...
Борис Чурзін

Що дивно, git count-objects -v -> count: 0, size: 0, in-pack: 10021, packs: 1, size-pack: 244547, prune-packable: 0, garbage: 0але:git clone test1 test2 -> Checking out files: 100% (8509/8509), done
Борис Чурзін


1

У мене була та сама проблема, і я знайшов чудовий підручник з 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

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