Як видалити / видалити великий файл із історії фіксацій у сховищі Git?


708

Інколи я кидав DVD-ріп в проект веб-сайту, потім недбало git commit -a -m ..., і, зап, репо було роздуто на 2,2 гіга. Наступного разу я вніс кілька змін, видалив відео-файл і все зробив, але стислий файл все ще є в сховищі, в історії.

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


9
Ця стаття повинна допомогти вам допомогти.github.com/ removing-sensitive-data
MBO


1
Зауважте, що якщо ваш великий файл знаходиться у підкаталозі, вам потрібно вказати повний відносний шлях.
Йоган

1
Також пов’язана допомога.github.com
en/

Багато відповідей нижче, ніж BFG простіше, ніж git filter-branchя, але я вважав, що навпаки є правдою.
2540625

Відповіді:


605

Використовуйте BFG Repo-Cleaner , більш просту та швидку альтернативу, git-filter-branchспеціально розроблену для видалення непотрібних файлів з історії Git.

Уважно дотримуйтесь інструкцій із використання , основна частина - саме це:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

Будь-які файли розміром понад 100 Мб (які не належать до останньої комісії) будуть видалені з історії вашого сховища Git. Потім можна використовувати git gcдля очищення мертвих даних:

$ git gc --prune=now --aggressive

BFG, як правило, принаймні на 10-50 разів швидший, ніж біг git-filter-branch, і, як правило, простіший у використанні.

Повне розкриття інформації: Я є автором BFG Repo-Cleaner.


4
@tony Варто повторити всю процедуру клонування та очищення, щоб побачити, чи не з’являється повідомлення з проханням витягнути повторно, але це майже напевно, тому що ваш віддалений сервер налаштований на відхилення нешвидкісних оновлених оновлень (тобто налаштований так, щоб зупинити вас від втрати історії - це саме те, що ви хочете зробити). Потрібно змінити цей параметр на пульті дистанційного керування або, якщо цього не вдалося, підсунути оновлену історію репо до абсолютно нового порожнього репо.
Роберто Тілей

1
@RobertoTyley Дякую Я спробував це 3 різні рази, і все вийшло з тим самим повідомленням. Тому я також думаю, що ти маєш рацію щодо віддаленого сервера, який налаштований на відхилення нешвидкісних оновлень. Я вважаю, що просто підштовхнути оновлене репо до абсолютно нового репо. Дякую!
Тоні

7
@RobertoTyley Чудово, ви заощадите мій час, дуже дякую. До речі, можливо, це слід зробити git push --forceпісля ваших кроків, інакше віддалений репо все ще не змінився.
li2

3
+1 до додавання git push --force. Також варто відзначити: віддалені сили можуть не дозволяти віддалений (за замовчуванням gitlab.com не дозволяє. Довелося "зняти захист" гілки).
MatrixManAtYrService

25
Я думаю, що жаргон Трампа інструменти виводить трохи.
Кріс

564

Те, що ви хочете зробити, є дуже руйнівним, якщо ви опублікували історію іншим розробникам. Про необхідні кроки після відновлення історії див. Розділ «Відновлення з верхньої версії» в git rebaseдокументації .

У вас є щонайменше два варіанти: git filter-branchта інтерактивна база даних, обидва пояснені нижче.

Використання git filter-branch

У мене була схожа проблема з об'ємними даними бінарних тестів із імпорту Subversion, і я писав про видалення даних із сховища git .

Скажімо, ваша історія git така:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Зауважте, що git lolaце нестандартний, але дуже корисний псевдонім. За допомогою --name-statusперемикача ми можемо побачити модифікації дерева, пов’язані з кожним комітом.

У комітеті "Недбале" (чиє ім'я об'єкта SHA1 це ce36c98) файл oops.iso- це DVD-рип, доданий випадково та видалений у наступній комісії, cb14efd. Використовуючи техніку, описану у вищезгаданому дописі блогу, командою для виконання є:

git filter-branch --prune-empty -d /dev/shm/scratch \
  --index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
  --tag-name-filter cat -- --all

