Git: как удалить файл из исторической фиксации?

113

У меня есть фиксация с идентификатором 56f06019 (например). В этом коммите я случайно зафиксировал большой файл (50 МБ). В другом коммите я добавляю тот же файл, но нужного размера (маленький). Теперь мое репо, когда я клонирую, слишком тяжелое :( Как удалить этот большой файл из истории репо, чтобы уменьшить размер моего репо?

marioosh
источник
в моем случае это не большой файл, а файл конфигурации, содержащий кредиты базы данных. Я изучал git, в то время я не знал о .gitignore.
Rashi
1
related help.github.com/articles/…
Тревор Бойд Смит

Ответы:

165

В главе 9 книги Pro Git есть раздел об удалении объектов .

Позвольте мне кратко изложить шаги здесь:

git filter-branch --index-filter \
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \
    --tag-name-filter cat -- --all

Как и в случае с описанным ранее вариантом перебазирования, filter-branchэто операция перезаписи. Если вы опубликовали историю, вам придется --forceподтолкнуть новых ссылок.

Этот filter-branchподход значительно мощнее, чем rebaseподход, поскольку он

  • позволяет работать сразу по всем веткам / реферам,
  • переименовывает любые теги на лету
  • работает чисто, даже если с момента добавления файла было несколько коммитов слияния
  • работает чисто, даже если файл (повторно) добавлялся / удалялся несколько раз в истории (а) ветки (ов)
  • не создает новые, несвязанные коммиты, а скорее копирует их, изменяя связанные с ними деревья. Это означает, что такие вещи, как подписанные коммиты, заметки о коммитах и ​​т. Д., Сохраняются.

filter-branch также хранит резервные копии, поэтому размер репо не уменьшится сразу, если вы не истечете время рефлогов и сборки мусора:

rm -Rf .git/refs/original       # careful
git gc --aggressive --prune=now # danger
sehe
источник
1
Стоит отметить, что это не работает под windows cmd.exe. Хотя, похоже, работает под Cygwin нормально.
Fake Name
2
Я получил указанную выше ветку фильтра git для работы с использованием двойных кавычек вместо одинарных кавычек (в Windows Server 2012 cmd.exe)
JCii
1
Для меня сработала эта командная строка ветки фильтра. git filter-branch --force --index-filter 'git rm --ignore-unmatch --cached PathTo/MyFile/ToRemove.dll' -- fbf28b005^.. Тогда rm --recursive --force .git/refs/originalи rm --recursive --force .git/logs потом я использовал git prune --expire now и git gc --aggressive Это сработало для меня лучше, чем ваши точные шаги, перечисленные выше. Спасибо за ссылку на книгу Git Pro, поскольку она была бесценной.
dacke.geo
После команды filter-branch единственный способ получить размер папки .git - это выполнить команду, найденную здесь: stackoverflow.com/questions/1904860/… git -c gc.reflogExpire = 0 -c gc. reflogExpireUnreachable = 0 -c gc.rerereresolved = 0 \ -c gc.rerereunresolved = 0 -c gc.pruneExpire = now gc "$ @"
Стив Ардис,
Для сжатия репозитория я использовал команды, перечисленные в git filter-branch doc: git-scm.com/docs/…
Людовик Ронсин
1

Я пробовал использовать следующий ответ в Windows https://stackoverflow.com/a/8741530/8461756

Одиночные кавычки не работают в окнах, вам нужны двойные кавычки.

Следующее сработало для меня.

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PathRelativeRepositoryRoot / bigfile.csv" - --all

После удаления большого файла я смог отправить свои изменения в мастер github.

Сандип Диксит
источник
0

Вам нужно будет выполнить git rebase в интерактивном режиме, см. Пример здесь: Как мне удалить фиксацию на GitHub? и как удалить старые коммиты .

Если ваша фиксация находится в HEAD минус 10 коммитов:

$ git rebase -i HEAD~10

После редактирования вашей истории вам нужно нажать "новую" историю, вам нужно добавить в +силу (см. Refspec в параметрах push ):

$ git push origin +master

Если другие люди уже клонировали ваш репозиторий, вы должны сообщить им, потому что вы только что изменили историю.

Loïc d'Anterroches
источник
3
Это не удаляет большой файл из истории. Кроме того, канонический способ принудительного нажатия - это git push --forceили git push -f(который не требует, чтобы люди знали цель push ветки)
см.
Исходя из вопроса, новый файл точно такой же, как и старый файл, то есть по тому же пути. Вот почему вы не можете напрямую использовать git rmна пути.
Loïc d'Anterroches
2
@sehe, если вы выполните перебазирование, удалив фиксацию с огромным файлом, он исчезнет навсегда.
vonbrand 07
@vonbrand только из той ветки, которую вы перебазировали. Я не предполагаю, что ветка "от" будет удалена. Но да, если вы удалите ветку дерева ревизий, это поможет: _
sehe
@sehe, конечно, вам нужно отследить все ветки, содержащие оскорбительный коммит. Если это произойдет до некоторой густоты репо, вам придется многое реорганизовать. Но инструмент для этого - rebase .
vonbrand 07
0

Вы можете использовать простую команду для удаления

 git rm -r -f app/unused.txt 
 git rm -r -f yourfilepath
мини-разработчик
источник