Как я могу принудительно использовать определенную ветку в подмодуле git при фиксации и отправке изменений в суперпроекте? - PullRequest
1 голос
/ 06 ноября 2019

Я хочу сделать это, чтобы можно было применять ветви релизов в подмодулях при нажатии ветви релиза в суперпроекте

1 Ответ

2 голосов
/ 06 ноября 2019

TL; DR

Имена ветвей подмодуля имеют значение только в том случае, если и когда вы выполняете реальную работу в этом подмодуле, и даже тогда, только для того, чтобы вы могли легко git push из этого подмодуля. В противном случае имеет значение только фактический необработанный идентификатор хеша внутри подмодуля. Git обычно будет поддерживать подмодуль с «отключенной головой». В то время как вы можете - в более новых версиях Git - сохранять имя ветки для подмодуля, Git действительно никогда не использует это имя при работе в суперпроекте. Он просто использует хеш-идентификаторы коммитов.

Вы можете получить суперпроект git checkout (отсоединенный HEAD) коммит в подмодуле, используя имя на основе имен в восходящем направлении этого подмодуля. Это иногда полезно, когда вы не работаете с подмодулем, но кто-то другой делает: вы можете выбрать их последний коммит, посмотреть, работает ли он с вашим проектом, и если да, переключить ваш проектиспользовать их последний коммит. Здесь, имя ветки немного полезно, потому что git submodule update --remote может использовать его, чтобы ваш клон подмодуля вызывал их Git, видел имена ветвей их Git и получал для вас хеш-идентификатор. Но это действительно нацелено на процесс разработки, а не на процесс выпуска.

Длинный

Краткий ответ в основном «вы не можете сделать это напрямую», но также в основном «это не так»не имеет значения ".

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

Давайте сделаем этот пример немного более конкретным. Предположим, у нас есть проект с именем P . Этот репозиторий - назовем его RepoP - содержит в себе некоторые коммиты. Этот репозиторий имеет несколько имен веток, таких как master, feature/f и, возможно, release/v1 и тому подобное. У него также могут быть имена тегов, такие как v1.0, который является определенным выпуском в ветви release/v1, который представляет версию 1.0.

Каждое из этих имен - master, feature/f, v1.0,и так далее - имена один конкретный коммит в репо. Разница между именем branch и тегом заключается в том, что имя ветви изменяется во времени: сегодня master может быть фиксацией a123456..., а завтра - b789abc... вместо. Имя тега никогда не должно меняться: оно всегда представляет один и тот же коммит.

Когда вы делаете git checkout в RepoP, независимо от того, используете ли вы имя ветви или имя тега или просто необработанный хэш коммита, Gitпервые выясняют , которые передают это . То есть Git находит фактический хэш-идентификатор целевого коммита. Затем Git извлекает этот коммит - все файлы в его снимке - в индексную / промежуточную область Git и в рабочее дерево для RepoP.

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

Допустим, вы использовали имя, выбравшее commit a123456... в RepoP. Допустим, далее, что commit a123456... требует двух подмодулей, которые должны быть извлечены в path/to/s1 и s2 (без начального пути к каталогу, просто ./s2) соответственно. В коммите a123456 вы найдете две сущности, которые Git вызывает gitlinks: они содержат path/to/s1 и необработанный идентификатор хеша, s2 и второй необработанный идентификатор хеша. Git также считывает все gitlink в индекс, чтобы они были готовы к вечному сохранению при следующем коммите, который вы делаете.

Скажем, что gitlink для path/to/s1 имеетхэш-идентификатор 5100000... и gitlink для s2 имеет хеш-идентификатор 5200000.... (Это довольно маловероятно, но не менее вероятно, чем a123456... или a6496b61... или что-то в этом роде. Дело в том, что если этот коммит вызывает эти два подмодуля, то будет два идентификатора хеша, какими бы они ни были.)

