Обновление подмодуля Git

242

Мне не ясно, что означает следующее (из документации по обновлению подмодуля Git ):

... сделает Подмодули ГОЛОВА быть отсоединена, если --rebaseили --mergeне указан ...

Как --rebase/ --mergeизменить вещи?

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

  • Могу ли я создавать ветки / модификации из этих подмодулей и использовать push / pull точно так же, как в обычных репозиториях, или есть вещи, которые нужно соблюдать осторожность?
  • Как бы я продвинул коммит, на который ссылается субмодуль, скажем, с (помеченного) 1.0 до 1.1 (даже если заголовок исходного репозитория уже находится на 2.0), или выбрал, какая фиксация ветки используется вообще?
темно-синий
источник
По теме «отсоединенная голова» см. Также stackoverflow.com/questions/964876/head-and-orighead-in-git и stackoverflow.com/questions/237408/… для практического примера (не относящегося к подмодулю, но все же )
VonC
«Вы не можете изменять содержимое подмодуля из основного проекта»: да, правда. И я отредактировал свой ответ, чтобы пролить некоторый свет на это кажущееся противоречие (немодифицируемый подмодуль, который вы все еще можете изменить из основного репо проекта!)
VonC

Ответы:

304

Эта страница GitPro действительно суммирует последствия обновления подмодуля git

Когда вы запускаете git submodule update, он проверяет конкретную версию проекта, но не внутри ветви. Это называется наличием отдельной главы - это означает, что файл HEAD указывает непосредственно на коммит, а не на символьную ссылку.
Проблема в том, что вы, как правило, не хотите работать в автономном окружении, потому что изменения легко потерять .
Если вы выполняете первоначальное обновление субмодуля, фиксируете в этом каталоге субмодуля, не создавая ветку для работы, а затем снова запускаете обновление субмодуля git из суперпроекта без фиксации за это время, Git перезапишет ваши изменения, не сообщив вам. Технически вы не потеряете работу, но у вас не будет ветки, указывающей на нее, поэтому ее будет довольно сложно найти.


Примечание март 2013:

Как упоминалось в « последнем отслеживании подмодулей git », подмодуль сейчас (git1.8.2) может отслеживать ветку.

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

Смотрите " git submodule update --remoteпротивgit pull ".

MindTooth «сек ответ иллюстрирует обновление вручную (без локальной конфигурации):

git submodule -q foreach git pull -q origin master

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

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


Чтобы избежать этой проблемы, создайте ветку, когда вы работаете в подмодульном каталоге с git checkout -b work или чем-то аналогичным. Когда вы обновите субмодуль во второй раз, он все равно вернет вашу работу, но, по крайней мере, у вас есть указатель для возврата.

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


Итак, чтобы ответить на ваши вопросы:

могу ли я создавать ветки / модификации и использовать push / pull так же, как я бы делал это в обычных репозиториях, или есть вещи, которые нужно соблюдать осторожность?

Вы можете создать ветку и нажать на изменения.

ПРЕДУПРЕЖДЕНИЕ (из учебника по Git Submodule ): всегда публиковать (отправлять) изменения подмодуля, прежде чем публиковать (отправлять) изменения в суперпроект, который ссылается на него. Если вы забудете опубликовать изменение субмодуля, другие не смогут клонировать репозиторий.

как бы я продвинул коммит субмодуля, на который ссылаются, с say (tagged) от 1.0 до 1.1 (даже если голова исходного репо уже на 2.0)

Страница « Понимание подмодулей » может помочь

Подмодули Git реализованы с использованием двух движущихся частей:

  • .gitmodulesфайл и
  • особый вид дерева.

Вместе они триангулируют конкретную ревизию определенного репозитория, которая извлекается в определенное место в вашем проекте.


Со страницы подмодуля git

вы не можете изменять содержимое подмодуля из основного проекта

100% правильно: вы не можете изменить подмодуль, а только сослаться на один из его коммитов.

Вот почему, когда вы изменяете подмодуль из основного проекта, вы:

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

Подмодуль позволяет вам разрабатывать компонентный подход , когда основной проект ссылается только на конкретные коммиты других компонентов (здесь «другие репозитории Git, объявленные как субмодули»).

Подмодуль - это маркер (коммит) в другом репозитории Git, который не связан основным циклом разработки проекта: он («другое» репозиторий Git) может развиваться независимо.
Основной проект должен выбрать из этого репо то, что ему нужно.

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

Но основная идея остается: ссылки на конкретные компоненты, которые:

  • имеют свой жизненный цикл
  • иметь свой собственный набор тегов
  • имеют собственное развитие

Список конкретных коммитов, на которые вы ссылаетесь в своем основном проекте, определяет вашу конфигурацию (это то, чем занимается Configuration Management, включая простую систему контроля версий )

Если компонент действительно может быть разработан в то же время, что и ваш основной проект (поскольку любая модификация основного проекта будет включать изменение подкаталога и наоборот), то это будет не «подмодуль», а скорее слияние поддеревьев (также представлено в вопросе « Перенос базы устаревшего кода из cvs в распределенный репозиторий» ), связывающее историю двух репозиториев Git вместе.

Помогает ли это понять истинную природу подмодулей Git?

