Как правильно настроить подмодуль git - PullRequest
1 голос
/ 31 мая 2019

Я пытаюсь добавить хранилище как подмодуль в другой модуль git.После добавления подмодуля я попытался клонировать родительский проект:

git clone https://...
cd <parent_path>/<submodule_path>
git submodule init
git submodule update

Теперь, если я git status в подмодуле, ГОЛОВКА отсоединена:

cd <submodule_path>
git status
HEAD detached at a4709b3
nothing to commit, working tree clean

После прочтения этого ответ Я пытался оформить заказ на субмодуль master:

git checkout master
git status

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

Но теперь, если я git status в родительском каталоге, это показывает, что в подмодуле есть новые коммиты (что определенно неcase)

cd <parent_dir_path>
git status

On branch test_submodule
Your branch is up to date with 'origin/test_submodule'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   submodule_name (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

Может кто-нибудь пролить свет на это?

РЕДАКТИРОВАТЬ: Вот вывод cd <submodule_path> && git show master:

commit 42309e0e2f48aba11902633173053e2423d4ba62 (HEAD -> master, origin/master, origin/HEAD)
Merge: a4709b3 1c1ae85
Author: Abc
Date:   Fri May 31 16:27:52 2019 +0100

    Merge pull request #6 in test/testing_submodule from test_integration_with_repos to master

    * commit '1c1ae8515716d9c2d5135e86dc9c024c81e4320b':
      test

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Ваш суперпроект помнит, что субмодуль должен быть в коммите a4709b3.Но подмодуль был обновлен, и теперь его master указывает на 42309e0.Что вы должны сделать сейчас, зависит от того, какой код (какой коммит) вы хотите использовать с суперпроектом.Самое простое решение - проверить сохраненный коммит:

cd <submodule_path>
git checkout a4709b3

Подмодуль будет находиться в отключенном состоянии HEAD.Не о чем беспокоиться.

Другая возможность - обновить подмодуль:

cd <submodule_path>
git checkout master # reconcile detached HEAD
git pull origin master

, а затем обновить суперпроект:

cd <parent_dir_path>
git add <submodule_path>
git commit -m "Update submodule"
1 голос
/ 01 июня 2019

TL; DR

git status сравнивает коммит HEAD (текущий коммит) и индекс. Что бы ни отличалось, готовится к коммиту . Затем он сравнивает индекс и рабочее дерево. Что бы ни отличалось, не ставится на коммит . В этом случае Git сравнивает индекс gitlink с фактическим идентификатором хэша в подмодуле. Когда говорится:

modified:   submodule_name (new commits)

это просто означает , что gitlink в индексе не соответствует хэшу HEAD commit в подмодуле . Это не означает, что являются новыми коммитами в подмодуле, и что там нет новых коммитов; это просто означает, что существующий идентификатор хеша индекса gitlink не соответствует существующей проверке субмодуля.

Long

Там всегда много путаницы вокруг подмодулей. Вопрос, который вы связали с - Почему мой подмодуль GIT HEAD отсоединен от мастера? - в качестве принятого ответа, ответ, который на самом деле не доходит до сути проблемы, что, я думаю, может быть резюмируется следующим разговором:

  • ЧЕЛОВЕК: Эй, Git, я хотел бы использовать этот другой Git-репозиторий в качестве подкаталога моего Git-репозитория.

  • GIT: ОК, готово.

  • ЧЕЛОВЕК: Круто. [Позже:] О, эй, почему, когда я создаю новый клон, мой подмодуль находится в отсоединенном состоянии HEAD?

  • GIT: Вот как это работает.

  • ЧЕЛОВЕК: Но я хочу, чтобы он был на ветке master.

  • GIT: ОК.

  • ЧЕЛОВЕК: Он все еще отсоединен!

  • GIT: Да.

  • ЧЕЛОВЕК: Я хочу это на ветке!

  • GIT: Да, нет. К сожалению.

Короче, так оно и есть. Теперь подмодуль является репозиторием Git, поэтому вы можете получить подмодуль на ветке. Но суперпроект Git собирается вернуть его обратно с ветки, потому что так работают подмодули . Чтобы понять, почему это так, нужно еще немного ума.

Почему субмодули отключены

Во-первых, давайте еще раз отметим, что подмодуль является репозиторием Git. Единственное, что делает подмодулем, это тот факт, что какой-то другой Git-репозиторий контролирует его время от времени. Мы называем другой репозиторий Git суперпроектом . Суперпроект выполняет управляющие команды, а подмодуль подчиняется им. Кроме этого, это два независимых репозитория Git: если подмодуль имеет master и develop и любые другие ветви, они не зависят от master и develop суперпроекта и любых других и у подмодуля и суперпроекта не должно быть одинакового набора имен ветвей вообще.

Также обратите внимание, что подмодуль может быть суперпроектом для еще одного подмодуля. Эта ситуация становится особенно запутанной, поскольку теперь говорить, что «подмодуль» или «суперпроект» является неоднозначным. В настоящее время существует два суперпроекта, два подмодуля и три Git-репозитории, а средний Git-репозиторий является как подмодулем (верхнего Git), так и суперпроектом (из нижний).

Конструкция делает одно огромное предположение, которое является полностью безопасным предположением, но может быть раздражающим.Это допущение: Подмодуль клонируется из репозитория, который вы не контролируете. Этот другой репозиторий может обновляться очень часто или почти никогда, но их ветви , которые копируютсяк своему клону в качестве origin/* имен удаленного отслеживания вашего подмодуля, измените его так, чтобы вы не обязательно контролировали. Когда вы впервые клонируете этот репозиторий подмодуля, git clone будет создайте новую ветвь с именем master или другое имя, если они так говорят, и коммит, который вы получите, проверив, какое бы это имя не было, находится под их контролем, а не вашим.

По этой причине самому суперпроекту не нужно - и почти никогда не используется - ни одно из имен ветвей подмодуля.Вместо этого суперпроект записывает что-то в хранилище подмодулей, которое не может изменить.Тот факт, что он не может измениться, означает, что независимо от того, кто контролирует ваш источник-клон, - подмодуль, он не может разрушить вашу зависимость от этого подмодуля.

(Конечно, это не на 100% верно. Например, они могут полностью удалить исходный репозиторий. Или они могут отказаться от коммита или тега, от которого вы зависите, но, как правило, люди не удаляют репозитории. Отмена коммитов встречается редко.и исключение опубликованного тега и его соответствующего коммита встречается особенно редко.)

То, что не может измениться, это запись вашего суперпроекта, это необработанный хэш-идентификатор коммита, который суперпроектсообщит субмодулю git checkout <em>hash</em>.Эта записанная информация входит в каждый коммит в вашем суперпроекте!(Ну, каждый коммит, который использует подмодуль.)

Отключенный HEAD возникает при запуске git checkout <em>hash</em>

Если вы достаточно долго использовали Git, вы уже знакомы с этим.Проверьте любую историческую фиксацию по ее хэш-идентификатору, и Git переходит в режим отдельного HEAD.

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

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

Это мешает новой работе

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

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

A commit, который ссылается на подмодуль, делает это через то, что Git называет gitlink .Gitlink, по сути, является зафиксированным файлом mode 160000 (обычные файлы mode 100644 или mode 100755), где «содержимое» файла - это просто хэш-идентификатор, который суперпроект должен отдать подмодулю Git на git checkout.

Следовательно, запись подмодуля - gitlink - в коммите сообщает git checkout: Вы действуете как суперпроект.Когда вы попадаете в это место в рабочем дереве, вместо того, чтобы извлекать здесь только один файл, подмодуль должен быть включен в этот коммит, как отдельный HEAD. Если вы используете git checkout --recurse-submodules, Git делает именно это.Если вы используете git checkout --no-recurse-submodules, Git удерживается на этом - он оставляет подмодуль, который, в конце концов, отдельный Git-репозиторий, один.

Теперь Git делает new коммиты не изчто находится в рабочем дереве, а что находится в index .Индекс содержит копию каждого файла ... и когда коммит имеет gitlink, индекс содержит копию этой gitlink. Это запись gitlink в индексе, которая определяет, что входит в следующий коммит, который вы делаете. Так что следующий суперпроект коммит использует все, что есть в индексе суперпроекта.

Иногда вы хотите, чтобы подмодуль находился в другом коммите. Поскольку подмодуль является хранилищем Git, вы можете просто зайти в него и git checkout как захотите.Если вы используете имя ветки, подмодуль HEAD теперь будет прикреплен.Что касается суперпроекта Git, это не имеет значения: для суперпроекта важен фактический хеш-идентификатор.Если подмодуль git rev-parse HEAD все еще выдает тот же хэш-идентификатор, что и в gitlink индекса суперпроекта, все равно совпадает.Если он создает какой-то другой хэш-идентификатор, вам решать, как это сделать. Поскольку вы хотите другой коммит, вы должны обновить gitlink индекса суперпроекта.

  • ЧЕЛОВЕК: Но, эй, Git:Я сказал вам запомнить имя ветки в суперпроекте для этого конкретного подмодуля.Как насчет вас, Git, подайте команду Git, которая контролирует подмодуль, на git checkout эту ветку name ?

Вы можете сделать это.Но здесь предполагается, что ваш Git клонировал ваш подмодуль Git из верхнего хранилища, которое вы не контролируете, и что вы не git push.Так что недостаточно , и вместо этого Git предоставляет команду:

git submodule update --remote

В этом случае суперпроект Git будет:

  • ввестиподмодуль
  • дает команду подмодулю Git запустить git fetch
  • дождаться обновления origin/master или чего-либо еще в подмодуле, в результате этого git fetch
  • найдите новый хэш-идентификатор подмодуля origin/master (или чего-либо еще) на основе восходящего потока (который вы не контролируете, но который только что извлек) из

, а затемИмейте подмодуль Git git checkout , который ID хеша ... как отсоединенную ГОЛОВУ, снова!

Если вы управляете подмодулем и хотите сделать в нем новые коммиты, вам нужно cd включить в субмодуль и просто git checkout любое имя филиала, которое вы хотите, и затем выполнять свою работу там.В конце концов, этот подмодуль является обычным старым Git-репозиторием.Вы можете делать любую работу, которая вам нравится, а затем запустить git add, чтобы скопировать все обновленные файлы рабочего дерева в индекс - git commit собирается использовать то, что находится в индексе, - и запустить git commit, чтобы сделать новый коммит.

ТогдаСделав все это, вы можете прямо сейчас отправить коммит вверх или подождать и cd вернуться в суперпроект. В любом случае теперь вы можете выполнять любую работу, которая требуется в суперпроекте, и git add любые измененные файлы и имя подмодуля . Вы не просто обновляете файлы в индексе суперпроекта, вам также необходимо обновить gitlink в суперпроекте. И теперь, когда вы сделали все это, вы можете запустить git commit в суперпроекте, чтобы сделать новый коммит, в котором будут храниться обновленные файлы и обновленной gitlink.

Теперь, когда у вас есть новый коммит суперпроекта, вы можете git push новый коммит суперпроекта где-нибудь. Если вы уже использовали git push в подмодуле, это все, что вам нужно сделать. Но если нет, вам следует сначала git push подмодуль. Причина довольно очевидна, если подумать: новая фиксация суперпроекта говорит: Когда вы попадете в этот подмодуль, прочитайте эту ссылку и извлеките фиксацию. a987654... (или любой другой хэш-идентификатор). Чтобы кто-то еще сделал это, ему нужно будет git fetch подмодуль восходящего потока, к которому у вас уже должен быть git push редактор, чтобы get commit a987654... в их подмодуль Git!

Обратите внимание, что это соответствует действию git submodule update --remote: они перейдут в восходящий поток своего подмодуля, git fetch обновленную ветвь, а затем git checkout соответствующий origin/<em>branch</em> идентификатор хеша, в данном случае a987654..., в качестве Отдельная ГОЛОВА для их подмодуля.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...