Влияние редактирования истории мерзавцев
У нас довольно плохая ситуация с состоянием одного из наших репо. Кто-то небрежно выделил 4 ГБ бинарных файлов в репозиторий и отправил его на удаленный мастер. Затем они сказали "Ой!" и отменил этот коммит.
К сожалению, git хранит только diff, и поскольку он не может на самом деле хранить diff двоичных файлов, он сохраняет весь файл в истории. И поскольку он был включен в историю дважды (один раз, когда он был добавлен, один раз, когда он был удален), размер репо теперь составляет 8 ГБ. Это вызывает у нас огромные проблемы и заставляет наши сборки занимать на час больше времени, чем им нужно.
Я понимаю, что могу использовать такие инструменты, как rebase и filter-branch, чтобы удалить эти коммиты или удалить эти файлы из истории git. Тем не менее, каждая публикация или документация по этим инструментам гласит: "Если коммиты, которые вы хотите отредактировать, уже отправлены на удаленный сервер, НЕ ДЕЛАЙТЕ ЭТОГО! Переписывание истории - ПЛОХАЯ ИДЕЯ!!!"
Но нигде фактически не объясняется, каково влияние переписывания истории. У нас действительно нет выбора - мы ДОЛЖНЫ удалить эти файлы из истории. Но, со всеми ужасными предупреждениями об опасности переписывания истории git, мы очень боимся на самом деле пытаться удалить эти файлы.
Итак, я надеюсь, что полезный пользователь Stackru сможет объяснить, что может быть результатом удаления этих огромных файлов с помощью filter-branch, или, может быть, если есть какое-то лучшее решение, о котором мы не знаем.
1 ответ
Это распространенное заблуждение, что git хранит различия. Он на самом деле хранит полное содержимое каждой версии *. На самом деле, вся модель git построена вокруг гарантированного безупречного извлечения исходного кода, чего не могут добиться в VCS на основе diff.
Вероятно, у вас либо два коммита с двоичными файлами, либо вы считаете как копию в базе данных, так и копию в рабочем каталоге.
Чтобы ответить на ваш основной вопрос, хотя.
Git хранит данные в виде коллекции объектов, которые ссылаются друг на друга. (См. Деревья Меркле). Поскольку деревья и история построены из объектов, которые ссылаются на другие объекты, очень трудно действительно удалить общие данные из git-репо.
"Переписывание истории" даже немного ошибочно, так как git никогда не переписывает историю, он просто возвращается и создает новую историю, а затем указывает на эту новую историю. Старые вещи могут зависать месяцами перед сборкой мусора. Как только вы начинаете делиться этим, в логической модели git ваша переписанная история - это просто еще одна ветвь в другом экземпляре репо.
Обычно ветви перемещают кодовую базу вперед и могут быть объединены, чтобы объединить эту историю. Если у вас есть ветвь функции под названием feature1
и слить его в свой master
ветвь, это не просто код, который становится частью мастера, все коммиты на feature1
стать частью мастера, а также. Когда каждая ветвь представляет собой отдельный фрагмент кода, это не проблема.
Это становится проблемой, когда вы пытаетесь переписать историю. Допустим, вы делаете то, что предлагаете, и удаляете код из истории, используя фильтр-ветвь (хотя перебазировка будет проще и, вероятно, безопаснее, это довольно недавно). Каждый член вашей команды удаляет свою локальную копию этой ветки и проверяет новую. Все замечательно, за исключением того, что вы работали над featureX и уже слили ветку master в нее после того, как произошла ошибка, поэтому старый master является частью вашей ветви featureX. Делать различие между featureX
а также master
покажет те же результаты, что и разница между featureX
и старый мастер, но все эти коммиты все еще являются частью featureX
, В мозгу мерзавца, featureX
разветвились в тот момент, когда были добавлены большие файлы, и когда вы объедините его в мастер, featureX
приносит все обратно с этим.
Так что это опасность, если даже у одного человека, где-нибудь в любой из его ветвей, все еще есть копия старого коммита в истории, у вас останутся не только файлы, от которых вы пытаетесь избавиться, но и целая вторая версия истории, чтобы иметь дело также.
Если вы должны удалить его, это можно сделать, но вам нужно будет очень тщательно координировать процесс, чтобы гарантировать, что каждый экземпляр хранилища был очищен. С очень маленькой командой это не страшно, но чем больше ваша команда распределена, тем сложнее становится.
* Он делает некоторые умные вещи с дельта-сжатием, когда упаковывает объекты для хранения, но всегда таким образом, который гарантирует немного идеальную реконструкцию. Git обнаружит даже один бит неуместной во всей истории как сломанный репо.