Подтвердить что ты не робот

Возможно ли ограничить хранилище .git без перезаписи истории?

У нас есть несколько репозиториев git, которые выросли до неуправляемого размера из-за исторического включения двоичных тестовых файлов и java .jar файлов.

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

В идеале я хотел бы экрнализировать файлы проблем без перезаписи истории каждого репозитория. Теоретически это должно быть возможно, потому что вы проверяете те же файлы с одинаковыми размерами и теми же хэшами, просто используя их из другого места (удаленный, а не локальный магазин объектов). Увы, ни одно из потенциальных решений, которые я нашел, пока что не позволяет мне это сделать.

Начиная с git-annex, наиболее близким к решению моей проблемы было Как ретроактивно добавлять файл уже в репозиторий git, но, как и при удалении больших файлов, для этого требуется переписать историю, чтобы преобразовать исходный git add в git annex add.

Перейдя оттуда, я начал смотреть на другие проекты, перечисленные в что git -annex не, поэтому я рассмотрел git-bigfiles, git-media и git-fat. К сожалению, мы не можем использовать git -bigfiles fork git, так как мы являемся магазином Eclipse и используем смесь git и EGit. Это не похоже на то, что git -media или git -fat может делать то, что я хочу, поскольку, поскольку вы могли бы заменить существующие большие файлы внешними эквивалентами, вам все равно придется переписывать историю, чтобы удалить большие файлы, которые уже были зафиксированы.

Итак, возможно ли разрезать репозиторий .git без перезаписи истории, или мы должны вернуться к плану использования git filter-branch и целой загрузки перераспределений?


В стороне, полагайте, что это должно быть возможно, но, вероятно, связано с теми же ограничениями, что и в git current неглубокий клон.

Git уже поддерживает несколько возможных мест для одного и того же blob, поскольку любой данный blob может находиться в свободное хранилище объектов (.git/objects) или в файл пакета (.git/objects), поэтому теоретически вам просто нужно что-то вроде git-annex, чтобы подключиться к этому уровень, а не выше (т.е. есть идея загрузки по требованию удаленного блоба, если хотите). К сожалению, я не могу найти никого, кто бы реализовал или даже предложил что-нибудь подобное.

4b9b3361

Ответ 1

Сорт. Вы можете использовать Git функцию замены, чтобы выделить большую раздутую историю, чтобы она была загружена только при необходимости. Это как мелкий клон, но без ограничений мелкого клонирования.

Идея заключается в том, что вы перезагружаете ветвь, создавая новую команду root, а затем вишневый захват старой фиксации ветки. Обычно вы потеряете всю историю таким образом (это также означает, что вам не нужно клонировать эти большие файлы .jar), но если вам нужна история, вы можете получить исторические фиксации и использовать git replace, чтобы их легко сшить назад.

Смотрите Скотт Чакон отличный пост в блоге для подробного объяснения и прохода.

Преимущества такого подхода:

  • История не изменяется. Если вам нужно вернуться к более старому завершению с большим .jars и всем, вы все равно можете.
  • Если вам не нужно смотреть на старую историю, размер вашего локального клона хорош и мал, и любые свежие клоны, которые вы делаете, не потребуют загрузки тонны бесполезных данных.

Недостатки этого подхода:

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

    * modify bar (master)
    |
    * modify foo  <--replace-->  * modify foo (historical/master)
    |                            |
    * instructions               * remove all of the big .jar files
                                 |
                                 * add another jar
                                 |
                                 * modify a jar
                                 |
    

    и у кого-то есть ветка старой ветки, с которой они сливаются:

    * merge feature xyz into master (master)
    |\__________________________
    |                           \
    * modify bar                 * add feature xyz
    |                            |
    * modify foo  <--replace-->  * modify foo (historical/master)
    |                            |
    * instructions               * remove all of the big .jar files
                                 |
                                 * add another jar
                                 |
                                 * modify a jar
                                 |
    

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

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

Ответ 2

Нет, это невозможно - вам придется переписать историю. Но вот несколько указаний на это:

  • Как упоминалось в VonC: если это соответствует вашему сценарию, используйте BFG-repo cleaner - его гораздо проще в использовании, чем git filter-branch.
  • Вам больше не нужно клонировать! Просто запустите эти команды вместо git pull, и все будет в порядке (замените origin и master на ваш пульт и ветвь):

    git fetch origin
    git reset --hard origin/master
    

    Но обратите внимание, что в отличие от git pull вы потеряете все локальные изменения, которые еще не были перенесены на сервер.

  • Это помогает, если вы (или кто-то еще в вашей команде) полностью понимаете, как git видит историю, а что git pull, git merge и git rebase (также как git rebase --onto). Затем дайте всем участникам быстрое обучение тому, как справиться с этой ситуацией перезаписи (должно быть достаточно 5-10 минут, основные досы и донты).
  • Имейте в виду, что git filter-branch не приносит никакого вреда самому себе, но приводит к тому, что многие стандартные рабочие процессы могут нанести вред. Если люди не действуют соответственно и объединяют старую историю, вам просто придется переписать историю еще раз, если вы не заметите достаточно скоро.
  • Вы можете запретить людям слияние (точнее нажатие) старой истории, написав (5 строк) подходящий крюк обновления на сервере, Просто проверьте, содержит ли история нажатой головки конкретное старое коммит.

Ответ 3

Я не знаю решения, которое позволит избежать перезаписи истории.

В этом случае очистка rpeo с помощью инструмента, такого как BFG-repo cleaner - это самое простое решение (проще что git filter-branch).

Ответ 4

Я, честно говоря, не могу придумать, как это сделать. Если вы думаете о том, что Git "promises" вы как пользователь, в отношении целостности данных, я не могу придумать, как вы могли бы удалить файл из репозитория и сохранить тот же хеш. Другими словами, если бы вы спросили, возможно ли, что Git будет намного менее надежным...