Параметри:

  • --prune-emptyвидаляє коміти, які стають порожніми ( тобто не змінюють дерево) в результаті роботи фільтра. У типовому випадку ця опція дає більш чисту історію.
  • -dназиває тимчасовий каталог, який ще не існує для використання для побудови відфільтрованої історії. Якщо ви працюєте на сучасному дистрибутиві Linux, вказівка дерева в дереві /dev/shmпризведе до швидшого виконання .
  • --index-filterє основною подією та працює проти індексу на кожному кроці історії. Ви хочете видалити, oops.isoде б він не був знайдений, але він присутній у всіх комісіях. Команда git rm --cached -f --ignore-unmatch oops.isoвидаляє DVD-рип, коли він присутній, і не виходить з ладу.
  • --tag-name-filterописується, як переписати імена тегів. Фільтр cat- це операція ідентичності. У вашому сховищі, як і в наведеному вище прикладі, може не бути тегів, але я включив цю опцію для повної загальності.
  • -- вказує кінець параметрів для git filter-branch
  • --allдалі --- стенограма для всіх посилань. У вашому сховищі, як і в наведеному вище зразку, може бути лише одна посилання (головний), але я включив цю опцію для повної загальності.

Після певного розбиття історія зараз:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A   login.html
| * cb14efd Remove DVD-rip
| | D   oops.iso
| * ce36c98 Careless
|/  A   oops.iso
|   A   other.html
|
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Зауважте, що новий комітет "Недбале" додає лише other.htmlте, що команда "Видалити DVD-видобуток" більше не знаходиться на головній гілці. Позначена гілка refs/original/refs/heads/masterмістить ваші оригінали, якщо ви допустили помилку. Щоб видалити його, виконайте кроки в "Контрольний список для зменшення сховища".

$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now

Для більш простої альтернативи клонуйте сховище, щоб відкинути небажані біти.

$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo

Використання file:///...URL-адреси клонування копіює об'єкти, а не створює лише жорсткі посилання.

Тепер ваша історія:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Імена об'єктів SHA1 для перших двох комітетів ("Індекс" та "Сторінка адміністратора") залишилися однаковими, оскільки операція фільтрації не змінила цих комісій. «Careless» втратив oops.isoі «Логін сторінка» отримали новий батько, так що їх SHA1s зробив зміни.

Інтерактивна база даних

З історією:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

ви хочете видалити oops.isoз "Недбалого" так, ніби ви його ніколи не додавали, і тоді "Видалити DVD-rip" для вас марний. Таким чином, наш план переходить до інтерактивної бази даних - це зберегти "сторінку адміністратора", відредагувати "Недбало" та відмовитись "Видалити DVD-rip".

Запуск $ git rebase -i 5af4522запускає редактор із наступним вмістом.

pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Виконуючи наш план, ми його модифікуємо

edit ce36c98 Careless
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
# ...

Тобто, ми видаляємо рядок із "Видалити DVD-rip" і змінюємо операцію на "Недбале", editа не на pick.

Збереження-вихід із редактора скидає нас у командний рядок із наступним повідомленням.

Stopped at ce36c98... Careless
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

Як повідомляється в повідомленні, ми перебуваємо на «необережному» зобов'язанні, яке ми хочемо відредагувати, тому ми виконуємо дві команди.

$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue

Перший видаляє обраний файл з індексу. Другий модифікує або доповнює "Недбалий", щоб бути оновленим покажчиком, і -C HEADвказує git повторно використовувати старе повідомлення. Нарешті, git rebase --continueйде вперед з рештою операції ребасті.

Це дає історію:

$ git lola --name-status
* 93174be (HEAD, master) Login page
| A     login.html
* a570198 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

що ви хочете.


4
Чому я не можу натиснути при використанні гіт-фільтр-філії, не вдалося натиснути кілька посилань на 'git@bitbucket.org: product / myproject.git' Щоб уникнути втрати історії, відхилені нешвидкі перемотки вперед Об’єднайте пульт зміни, перш ніж знову натиснути.
Agung Prasetyo

11
Додайте до своєї команди опцію -f(або --force) git push: "Зазвичай команда відмовляється від оновлення віддаленого ref, який не є родоначальником локального ref, використовуваного для його заміни. Цей прапор відключає чек. Це може призвести до втрати віддаленого сховища комісій; використовуйте це обережно ».
Грег Бекон

5
Це дивовижно ґрунтовна відповідь, що пояснює використання git-filter-гілки для видалення небажаних великих файлів з історії, але варто зазначити, що після написання своєї відповіді Грег вийшов BFG Repo-Cleaner, який часто швидше і простіше використання - див. мою відповідь для деталей.
Роберто Тілей

1
Після того, як я виконую будь-яку з описаних вище процедур, віддалений сховище (на GitHub) НЕ видаляє великий файл. Тільки місцеві. Я змушую натискати і нада. Що я пропускаю?
азатар

1
це також працює на дрірах. ... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop

198

Чому б не використати цю просту, але потужну команду?

