Несколько копий одного и того же хранилища на машине - PullRequest
1 голос
/ 29 января 2020

У меня есть локальный компьютер, на котором есть несколько копий одного и того же репозитория GIT, каждая копия для своего пользователя. Так это может выглядеть так:

/home/userA/BigRepository
/home/userB/BigRepository
/home/userC/BigRepository
/home/userD/BigRepository
/home/userE/BigRepository

Допустим, каждый репозиторий использует ~ 2-3 ГБ, 20 пользователей будут использовать 40-60 ГБ ненужных избыточных данных. пользователи могут работать в своих частных филиалах, разрабатывая что-то, но большая часть данных остается избыточной. Вот почему я хотел бы оптимизировать использование диска.

Интересно, как лучше подходить к нему?


То, что я уже проверил :

  • git clone --local - Каждый репозиторий будет совместно использовать .git / objects с пустым репозиторием, но это означает, что .bare репозиторий mu sh будет доступен локально (поэтому это не может быть GitHub, верно?)
  • git clone --depth <n> - что уменьшит размер репо, но также уменьшит локальную историю до n объектов.
  • git clone --shallow-since - насколько я понимаю, это будет работать аналогично опции --depth но будет хранить коммиты с указанного времени.
  • git clone --separate-dir - моя собственная идея использовать одно и то же место для хранения всех. git каталогов. (поэтому каждый из 20 репозиториев будет ссылаться на одно и то же место при создании клона. Пока не знаю, возможно ли это, просто поделюсь своими идеями.

Будет --depth означать, что в репозиториях будет не более n фиксирует или проверяется только при клонировании, и тогда хранилище может расти со временем?

Ответы [ 2 ]

1 голос
/ 29 января 2020
  • git clone --local - Каждый репозиторий будет совместно использовать .git / objects с пустым репозиторием, но это означает, что .bare репозиторий mu sh будет доступен локально (поэтому это не может быть GitHub, верно?)

Не совсем верно, нет. Вы можете использовать это с любым локальным клоном, голым или нет. Но в целом, в тех случаях, когда это работает вообще, вам даже не нужно --local: вы можете просто клонировать по локальному пути.

Например, предположим userA, домашний каталог которого /home/userA, клонирует репозиторий GitHub, делая полный и непонятный клон. Предположим далее, что userB может прочитать из /home/userA. Поэтому пользователь B может сделать:

git clone /home/userA/BigRepository

, чтобы создать ./BigRepository. Если он сделает это в своем домашнем каталоге, он получит /home/userB/BigRepository, который содержит все те же коммиты, что и клон userA.

Поскольку Git будет делать жесткие ссылки, если пользователь А сейчас удаляет своего хранилища, он не восстанавливает свое пространство (поэтому, если действуют дисковые квоты, пользователь А не возвращает свою квоту). У пользователя B все еще есть ссылки на файлы, принадлежащие пользователю A. Все еще работает ; просто тот, кто сделал этот первый клон, «заплатил» за первоначальное хранилище для самого репозитория.

(пользователь B «платит» за свое собственное рабочее дерево . Он разделяет .git/objects файлов , включая файлы пакета, которые создал пользователь A. Все эти файлы доступны только для чтения, независимо от того, совместно использует ли пользователь B файлы пользователя A или нет, поэтому тот факт, что пользователь B может ' t запись в эти файлы не важна.)

Единственный недостаток этого процесса в том, что пользователь B, вероятно, захочет изменить свой origin URL, чтобы он указывал на репозиторий GitHub, а не клон пользователя А, и пока он этого не сделает, он не будет видеть тот же набор имен удаленного отслеживания (origin/* имена), который видит пользователь А.

Пользователь C может повторите этот процесс с любым из предыдущих репозиториев.

  • git clone --depth <n> - что уменьшит размер репо, но также уменьшит локальную историю до n объектов.

В основном да. Технически неверно с точки зрения числа n , хотя:

Будет --depth означать, что репозитории будут иметь не более n коммитов, или проверяется только при клонировании, а затем хранилище может расти со временем?

Они не только растут со временем, число n не означает, что вы предлагаете. Это глубина , а не количество коммитов. Глубина в этом случае является техническим термином, относящимся к обходу графика.

Помните, что Git использует commit в качестве основной единицы хранения c. (Коммиты могут быть разбиты и далее, но для нашей цели они здесь единица.) Каждый коммит имеет уникальный идентификатор ha sh и может быть представлен в виде узла или вершины на графе. Каждый коммит также хранит идентификатор ha sh своего непосредственного коммита (ов) предшественника: они образуют односторонние ребра или дуги , связывающие узлы, и, следовательно, образуют остальную часть графа.

Мы можем нарисовать биты графика следующим образом:

... <-F <-G <-H

, где каждая буква обозначает коммит ha sh ID. Сохраненные идентификаторы ha sh в каждом коммите действуют как указатели на предыдущие коммиты. Чтобы легко найти конец этой цепочки, мы - или Git - устанавливаем sh имя ветви или какую-либо другую форму имени, которая указывает на last коммит в цепочке:

...--F--G--H   <-- master

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

Теперь На графике с такими стрелками, направленными назад, могут быть разветвления и объединения:

          o--o         o--o--H   <-- branch1
         /    \       /
...--o--o--o---o--o--o--o--K   <-- branch2
         \          /
          o--o--o--o

Когда мы пересекаем этот граф, мы начинаем с конца - в нормальных графах мы начинаем с начала, но Git работает в обратном направлении - как commit H, как указано по имени branch1. Если мы выберем --depth 3, Git получит H и два более ранних коммита и K и два более ранних коммита:

          o--o--H   <-- branch1
         /
<snip>--o--o--K   <-- branch2

Наши --depth 3 получили шесть коммитов, потому что возвращаясь назад 3 с каждого конца получили нам эти коммиты из полного графа. Если мы go до --depth 4 получим:

               o--o--H   <-- branch1
              /
  <snip>--o--o--o--K   <-- branch2
         /
<snip>--o

Каждая из этих "отрывных" точек представляет собой мелкий трансплантат , где мы знаем, что были больше коммитов, но мы намеренно пропустили эти коммиты. Идентификаторы ha sh пропущенных коммитов записываются в .git/shallow и Git знает, когда он посещает коммит, чьи родители перечислены в .git/shallow, не пытаться найти родительские коммиты.

Аргумент --depth выбирает точки отсечения. Это происходит во времена, когда git fetch - git clone представляет собой необычную обертку из шести частей, которая включает git fetch в качестве пятого шага. Точки отсечения остаются там, где они есть, до тех пор, пока вы не запустите git fetch с указанным аргументом c для углубления или дальнейшего углубления в хранилище. Новые коммиты добавляются обычным способом и делают граф глубже, включая любые git fetch операции, которые выполняет любой из пользователей.

  • git clone --shallow-since - насколько я понимаю, он будет работать аналогично в --depth, но будет сохранять коммиты с указанного времени.

Да: это просто более полезный, а также менее запутанный способ установки точек «отсечки».

  • git clone --separate-dir

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

При стандартной настройке само хранилище отображается в рабочее дерево в подкаталоге с именем .git. С --separate-git-dir, .git все еще появляется в рабочем дереве, но на этот раз это файл , содержащий путь к хранилищу. В любом случае каждый пользователь оплачивает стоимость хранения независимо, если только не использует --local, как подразумевается, путем клонирования репозитория другого пользователя.

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

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

Между тем, если и когда пользователь B делает новый коммит, его Git должен записать один или несколько новых объектов в свой .git/objects. Если пользователи A и B буквально совместно используют репозиторий Git , то A и B должны иметь разрешение на запись в файлы и каталоги других пользователей. Этот режим можно заставить работать, но у него есть дополнительный недостаток: каждый пользователь должен быть очень осторожным , чтобы случайно не наступить на других пользователей. Хотя основная часть репозитория, включая предлагаемые для совместного использования части .git/objects, состоит из объектов, которые никогда не изменяются после записи, другие части, включая специальный файл .git/HEAD, и многочисленные другие файлы, такие как данные заголовка ветви и reflogs, должен быть закрытым для каждого пользователя, или иначе - и эта альтернатива, как правило, неработоспособна - только один пользователь может выполнять какую-либо реальную работу в любое время.

В теории, git worktree add можно использовать здесь

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

предназначен для этого --reference

Что такое , предназначенное для решения этой проблемы, это опция --reference. Используя --reference, вы, как администратор компьютера, сначала создадите полный клон репозитория GitHub. Вы можете сделать это --bare или нет - это не очень важно - но вы можете захотеть сделать его клоном --mirror, чтобы он получал каждый реф и мог легче обновляться. (Я немного поэкспериментировал с этим на предыдущей работе, и здесь есть некоторые проблемы, которые усложняют его обновление, так что это может быть не так полезно, как вы думаете вначале.)

Once this "эталонный клон "существует, каждый пользователь может сделать:

git clone --reference <path> <github-url>

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

Что это означает, что сам git clone идет очень быстро и почти не использует дополнительное дисковое пространство. Для создания исходного эталонного клона ~ 3 ГБ может потребоваться несколько минут или даже несколько часов, но когда один из пользователей выполняет эту операцию git clone --reference, он должен завершиться sh в секундах. Более того, он работает «чисто» в том смысле, что если ему нужны новые объекты от GitHub, они просто получают их из GitHub как обычно. Поскольку никакой коммит - никакой Git объект любого вида, действительно - никогда не может быть изменен , эталонный клон просто служит для предоставления всех объектов, которые вы изначально поместили в него. Новые объекты постепенно расширяют репозиторий каждого пользователя.

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

0 голосов
/ 29 января 2020

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

git clone git@server:BigRepository /home/userA/BigRepository
mkdir /home/userB/BigRepository/
ln -s /home/userA/BigRepository/.git /home/userB/BigRepository/.git

Однако все будут менять ветви всех остальных, т. Е. Ваша ветвь master может неожиданно переместиться. Ваше рабочее пространство не изменится, поэтому ваши файлы будут работать так, как ожидается. Но Git внезапно сообщит об изменениях.

...