BFG Repo Cleaner - альтернатива свежему клону

Я собирался спросить об этом в хранилище, но ТАК казалось, что это более подходящее место, чтобы спросить об этом.

Я смог использовать BFG Repo Cleaner (отличный инструмент, спасибо!), Чтобы уменьшить наш .git размер папки более 1 ГБ, что является огромным успехом для нашего хранилища. Я еще не перенес свой голый клон на удаленный, так как я заинтересован в том, чтобы выдвинуть эти изменения, прежде чем понять последствия подталкивания, а затем повторного клонирования.

Я понимаю, что лучшая практика диктует, что, когда история изменилась таким образом, лучшее решение - выполнить новый клон. Тем не менее, я работаю с командой из более чем 50 человек в репозитории с более чем 2 ГБ и 23 000 коммитов, и координация между группами может быть невероятно сложной в нашей структуре. В результате у меня есть несколько вопросов:

  1. Каковы будут последствия, если я нажму на эти измененные ссылки, и люди будут тянуть к своей существующей копии, а не создавать новый клон?
  2. Должны ли они делать что-либо еще, чтобы смягчить эти последствия как часть или в дополнение к их усилиям, если это возможно?
  3. Изменится ли эта рекомендация вообще, если учесть, что удаленные большие двоичные объекты взяты из истории, которой исполнился год, а максимум три года?
  4. Наконец, учитывая, что новый клон не будет включать в себя какую-либо работу, не синхронизированную в восходящем направлении, есть ли у вас рекомендация о наилучшем способе переноса неотслеживаемых ветвей от одного клона к другому? Если для этого уже существует команда Git, я бы хотел услышать ваше понимание.

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

1 ответ

Решение

Предисловие

Прежде чем мы углубимся в это, позвольте мне уточнить рекомендуемый процесс очистки истории Git в контексте активной команды разработчиков (независимо от того, какая технология используется для очистки - будь то BFG Repo-Cleaner или git filter-branch):

  1. Потренируйтесь делать чистку несколько раз на локальной одноразовой копии вашего хранилища, чтобы быть уверенным, что вы можете сделать это и получить желаемый результат, и вы знаете, сколько времени это займет.
  2. ОБЩАТЬСЯ С ВАШЕЙ КОМАНДОЙ. Это важно, неизбежно (потому что Git специально создан для того, чтобы жаловаться и мешать, если история переписывается) и просто хорошая практика для любой команды:-) Вы должны сказать им:
    • Почему происходит чистка (например, меньшее репо!)
    • Когда планируется чистка - предупредите их заранее.
    • Чтобы перенести всю свою работу в основной репозиторий до начала очистки - его не нужно объединять с основной веткой, но всю работу нужно выполнять в той или иной ветви.
    • Посоветуйте им, что им нужно будет удалить свои старые копии репо после завершения очистки, и повторно клонировать только что очищенный репозиторий.
  3. Когда все работы перенесены в основной репозиторий, сделайте зеркальный клон основного репозитория. Сделайте резервную копию этого клона, чтобы вы всегда могли вернуться, если что-то пойдет не так.
  4. Запустите очистку (с помощью BFG Repo-Cleaner или более медленного инструмента, такого как git filter-branch) и использовать git gc обрезать мертвые предметы.
  5. Как только вы убедитесь, что очистка прошла успешно, верните очищенную историю обратно в главное хранилище (потому что это было mirror клон, все старые ветки / теги будут перезаписаны в новую очищенную историю)
  6. Сообщите вашей команде, что пришло время удалить их старые копии репозитория и повторно клонировать очищенный репозиторий.

Итак, на ваши вопросы:

Что если: пользователь со старым репо извлекает из очищенного репо?

Каковы будут последствия, если я нажму на эти измененные ссылки, и люди будут тянуть к своей существующей копии, а не создавать новый клон?

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

В частности, на машине этого человека происходит то, что git pull Команда объединит старую грязную историю и новую очищенную историю, с двумя длинными расходящимися историями (изначально расходящимися с первым "грязным" коммитом в вашей истории, который в вашем случае был 3 года назад), соединенным вместе с одним совершенно новым и очень запутанный коммит слияния. Пользователям редко бывает ясно, что это произошло - большинство визуализаторов журнала Git не будут отображать это таким образом, чтобы это можно было сделать очевидным - если вам повезет, пользователь может сказать что-то вроде: "У меня есть две копии каждого коммита сейчас, WTF?!" - но только если они действительно наблюдательны.

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