VonC
источник
77
Вот это да. Такого длинного объяснения чего-то, что в принципе так просто, должно быть достаточно, чтобы напугать любого новичка, который просто придерживается их svn: externals. ;-)
Конни
2
@conny: но, как я подробно описываю в разделе « Почему подмодули git несовместимы с внешними svn? », подмодули принципиально отличаются и не совместимы с svn:externals.
VonC
1
Извините, чтобы ответить на мой собственный вопрос, я собираю cd'ing в подмодуль и делаю git checkout sha, или git pull / fetch подойдет. Затем фиксируем обновление в локальном репозитории.
Хенрик
2
@hced: Вы также можете поразить все подмодули одновременно, используяgit submodule foreach
Дэв Кларк,
1
.. до сих пор не понимаю. Где-нибудь в Интернете есть более легкое объяснение?
Евгений
135

Чтобы обновить каждый подмодуль, вы можете вызвать следующую команду (в корне хранилища):

git submodule -q foreach git pull -q origin master

Вы можете удалить опцию -q, чтобы проследить весь процесс.

MindTooth
источник
15
Если вы просто запустите git submodule update --init --recursiveиз корня, он получит их все рекурсивно и инициализирует их, если это еще не сделано.
Сэм Соффс
10
@SamSoffes Это служит совершенно другой цели. Обновление подмодулей будет проверять подмодули при коммите, на который они в данный момент указывают (не обязательно при последнем коммите). Решение в ответе выше обновляет коммит каждого субмодуля до последней HEAD от origin / master.
indragie
7
Мой новый метод:git submodule update --rebase --remote
MindTooth
19

Чтобы рассмотреть вариант --rebaseпротив --merge:

Допустим, у вас есть супер-репозиторий A и подмодуль B, и вы хотите выполнить некоторую работу в подмодуле B. Вы выполнили свою домашнюю работу и знаете, что после звонка

git submodule update

вы находитесь в состоянии HEAD, поэтому к любым коммитам, которые вы делаете в этот момент, трудно вернуться. Итак, вы начали работу над новой веткой в ​​подмодуле B

cd B
git checkout -b bestIdeaForBEver
<do work>

Между тем, кто-то еще в проекте A решил, что последняя и самая лучшая версия B - это то, что A заслуживает. Вы по привычке объединяете самые последние изменения и обновляете свои подмодули.

<in A>
git merge develop
git submodule update

О нет! Вы снова находитесь в безголовом состоянии, вероятно, потому что B теперь указывает на SHA, связанный с новым советом B, или каким-то другим коммитом. Если бы только у вас было:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

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

(Изменения --mergeбудут перенесены из beforeUpdateSHA в afterUpdateSHA в вашу рабочую ветвь, в отличие от изменения ваших изменений в afterUpdateSHA.)

robinspb
источник
7

В Git 1.8.2 появилась новая опция --remote, которая включит именно это поведение. Бег

git submodule update --rebase --remote

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

--удаленный

Эта опция действительна только для команды обновления. Вместо того, чтобы использовать записанный SHA-1 суперпроекта для обновления подмодуля, используйте статус ветви удаленного отслеживания подмодуля.

Это эквивалентно запуску git pullв каждом подмодуле, что, как правило, именно то, что вы хотите.

(Это было скопировано из этого ответа .)

Юлиан Онофрей
источник
Если вы решите ответить на старый вопрос, на котором уже есть точные и правильные ответы, добавление нового ответа в конце дня может не принести вам никакой пользы. Если у вас есть какая-то новая отличительная информация, или вы убеждены, что все остальные ответы неверны, обязательно добавьте новый ответ, но «еще один ответ», дающий ту же основную информацию спустя долгое время после того, как вопрос был задан, обычно выигрывает ». Я не заработаю тебе много кредитов. Там нет объяснения того, что это делает - даже ссылка на внешнюю документацию (что было бы недостаточно).
Джонатан Леффлер
2
Это не «еще один ответ», поскольку никакой другой ответ не имеет этой команды (докажите, что я не прав). Другие комментарии не сработали для меня, этот комментарий сработал , поэтому я решил опубликовать его как ответ, отдавая должное первоначальному владельцу. Так что подумайте о том, чтобы убрать свой гнев.
Юлиан
Есть комментарий от MindTooth из 2015 года, в котором говорится, что это то, что они делают сейчас. Вы не даете объяснения тому, что это делает (хотя вы упоминаете MindTooth, но нет реального объяснения того, что вы подразумеваете под этим - встраивание URL, как в этом комментарии, поможет). Вы не говорите, почему это хорошая идея. Вы не даете никаких предостережений. На мой взгляд, это не очень полезный ответ, потому что он вызывает больше вопросов, чем решает.
Джонатан Леффлер
1
Я имел в виду, что это работает, а не не работает. Поверьте мне, если бы больше людей увидели этот ответ, они были бы рады, потому что он работает . Для подобных вещей большинство людей просто хотят знать команду, которая обновляет подмодуль git, а не то, как она реализована.
Юлиан
Я отредактировал ответ, чтобы доказать, что вы не правы, также, stackoverflow.com/questions/1979167/git-submodule-update/… !!!
Юлиан