git filter-branch --tree-filter 'rm -f DVD-rip' HEAD

--tree-filterОпція запускає вказану команду після кожної перевірки проекту , а потім знову заявляють результати. У цьому випадку ви видаляєте файл під назвою DVD-rip із кожного знімка, незалежно від того, існує він чи ні.

Якщо ви знаєте, яка фіксація запровадила величезний файл (скажімо, 35dsa2), ви можете замінити HEAD на 35dsa2..HEAD, щоб уникнути перезаписування занадто багато історії, тим самим уникаючи розбіжних комітетів, якщо ви ще не натиснули. Цей коментар ввічливий @ alpha_989 здається занадто важливим, щоб залишати його тут.

Дивіться це посилання .


3
Це хороше рішення! Я створив історію, у якій є сценарій python для переліку файлів & git cmd, який видалить файл, який ви хочете очистити gist.github.com/ariv3ra/16fd94e46345e62cfcbf
punkdata

5
Набагато краще, ніж bfg. Я не зміг очистити файл із git за допомогою bfg, але ця команда допомогла
podarok

4
Це чудово. Лише зауваження для інших, що вам доведеться робити це для кожної гілки, якщо великий файл знаходиться в декількох гілках.
Джеймс

2
У Windows я отримав fatal: bad revision 'rm', що я виправив, використовуючи "замість '. Загальна команда:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
marcotama

2
Якщо ви знаєте, commitде ви помістіть файл в (скажімо 35dsa2), ви можете замінити HEADз 35dsa2..HEAD. tree-filterнабагато повільніше, ніж index-filterтаким чином, ми не будемо намагатися перевірити всі комісії та переписати їх. якщо ви використовуєте HEAD, він спробує це зробити.
alpha_989

86

