Иногда я бросал DVD-рип в проект веб-сайта, затем небрежно git commit -a -m ...
, и, зап, репо было раздутым на 2,2 гига. В следующий раз я сделал некоторые изменения, удалил видеофайл и зафиксировал все, но сжатый файл все еще находится в хранилище, в истории.
Я знаю, что могу начинать ветки с этих коммитов и перебазировать одну ветку на другую. Но что я должен сделать, чтобы объединить 2 коммита, чтобы большой файл не отображался в истории и был очищен в процессе сборки мусора?
git filter-branch
, но я обнаружил, что все наоборот.Ответы:
Используйте BFG Repo-Cleaner , более простую и быструю альтернативу,
git-filter-branch
специально разработанную для удаления ненужных файлов из истории Git.Тщательно следуйте инструкциям по использованию , основная часть просто так:
Любые файлы размером более 100 МБ (которых нет в вашем последнем коммите) будут удалены из истории вашего репозитория Git. Затем вы можете использовать
git gc
для очистки мертвых данных:BFG обычно по крайней мере в 10-50 раз быстрее, чем бег
git-filter-branch
, и, как правило, проще в использовании.Полное раскрытие: я являюсь автором BFG Repo-Cleaner.
источник
git push --force
после ваших шагов, в противном случае удаленное репо все равно не изменилось.git push --force
. Также стоит отметить: принудительные нажатия могут быть запрещены удаленным пользователем (по умолчанию gitlab.com этого не делает. Пришлось «снимать защиту» с ветки).То, что вы хотите сделать, очень разрушительно, если вы опубликовали историю другим разработчикам. См. «Восстановление из исходной версии» в
git rebase
документации, чтобы узнать о необходимых шагах после восстановления истории.У вас есть как минимум два варианта:
git filter-branch
и интерактивная перебазировка, оба объяснены ниже.С помощью
git filter-branch
У меня была похожая проблема с объемными данными бинарных тестов из импорта Subversion и я писал об удалении данных из репозитория git .
Скажите, что ваша история с мерзавцами:
Обратите внимание, что
git lola
это нестандартный, но очень полезный псевдоним. С помощью--name-status
переключателя мы можем видеть модификации дерева, связанные с каждым коммитом.В коммите «Неосторожный» (имя объекта SHA1 - ce36c98) файл
oops.iso
представляет собой DVD-рип, случайно добавленный и удаленный при следующем коммите cb14efd. Используя технику, описанную в вышеупомянутом сообщении в блоге, команда для выполнения:Опции:
--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
Следующее--
является сокращением для всех ссылок. Ваш репозиторий, как и в приведенном выше примере, может иметь только один ref (master), но я включил эту опцию для полной общности.После некоторого сбивания история теперь:
Обратите внимание, что добавляется только новый коммит «Неосторожный»
other.html
и что коммит «Remove DVD-rip» больше не находится в основной ветке. В ветке с пометкойrefs/original/refs/heads/master
содержатся ваши исходные коммиты на случай, если вы допустили ошибку. Чтобы удалить его, следуйте инструкциям в «Контрольном списке для сокращения хранилища».Для более простой альтернативы клонируйте репозиторий, чтобы отбросить ненужные биты.
Использование
file:///...
клона URL копирует объекты, а не только создает жесткие ссылки.Теперь ваша история:
Имена объектов SHA1 для первых двух коммитов («Индекс» и «Страница администратора») остались прежними, поскольку операция фильтрации не изменила эти коммиты. «Careless» потерял
oops.iso
и «Логин страница» получили новый родитель, так что их SHA1s сделал изменения.Интерактивная перебазировка
С историей:
Вы хотите удалить
oops.iso
из «Неосторожного», как если бы вы никогда не добавляли его, а затем «Удалить DVD-рип» для вас бесполезно. Таким образом, наш план перехода к интерактивной перебазировке - сохранить «Страницу администратора», отредактировать «Неосторожный» и отказаться от «Удалить DVD-рип».Запуск
$ git rebase -i 5af4522
запускает редактор со следующим содержимым.Выполняя наш план, мы изменяем его
То есть мы удаляем строку с «Удалить DVD-рип» и меняем операцию на «Неосторожно»,
edit
а не наpick
.При выходе из редактора при сохранении мы получаем командную строку со следующим сообщением.
Как говорится в сообщении, мы находимся в «небрежном» коммите, который хотим редактировать, поэтому мы запускаем две команды.
Первый удаляет поврежденный файл из индекса. Второй изменяет или изменяет «Careless», чтобы он был обновленным индексом, и
-C HEAD
дает команду git повторно использовать старое сообщение коммита. Наконец, мыgit rebase --continue
продолжаем с остальной частью операции rebase.Это дает историю:
что ты хочешь
источник
-f
(или--force
) к своейgit push
команде: «Обычно команда отказывается обновлять удаленную ссылку, которая не является предком локальной ссылки, используемой для ее перезаписи. Этот флаг отключает проверку. Это может привести к потере коммитов в удаленном репозитории; используйте это с осторожностью. ”... "git rm --cached -rf --ignore-unmatch path/to/dir"...
Почему бы не использовать эту простую, но мощную команду?
--tree-filter
Опция запускает указанную команду после каждой проверки проекта , а затем вновь заявляют результаты. В этом случае вы удаляете файл с именем DVD-rip из каждого снимка, независимо от того, существует он или нет.Если вы знаете, какой коммит ввел огромный файл (скажем, 35dsa2), вы можете заменить HEAD на 35dsa2..HEAD, чтобы избежать переписывания слишком большого количества истории, таким образом избегая расходящихся коммитов, если вы еще не нажали. Этот комментарий любезно @ alpha_989 кажется слишком важным, чтобы оставить его здесь.
Смотрите эту ссылку .
источник
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
commit
куда вы положили файл (скажем35dsa2
), вы можете заменитьHEAD
на35dsa2..HEAD
.tree-filter
гораздо медленнее, чемindex-filter
этот способ, он не будет пытаться извлекать все коммиты и переписывать их. если вы используете HEAD, он попытается это сделать.(Лучший ответ, который я когда-либо видел на эту проблему: https://stackoverflow.com/a/42544963/714112 , скопирован здесь, поскольку эта тема занимает высокое место в поисковом рейтинге Google, а другая нет)
Fast Чертовски быстрый однострочный корпус 🚀
Этот сценарий оболочки отображает все объекты BLOB-объектов в хранилище, отсортированные от наименьшего к наибольшему.
Для моего примера репо он работал примерно в 100 раз быстрее, чем другие, найденные здесь.
В моей надежной системе Athlon II X4 она обрабатывает репозиторий ядра Linux с 5,622,155 объектами всего за минуту .
Базовый сценарий
Когда вы запустите код выше, вы получите хороший читабельный вывод, подобный этому:
🚀 Быстрое удаление файлов 🚀
Предположим, что вы хотите удалить файлы,
a
иb
из каждой достижимой фиксацииHEAD
вы можете использовать эту команду:источник
--tag-name-filter cat
чтобы повторно пометить новые соответствующие коммиты по мере их переписывания, т.git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD
рабочий по праву от летучей мыши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
Попробовав практически каждый ответ в SO, я наконец нашел этот драгоценный камень, который быстро удалил и удалил большие файлы в моем хранилище и позволил мне снова синхронизироваться: http://www.zyxware.com/articles/4027/how-to-delete -файлы-постоянно-из-ваш-местного и ЩИТОК-GIT-репозитории
CD в вашу локальную рабочую папку и выполните следующую команду:
замените FOLDERNAME файлом или папкой, которые вы хотите удалить из данного репозитория git.
После этого выполните следующие команды, чтобы очистить локальный репозиторий:
Теперь внесите все изменения в удаленный репозиторий:
Это очистит удаленный репозиторий.
источник
Эти команды работали в моем случае:
Это немного отличается от приведенных выше версий.
Для тех, кому нужно отправить это в github / bitbucket (я проверял это только с bitbucket):
источник
git rm --cached files
. Предложение Грега Бэкона является более полным и почти таким же, как у этого рудника, но он пропустил индекс --force для случаев, когда вы используете фильтр-ветвь несколько раз, и он написал так много информации, что моя версия похожа на резюме этого-f
опцию не-rf
здесь,git rm --cached -rf --ignore-unmatch oops.iso
аgit rm --cached -r --ignore-unmatch oops.iso
в соответствии с @ lfender6445 нижеПросто отметьте, что эти команды могут быть очень разрушительными. Если больше людей работают над репо, им всем придется потянуть новое дерево. Три средние команды не нужны, если ваша цель НЕ уменьшить размер. Поскольку ветвь фильтра создает резервную копию удаленного файла, он может оставаться там в течение длительного времени.
источник
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
вместо первой из вашего кодаgit filter-branch --tree-filter 'rm -f path/to/file' HEAD
работал очень хорошо для меня, хотя я столкнулся с той же проблемой, как описано здесь , которую я решил, следуя этому предложению .Книга pro-git содержит целую главу о переписывании истории - взгляните на
filter-branch
раздел / Удаление файла из каждого коммита .источник
Если вы знаете, что ваш коммит был последним, а не проходил через все дерево, сделайте следующее:
git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD
источник
Я столкнулся с этим с помощью учетной записи bitbucket, где случайно хранил огромные резервные копии * .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/
источник
Это удалит его из вашей истории
источник
Я в основном сделал то, что было на этот ответ: https://stackoverflow.com/a/11032521/1286423
(для истории, я скопирую и вставлю это здесь)
Это не сработало, потому что я очень люблю переименовывать и перемещать вещи. Таким образом, некоторые большие файлы были в папках, которые были переименованы, и я думаю, что gc не смог удалить ссылку на эти файлы из-за ссылки в
tree
объектах, указывающих на этот файл. Мое окончательное решение действительно убить это было:Мое
.git
хранилище изменилось с 32 МБ до 388 КБ, что даже фильтр-ветвь не смог очистить.источник
git filter-branch
это мощная команда, которую вы можете использовать для удаления огромного файла из истории коммитов. Файл останется на некоторое время, и Git удалит его в следующей сборке мусора. Ниже представлен полный процесс удаления файлов из истории коммитов . В целях безопасности нижеприведенный процесс сначала запускает команды для новой ветви. Если результат - то, что вам нужно, то верните его обратно в ветку, которую вы действительно хотите изменить.источник
Используйте Git Extensions , это инструмент пользовательского интерфейса. Он имеет плагин под названием «Найти большие файлы», который находит файлы lage в репозиториях и позволяет удалять их постоянно.
Не используйте 'git filter-branch' перед использованием этого инструмента, так как он не сможет найти файлы, удаленные с помощью 'filter-branch' (хотя 'filter-branch' не удаляет файлы полностью из файлов пакета репозитория) ,
источник
Вы можете сделать это с помощью
branch filter
команды:git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD
источник
В этой теме есть очень хорошие ответы, но многие из них устарели. Использование
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 в вашей системе, но это не имеет большого значения.
Сначала вы можете запустить
Это поможет вам определить, что делать дальше.
Вы можете удалить свой DVD-рип файл везде:
Фильтр-репо действительно быстрый. Задача, которая занимала на моем компьютере около 9 часов с помощью ответвления фильтра, была выполнена за 4 минуты с помощью фильтра-репо. С помощью filter-repo вы можете делать еще много приятных вещей. Обратитесь к документации для этого.
Предупреждение. Сделайте это с копией вашего хранилища. Многие действия фильтра-репо не могут быть отменены. filter-repo изменит хеши коммитов всех измененных коммитов (конечно) и всех их потомков вплоть до последних коммитов!
источник
Когда вы
git rm
столкнетесь с этой проблемой, этого будет недостаточно, так как git помнит, что файл когда-то существовал в нашей истории, и, таким образом, сохранит ссылку на него.Что еще хуже, перебазировка также не легка, потому что любые ссылки на blob не позволят сборщику мусора git очистить пространство. Это включает в себя удаленные ссылки и ссылки reflog.
Я собрал
git forget-blob
небольшой скрипт, который пытается удалить все эти ссылки, а затем использует git filter-branch для перезаписи каждого коммита в ветке.Как только ваш блоб полностью не
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/
Я собрал это воедино благодаря ответам из Stack Overflow и некоторым записям в блоге. Кредиты им!
источник
Кроме
git filter-branch
(медленного, но чистого git-решения) и BFG (более простого и очень производительного), есть еще один инструмент для фильтрации с хорошей производительностью:https://github.com/xoofx/git-rocket-filter
Из его описания:
Назначение git-rocket-filter аналогично команде
git-filter-branch
, предоставляя следующие уникальные возможности:источник