При планировании, есть ли способ позволить пользователям сохранить свое старое репо, но обновить его, чтобы иметь очищенную историю?

Должны ли они делать что-либо еще, чтобы смягчить эти последствия как часть или в дополнение к их усилиям, если это возможно?

Технически да. На практике эта процедура сложна, подвержена ошибкам, и если только один пользователь ошибается, вы ввернуты, как и раньше.

На данный момент мы должны выяснить, почему вы пытаетесь уклониться от этой процедуры. Это потому что:

  • Вы пытаетесь избавить пользователей от необходимости знать и иметь дело с историей изменений Git? Похоже, что это может быть вашей целью, основанной на вашем высказывании "координация между командами может быть невероятно трудной в нашей структуре" - но, к сожалению, это не достижимая цель, потому что Git не позволит вам изменить историю, не заметив пользователей. Пользователи должны будут что- то сделать, и они должны будут согласовать с вами.
  • Вы хотите сократить время загрузки, создавая новый клон вашего действительно массивного репозитория, надеясь, что Git будет загружать только измененные большие двоичные объекты, а не все то, что не изменилось? Это несколько более разумная цель для гигантских репозиториев с несколькими гигабайтами, для загрузки которых требуются часы (хотя "если вы используете BFG для того, чтобы сделать репо гораздо меньше, мотивация будет меньше)- к сожалению, из-за подробностей выигранного вами протокола Git " не сможет реализовать эти преимущества. Протокол Git предназначен для определения того, какие коммиты находятся на удаленном сервере, которых нет в вашем локальном репо, и отправки специализированного пакетного файла, содержащего только то, что вам нужно для обновления вашего локального репо. Это здорово, но обратите внимание, что единица сравнения - коммит. Когда вы переписываете историю, дерево файлов коммитов почти не изменяется, но все идентификаторы коммитов меняются, потому что идентификатор фиксации - это хеш его родительской истории, а также содержимого дерева файлов. Протокол Git сравнивает только идентификаторы коммитов, и все они разные - поэтому все коммиты будут отправлены вместе с объектами файлового дерева. Протокол не копает достаточно глубоко, чтобы понять, что ему не нужно отправлять большую часть этих объектов файлового дерева - и поэтому вы не получаете преимущества от того, что уже имеете их копии в своем локальном репо.

Имеет ли значение, как давно плохое было в истории?

Изменится ли эта рекомендация вообще, если учесть, что удаленные большие двоичные объекты взяты из истории, которой исполнился год, а максимум три года?

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

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

Как насчет случайных коммитов / веток, которые не были перенесены в главный репозиторий, когда он был очищен?

Наконец, учитывая, что новый клон не будет включать в себя какую-либо работу, не синхронизированную в восходящем направлении, есть ли у вас рекомендация о наилучшем способе переноса неотслеживаемых ветвей от одного клона к другому?

Рекомендуемый способ решения этой проблемы - убедиться, что это не произойдет. Поговорите с вашей командой, скажите им, что очистка репозитория будет проходить, и все, что они должны сделать, чтобы это заработало, - это убедиться, что они перенесли всю свою работу в любую ветку в главный репозиторий, прежде чем начинать очистку.,

Если кто-то этого не делает, он может попытаться перебросить ветки, которые ему небезразличны, на очищенную историю. Для каждого feature ветка, что-то вроде:

$ git rebase --onto clean-origin/feature unclean-origin/feature feature

... (что в переводе означает "взять все коммиты, которые есть в моей ветви функций, которые я не перенес в главное репо до его очистки, и воспроизвести их поверх очищенной версии основного репо этой ветви),

Если пользователь ошибается или забывает сделать это только для одной ветви, вы вернетесь к сценарию плохой смешанной грязной / чистой истории.

Заключение

Вы знаете свою команду, уверены ли вы, что все они могут безупречно выполнять эзотерические операции по перебазированию Git? И какая польза от этого? После того как все сказано и сделано, не проще ли сказать им, чтобы они удалили свое старое репо и повторно клонировали?

Другие вопросы по тегам