(Найкраща відповідь, яку я бачив на цю проблему, це: https://stackoverflow.com/a/42544963/714112 , скопійований тут, оскільки ця нитка виявляється високо в рейтингу пошуку Google, але інша - ні)

One Світло-швидкий одноколісний корпус оболонки 🚀

Цей скрипт оболонки відображає всі об'єкти blob у сховищі, відсортовані від найменшого до найбільшого.

Для мого зразка репо, він пробіг приблизно в 100 разів швидше, ніж інші, знайдені тут.
У моїй надійній системі Athlon II X4 він обробляє сховище Linux Kernel зі своїми 6 622 155 об’єктами за трохи більше хвилини .

Базовий сценарій

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort --numeric-sort --key=2 \
| cut --complement --characters=13-40 \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

Запустивши вище коду, ви отримаєте приємний для читання людський вихід такий:

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

Швидке видалення файлів 🚀

Припустимо, ви хочете вилучити файли, aі bз кожного доступу, з якого можна дістатися HEAD, ви можете використовувати цю команду:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD

3
Якщо у вашому РЕПО є якісь теги, ви, ймовірно, також хочете додати прапор, --tag-name-filter catщоб повторно позначити нові відповідні комісії під час переписування, тобто git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD(див. Відповідну відповідь )
naitsirhc

3
Інструкції для Mac та деякі інші відомості з'являються в оригінальному пов'язаному пості
nruth

3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADПраворуч біту
вказівника

моя улюблена відповідь. невеликий твік для використання на mac os (використовуючи команди gnu)git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Флоріан Освальд

класний сценарій із списком rev, але він не працював для мене як псевдонім, будь-яка ідея, як це зробити?
Робін Манолі

47

Спробувавши практично кожну відповідь в SO, я нарешті знайшов цей дорогоцінний камінь, який швидко видалив і видалив великі файли з мого сховища і дозволив мені знову синхронізувати: http://www.zyxware.com/articles/4027/how-to-delete -файли-постійно-з-ваш-локальний-та-віддалений-git-сховища

CD у свою локальну робочу папку та запустіть таку команду:

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all

замініть FOLDERNAME на файл або папку, яку ви хочете видалити із заданого сховища git.

Після цього запустіть наступні команди для очищення локального сховища:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

Тепер натисніть всі зміни до віддаленого сховища:

git push --all --force

Це очистить віддалений сховище.


Працювало як шарм для мене.
Рамон Васкончелос

3
Це працювало і для мене. Позбавляє певної папки (у моєму випадку - файлу, яка містила файли занадто великі, або рето Github) у сховищі, але зберігає її у локальній файловій системі, якщо вона існує.
skizzo

Працювали для мене! не залишається жодна історія, яка потенційно може заплутати (якщо хтось зараз
клонується

38

Ці команди працювали в моєму випадку:

git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --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

Він мало відрізняється від вищезазначених версій.

Для тих, кому потрібно натиснути це на github / bitbucket (я протестував це лише за допомогою bitbucket):

# WARNING!!!
# this will rewrite completely your bitbucket refs
# will delete all branches that you didn't have in your local

git push --all --prune --force

# Once you pushed, all your teammates need to clone repository again
# git pull will not work

4
Чим він відрізняється згори, чому це краще?
Енді Хайден

1
Чомусь версія mkljun у моєму випадку не зменшує простір git, я вже видалив файли з індексу за допомогою git rm --cached files. Пропозиція Грега Бекона є більш повною і цілком однаковою до цієї шахти, але він пропустив - індекс сили для тих випадків, коли ви використовуєте фільтр-гілку кілька разів, і він написав стільки інформації, що моя версія схожа на резюме з нього.
Костанос

1
Це дійсно допомогло, але мені потрібно було скористатись -fне лише -rfтут, git rm --cached -rf --ignore-unmatch oops.isoа замість git rm --cached -r --ignore-unmatch oops.isoper @ lfender6445 нижче
drstevok

10

Тільки зауважте, що ці команди можуть бути дуже руйнівними. Якщо більше людей працює над репо, їм доведеться витягнути нове дерево. Три середні команди не потрібні, якщо ваша мета НЕ зменшити розмір. Оскільки гілка фільтра створює резервну копію видаленого файлу, і він може залишатися там тривалий час.

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

11
НЕ виконайте ці команди, якщо ви не хочете створити для себе величезний біль. Він видалив багато моїх оригінальних файлів вихідного коду. Я припускав, що вона видалить деякі великі файли з моєї історії фіксації в GIT (відповідно до оригінального питання), однак, я думаю, що ця команда призначена для постійної очищення файлів з вашого початкового дерева вихідного коду (велика різниця!). Моя система: Windows, VS2012, постачальник управління джерелами Git.
Контанго

2
Я використав цю команду: git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --allзамість першого з вашого коду
Костанос

9

git filter-branch --tree-filter 'rm -f path/to/file' HEAD працював для мене досить добре, хоча я зіткнувся з тією ж проблемою, що описана тут , яку я вирішив, дотримуючись цієї пропозиції .

У книзі про-git є ціла глава про історію перезапису - ознайомтеся з filter-branch/ Видаленням файлу з кожного розділу комісій .


8

Якщо ви знаєте, що ваш вчинок був нещодавним, а не переглядати все дерево, зробіть наступне: git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD


7

Я наткнувся на це з обліковим записом bitbucket, де я випадково зберігав ginormous * .jpa резервні копії свого сайту.

git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all

Розмістіться MY-BIG-DIRECTORYз відповідною папкою, щоб повністю переписати свою історію ( включаючи теги ).

джерело: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/


1
Ця відповідь мені допомогла, за винятком того, що сценарій у відповіді має незначне питання, і він шукає не у всіх галузях, що формуються у мене. Але команда у посиланні зробила це чудово.
Алі Б

5

Це видалить його з вашої історії

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all

Це працювало для мене спасибі !!
Sonja Brits

Це працює в моєму випадку. Я запускаю це на вашій головній гілці.
С. Доменг

4

Я в основному зробив те, що було на цій відповіді: https://stackoverflow.com/a/11032521/1286423

(для історії я скопію це вставлення тут)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

Це не вийшло, тому що мені подобається багато перейменовувати та переміщувати речі. Так що великий файл був у папках, які були перейменовані, і я думаю, що gc не міг видалити посилання на ці файли через посилання в treeоб'єктах, що вказують на цей файл. Моє остаточне рішення справді вбити це було:

# First, apply what's in the answer linked in the front
# and before doing the gc --prune --aggressive, do:

# Go back at the origin of the repository
git checkout -b newinit <sha1 of first commit>
# Create a parallel initial commit
git commit --amend
# go back on the master branch that has big file
# still referenced in history, even though 
# we thought we removed them.
git checkout master
# rebase on the newinit created earlier. By reapply patches,
# it will really forget about the references to hidden big files.
git rebase newinit

# Do the previous part (checkout + rebase) for each branch
# still connected to the original initial commit, 
# so we remove all the references.

# Remove the .git/logs folder, also containing references
# to commits that could make git gc not remove them.
rm -rf .git/logs/

# Then you can do a garbage collection,
# and the hidden files really will get gc'ed
git gc --prune --aggressive

Мій репо (the .git) змінився з 32MB на 388KB, що навіть фільтр-філія не міг очистити.


4

git filter-branchце потужна команда, за допомогою якої можна видалити величезний файл з історії комісій. Файл залишиться на деякий час, і Git видалить його в наступному сміттєзбірнику. Нижче наведено повний процес видалення файлів з історії фіксації . Для безпеки нижче процес спочатку запускає команди на новій гілці. Якщо результат - те, що вам було потрібно, поверніть його назад до гілки, яку ви насправді хочете змінити.

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master

2

Використовуйте розширення Git , це інструмент інтерфейсу користувача. У ньому є плагін під назвою "Знайти великі файли", який знаходить файли лагів у сховищах і дозволяє видаляти їх постійно.

Не використовуйте 'git filter-branch' перед тим, як скористатися цим інструментом, оскільки він не зможе знайти файли, вилучені "filter-branch" (Хоча "filter-branch" не видаляє файли повністю з файлів пакета репозиторію) .


Цей метод занадто повільний для великих сховищ. Щоб перерахувати великі файли, знадобилося більше години. Потім, коли я переходжу до видалення файлів, через годину це лише 1/3 шляху через обробку першого файлу, який я хочу видалити.
Крістіанп

Так, це повільно, але чи працює ... Чи знаєте ви щось швидше?
Нір

1
Не використовував його, але BFG Repo-Cleaner, відповідно до іншої відповіді на цій сторінці.
Крістіанп

2

Це можна зробити за допомогою branch filterкоманди:

git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD


2

У цій темі є дуже хороші відповіді, але тим часом багато з них застаріли. Використання git-filter-branchбільше не рекомендується, оскільки його важко використовувати та дуже повільно у великих сховищах.

git-filter-repo набагато швидше і простіше у використанні.

git-filter-repo- це сценарій Python, доступний на веб- сайті github: https://github.com/newren/git-filter-repo .

Вам потрібен лише один файл: скрипт Python3 git-filter-repo. Скопіюйте його в шлях, який входить до змінної PATH. У Windows, можливо, доведеться змінити перший рядок сценарію (див. INSTALL.md). Вам потрібен встановлений Python3, встановлений у вашій системі, але це не велика справа.

Спочатку можна бігти

git filter-repo --analyze

Це допомагає визначити, що робити далі.

Ви можете видалити файл DVD-rip скрізь:

 git filter-repo --invert-paths --path-match DVD-rip

Filter-repo дійсно швидкий. Завдання, яке зайняло близько 9 годин на моєму комп’ютері фільтром-філією, було виконане за 4 хвилини фільтром-репо. З фільтром-репо можна зробити ще багато приємних речей. Для цього зверніться до документації.

Попередження: зробіть це на копії вашого сховища. Багато дій фільтру-репо не можна скасувати. filter-repo змінить хеші фіксації всіх модифікованих комітетів (звичайно) та всіх їхніх нащадків до останніх зобов’язань!


1

Коли ви стикаєтеся з цією проблемою, git rm буде недостатньо, оскільки git пам'ятає, що файл існував колись в нашій історії, і таким чином буде зберігати посилання на нього.

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

Я склав разом git forget-blob невеликий сценарій, який намагається видалити всі ці посилання, а потім використовує фільтр-гілку git для перезапису кожного комітету у гілці.

Після того, як ваш кльош буде повністю невирішений, git gc позбудетесь її

Використання досить просте git forget-blob file-to-forget. Більше інформації ви можете отримати тут

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

Я поєднав це завдяки відповідям із переповнення стека та деяких записів у блозі. Кредити їм!


ви повинні отримати це на домашній мові
Cameron E

0

Окрім git filter-branch(повільне, але чисте рішення git) та BFG (простіший та дуже ефективний), є ще один інструмент для фільтрації з хорошою продуктивністю:

https://github.com/xoofx/git-rocket-filter

З його опису:

Призначення git-rocket-filter схоже з командою git-filter-branchпри наданні наступних унікальних особливостей:

  • Швидке переписування комітетів та дерев (на замовлення від x10 до x100).
  • Вбудована підтримка як білого списку з --keep (зберігає файли або каталоги), так і чорного списку з параметрами --remove.
  • Використання .gitignore типу візерунка для фільтрування дерев
  • Швидкий та простий скрипт на C # як для фільтрації фіксації, так і для фільтрування дерев
  • Підтримка сценаріїв для фільтрування дерев за шаблоном файлів / директорій
  • Автоматично обрізати порожні / незмінені комісії, включаючи об'єднання комітетів
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.