Теперь, когда комmit a123456 в вашем рабочем дереве, теперь Git может заполнить подмодули. Вам может потребоваться запустить:

git submodule update --init

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

Теперь Git войдет в каталог path/to/s1, клонирует хранилище подмодулей, если необходимо, и затем запустит:

git checkout 5100000...

чтобы получить этот конкретный коммит извлеченный в подкаталоге подмодуля, path/to/s1. (Помните, мы говорили, что запись gitlink для path/to/s1, которая сейчас находится в вашем индексе, говорит: использовать коммит 510000... с этим коммитом . Вот что делает Git.)

Git будетвведите подкаталог s2, клонируйте подмодуль при необходимости и выполните:

git checkout 5200000...

, чтобы получить этот конкретный коммит , извлеченный в подкаталоге подмодуля s2.

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

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


1 За исключением того, что во время оригинального git clone этого подмодуля: Git необходимо find commitsи, чтобы найти коммиты, Git нужны имена. Это потому, что идентификаторы хеша выглядят абсолютно случайными. Невозможно определить, какие коммиты являются новейшими , если только у вас нет имени ветви, например release/1.0, которое содержит новейший хэш-идентификатор для release/1.0 ветви.


Итак, когда do имена подмодулей имеют значение?

Допустим, вы собираетесь поработать над проектом P в вашем рабочем дереве RepoP.

Работа, которую вы выполняетенеобходимо исправить ошибку или добавить функцию в субмодуль s2. Итак, в этом окне или в другом окне вы вводите s2.

Теперь вы находитесь в подмодуле Git-репозитория. git status показывает, что у вас есть отсоединенный HEAD , потому что суперпроект Git сказал субмодулю Git: проверить коммит 5200000... как отсоединенный HEAD , и он это сделал.

Теперь вы можете изменять код и делать коммиты, но если вы это сделаете, они просто будут на этом отдельном ГОЛОВЕ. Будет трудно подтолкнуть их к другому Git. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *, а в более поздних версиях Git суперпроект Git направляет подмодуль Git проверять ветку по имени. Вы должны выполнить команду в этот момент в суперпроекте, чтобы заставить его делать это. 2 Но если вы собираетесь выполнить какую-то работу внутри s2 самостоятельно, вы можете просто выполнитьпростая команда git checkout внутри s2 при работе с подмодулем: например,

git checkout release/1.0

. Теперь вы можете выполнять свою работу как обычно и выполнять коммит, что заставит новый коммит изменить хеш-идентификатор, хранящийся в имени ветви субмодуля release/1.0. Затем вы можете git push получившийся коммит в origin субмодуля добавить его в этого репозитория release/1.0.

Скажем просто для конкретности, что этот новый коммиткак-то был присвоен хеш-код 5200001..., когда вы это сделали. Теперь, когда ваш новый коммит, с вашей новой функцией, существует в подмодуле и переведен в origin, вы просто возвращаетесь к суперпроекту и используете git add для обновления индексной / промежуточной области в суперпроекте Git:

git add s2

* следующий коммит, который вы делаете в RepoP, скажет: Когда вы используете этот коммит, скажите Git для подмодуля s2, чтобы проверить коммит 5200001.... Anyone используя , новый коммит использует его по необработанному хэш-идентификатору detached-HEAD. Название ветки не имеет отношения к суперпроекту. Вам просто нужно было использовать его, пока работает в подмодуле, чтобы вы могли подтолкнуть новый коммит к origin, чтобы каждый, кто клонирует подмодуль, тоже получил коммит 5200001....


2 Я полагаю, что более новые версии Git получают некоторые более изящные элементы управления, которые могут немного упростить вашу работу, особенно если есть несколько подмодулей, требующих работы. Но на самом деле, насколько проще сделать git submodule newsubcommand release/1.0, за которым следует cd s2, за которым следует выполнение вашей работы, против cd s2, за которым следует git checkout release/1.0, за которым следует выполнение вашей работы?

...