Можно ли уменьшить a.репозиторий git без переписывания истории?

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

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

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

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

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

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


в стороне, считаю что это должны возможно, но, вероятно, связано с теми же ограничениями, что и gits current мелкий клон реализация.

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

4 ответов


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

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

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

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

  • история не изменяется. Если вам нужно вернуться к старой совершать с большой .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 подключитесь к общему репозиторию, чтобы отклонить любые толчки, которые могли бы повторно ввести исторические корневые фиксации.


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

  • как 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 минут должно быть достаточно, основные dos и don'TS).
  • будьте в курсе это git filter-branch не причиняет никакого вреда сам по себе, но вызывает много стандартных рабочих процессов, чтобы причинить вред. Если люди не действуют соответствующим образом и не объединяют старую историю, вам, возможно, придется переписать историю снова, если вы не заметите этого достаточно скоро.
  • вы можете предотвратить людей от слияния (точнее толкая) старую историю, написав (5 строк) соответствующий обновление крюк на сервере. Просто проверьте, содержит ли история толкаемой головы определенный старый совершать.

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

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


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