Как только вывести последнюю фиксацию в подмодуле git

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

Например, когда я делаю

git submodule update --init --recursive

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

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

Примечание git archive (как указано в ответе ниже), похоже, не работает, когда я пытаюсь выполнить следующую последовательность команд

mkdir temp-git-test
cd temp-git-test
git init
git submodule add --depth 1 https://github.com/boostorg/boost
cd boost
git archive --format=tar HEAD --output ../boost.tar.gz
cd ..
tar -xzvf boost.tar.gz

Вывод расстегнутого репо совпадает с подмодулем. Я что-то делаю неправильно?

Ответ 1

Короткий ответ - нет. Возможно, длинный ответ, но рассмотрим другой способ.

Неглубокие клоны и мелкие подмодули

Длинный ответ, который позволяет вам получить часть от того, что вы хотите, начинается с технической заметки: вы не тянете, в терминах Git. В Git "pull" означает "fetch, then merge-or-rebase", и вы не собираетесь объединяться или переустанавливать здесь. Фактически, когда вы начинаете "init", вы обычно делаете начальные клоны.

Каждый подмодуль на самом деле является его собственным репозиторием. 1 Git рано или поздно собирается сделать git checkout в каждом из этих репозиториев, попросив его проверить, а не ветку, а скорее конкретный коммит, который нередко не является последним фиксатором. Учитывая природу репозиториев Git и разработку программного обеспечения, а также идею о том, что подмодуль является, в первую очередь, ссылкой на сторонний репозиторий, т.е. Тот, который вы специально не контролируете и не можете контролировать, лучшее, что вы можете сделать говорит: "Я знаю, что мое программное обеспечение работает с одной конкретной версией своего программного обеспечения, и эта версия заполняет пробел > ". Таким образом, ваш репозиторий перечисляет определенную версию, которую вы хотите, из своего репозитория.

Теперь мы доходим до сути проблемы. Когда вы git clone репозиторий или используете git fetch для обновления существующего клона, вы делаете это, запрашивая конкретные имена ветвей и/или тегов, а не конкретные идентификаторы фиксации. Существует некоторая (очень ограниченная) поддержка для получения определенных идентификаторов, но она должна быть включена в этом другом репозитории, тот, который мы только что сказали, что вы не можете и не можете контролировать. Включение fetch-by-ID для них является дорогостоящим для вычислений - кем бы они ни были, те, которые контролируют другой репозиторий, - а не то, что вы можете делать на своей стороне, и не требуете, и не включаетесь по умолчанию. Это означает, что в целом он просто недоступен.

В любом случае git clone работает только с именами: вы можете, например, git clone -b branch url сделать свой новый клон, проверив эту конкретную ветку или git clone -b tag url, чтобы начать ваш новый клон, проверив (как отдельный HEAD), который является специфическим тегом. Несмотря на это, "проверьте конкретную ветку или тег", клон по умолчанию клонирует все имена, предлагаемые удаленным, и делает полноразмерный (т.е. Не-мелкий) клон.

Все это означает что-то важное. Во-первых, существуют мелкие клоны. Неглубокий клон - это один, сделанный с аргументом --depth. Его можно углубить на git fetch с другим --depth. "Глубина" - это количество коммитов, выведенных за пределы "фиксации", идентифицированных именами (именами), используемыми во время клонирования или извлечения, с некоторыми довольно сложными правилами. (Детали этих правил здесь не имеют большого значения.)

Во-вторых, поскольку существуют мелкие клоны, существуют мелкие подмодули. Неглубокий подмодуль - это просто подмодуль, клонированный с помощью --depth. Но есть проблема: нет простого или очевидного способа определить, какая глубина необходима.. Вы можете передать аргумент --depth в git submodule add или git submodule update, но это не очевидно, насколько глубоко вы должны пойти.

Здесь проблема: ваш подмодуль будет клонирован, возможно, по имени ветки или тега, но тогда вашему подмодулю будет предложено проверить одно конкретное сообщение (по его сырому идентификатору хэша). Будет ли это зафиксировано в клоне? Какую глубину он гарантирует? Если вы клонируете по имени тега, и тег всегда называет правильную фиксацию, вы можете использовать --depth 1 (и, следовательно, вы можете использовать --shallow-submodules во время начального git clone), но это работает только, если, см. выше.


1 Что особенно важно в этих субрепозиториях, это:

  • указанный во внешнем репозитории (в файле .gitmodules);
  • обычно сохраняется в режиме "отсоединенный HEAD";
  • и отсоединен при фиксации, чей идентификатор хранится во внешнем репозитории.

В файле модулей перечислены имена и URL-адреса для различных подмодулей. "Инициализация" подмодуля сводится к копированию материала из .gitmodules в файл конфигурации для содержащего суперпроекта, а "обновление" подмодуля обычно составляет клонирование или выборку. Конец, на котором должен быть отсоединен субмодуль, записывается в репозиторий суперпроекта как запись "gitlink" в древовидном объекте.

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


Клоны для ссылок

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

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

Это позволяет вам получить полный, полный, обновленный клон при использовании очень небольшого количества сетевых ресурсов и ресурсов хранения, поскольку вам больше не нужно будет переносить данные (большинство или все), а также (кроме --detach -ing) сохраните его самостоятельно. Это, в свою очередь, означает, что вам не нужно беспокоиться о том, что ваш мелкий клоун слишком мелкий: вы просто получаете один медленный полный клон, а затем ссылаетесь на него на все остальные клоны, которые идут быстро. Использование ссылочных клонов может сократить время клонирования нескольких больших хранилищ GitHub, например, с часа до плюс до десятков секунд.


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

3 Ссылка должна быть "как можно более локальной" для скорости, но на самом деле она не должна быть на вашей машине, просто доступной. Если ссылка не всегда будет присутствовать, вы, вероятно, захотите добавить --dissociate, чтобы объекты копировались из ссылочного клона в новый клон. Разумеется, это использует больше дискового пространства.

Ответ 2

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

Затем объедините git archive репо boost с настройкой неглубокого клонирования для вашего подмодуля

  • ваш подмодуль по-прежнему мелкий
  • но затем вы переопределяете его неполное содержимое одним (полным) образа git archive одного и того же репо, что делает рабочее дерево точной репликой удаленного репо SHA1.

Оттуда каждое обновление (неглубокое) будет дополнять контент, который был бы полным, и будет оставаться актуальным.

git archive выполняется в локальном клоне репо:

git archive --format=tar HEAD

Если у вас нет локального клона, но репозиторий boost находится на GitHub (например, boostorg/boost), то вы можете получить сжатое изображение текущего HEAD с помощью простого завитка (тогда не нужно git archive).


Как видно из комментария, добавление содержимого архива бесполезно, поскольку оно представляет один и тот же контент коммита.

Однако это кажется неполным:

git submodule add --depth 1 https://github.com/boostorg/boost

Для обновления подмодуля - устраните работу (т.е. для извлечения последнего фиксации вместо сохранения начальной проверки SHA1) вам понадобится:

git submodule add -b master --depth 1 https://github.com/boostorg/boost

Затем a git submodule update --init --recursive --remote получит последнее коммит.

См. "Git подмодули: укажите ветку/тег".