Как указать ветку / тег при добавлении подмодуля Git?
Как git submodule add -b
Работа?
После добавления подмодуля с определенной веткой, новый клонированный репозиторий (после git submodule update --init
) будет на конкретном коммите, а не на самой ветке (git status
в подмодуле отображается "В настоящее время нет ни в одной ветви").
Я не могу найти информацию о .gitmodules
или же .git/config
о ветке подмодуля или о каком-либо конкретном коммите, так как Git это выяснит?
Кроме того, возможно ли указать тег вместо ветви?
Я использую версию 1.6.5.2.
14 ответов
Примечание: в Git 1.8.2 добавлена возможность отслеживать ветки. Смотрите некоторые ответы ниже.
Это немного сбивает с толку, чтобы привыкнуть к этому, но подмодули не на ветке. Как вы говорите, они являются просто указателем на определенный коммит репозитория подмодуля.
Это означает, что когда кто-то проверяет ваш репозиторий или извлекает ваш код и выполняет обновление подмодуля git, подмодуль извлекается для этой конкретной фиксации.
Это отлично подходит для подмодуля, который меняется не часто, потому что тогда у каждого в проекте может быть подмодуль при одном и том же коммите.
Если вы хотите переместить субмодуль в определенный тег:
cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push
Затем другой разработчик, который хочет, чтобы submodule_directory был изменен на этот тег, делает это
git pull
git submodule update
git pull
изменения, которые фиксируют их каталог подмодулей, на которые указывает. git submodule update
на самом деле сливается в новом коде.
Я хотел бы добавить здесь ответ, который на самом деле является просто конгломератом других ответов, но я думаю, что он может быть более полным.
Вы знаете, что у вас есть подмодуль Git, когда у вас есть эти две вещи.
Ваш
.gitmodules
имеет такую запись:[submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git
У вас есть объект субмодуля (в данном примере с именем SubmoduleTestRepo) в вашем Git-репозитории. GitHub показывает их как "субмодульные" объекты. Или сделать
git submodule status
из командной строки. Объекты подмодуля Git представляют собой особые виды объектов Git, и они содержат информацию SHA для конкретной фиксации.Всякий раз, когда вы делаете
git submodule update
, он заполнит ваш подмодуль контентом из коммита. Он знает, где найти коммит из-за информации в.gitmodules
,Теперь все
-b
это добавить одну строку в вашем.gitmodules
файл. Поэтому, следуя тому же примеру, это будет выглядеть так:[submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git branch = master
РЕДАКТИРОВАТЬ: выше поддерживается только имя ветви, но не SHA или TAG.
Объект подмодуля по-прежнему указывает на конкретный коммит. Единственное, что
-b
Опция покупает это возможность добавить--remote
пометить ваше обновление в соответствии с ответом Vogella:git submodule update --remote
Вместо того, чтобы заполнять содержимое подмодуля коммитом, на который указывает субмодуль, он заменяет этот коммит последним коммитом в основной ветке, ПОТОМ он заполняет субмодуль этим коммитом. Это может быть сделано в два этапа с помощью ответа djacobs7. Поскольку вы обновили коммит, на который указывает объект подмодуля, вы должны зафиксировать измененный объект субмодуля в своем Git-репозитории.
git submodule add -b
это не какой-то магический способ держать все в курсе с веткой. Это просто добавляет информацию о филиале в.gitmodules
файл и дает вам возможность обновить объект подмодуля до последнего коммита указанной ветви перед его заполнением.
Обратите внимание, что если у вас есть субмодуль, который еще не отслеживает ветку, то ( если у вас git 1.8.2+):
Убедитесь, что родительское хранилище знает, что его подмодуль теперь отслеживает ветку:
cd /path/to/your/parent/repo git config -f .gitmodules submodule.<path>.branch <branch>
Убедитесь, что ваш подмодуль на самом деле не позднее этой ветки:
cd path/to/your/submodule git checkout -b branch --track origin/branch # if the master branch already exist: git branch -u origin/master master
(с именем origin, являющимся именем удаленного репо восходящего потока, с которого был клонирован подмодуль.
git remote -v
внутри этого подмодуля будет отображаться. Обычно это "происхождение")
Не забудьте записать новое состояние вашего подмодуля в вашем родительском репо:
cd /path/to/your/parent/repo git add path/to/your/submodule git commit -m "Make submodule tracking a branch"
Последующее обновление для этого подмодуля должно будет использовать
--remote
опция:# update your submodule # --remote will also fetch and ensure that # the latest commit from the branch is used git submodule update --remote # to avoid fetching use git submodule update --remote --no-fetch
Обратите внимание, что с Git 2.10+ (3 квартал 2016 года) вы можете использовать .
'как название филиала:
Название филиала записывается как
submodule.<name>.branch
в.gitmodules
заupdate --remote
,
Особая ценность.
используется, чтобы указать, что имя ветви в подмодуле должно совпадать с именем текущей ветви в текущем репозитории.
Если вы хотите обновить все свои подмодули, следуя ветке:
git submodule update --recursive --remote
Обратите внимание, что результатом для каждого обновленного подмодуля почти всегда будет отдельная ГОЛОВА, как отмечает Dan Cameron в своем ответе.
( Clintm отмечает в комментариях, что, если вы запустите git submodule update --remote
и результирующий sha1 такой же, как ветвь, в которой в данный момент находится подмодуль, он ничего не будет делать и оставит подмодуль все еще "в этой ветке", а не в состоянии отдельного заголовка.)
Чтобы убедиться, что ветка действительно извлечена (и это не изменит SHA1 специальной записи, представляющей подмодуль для родительского репо), он предлагает:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch'
Каждый подмодуль будет по-прежнему ссылаться на тот же SHA1, но если вы сделаете новые коммиты, вы сможете их подтолкнуть, потому что на них будет ссылаться ветвь, которую вы хотите отследить подмодуль.
После этого продвижения в подмодуле не забудьте вернуться к родительскому репо, добавить, зафиксировать и отправить новый SHA1 для этих модифицированных подмодулей.
Обратите внимание на использование $toplevel
Рекомендовано в комментариях Alexander Pogrebnyak. $toplevel
был представлен в git1.7.2 в мае 2010 года: commit f030c96.
он содержит абсолютный путь к каталогу верхнего уровня (где
.gitmodules
является).
dtmland
добавляет в комментариях:
Скрипт foreach не сможет извлекать подмодули, которые не следуют за веткой.
Тем не менее, эта команда дает вам оба:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch' –
Та же команда, но проще для чтения:
git submodule foreach -q --recursive \
'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
[ "$branch" = "" ] && \
git checkout master || git checkout $branch' –
umläute уточняет dtmland с упрощенной версией в комментариях:
git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
несколько строк:
git submodule foreach -q --recursive \
'git checkout \
$(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
В Git 1.8.2 добавлена возможность отслеживать ветки.
# add submodule to track master branch
git submodule add -b master [URL to Git repo];
# update your submodule
git submodule update --remote
Смотрите также Git submodules
Пример того, как я использую подмодули Git.
- Создать новый репозиторий
- Затем клонируйте другой репозиторий как подмодуль
- Тогда у нас есть этот подмодуль, использующий тег V3.1.2
- И тогда мы совершаем.
И это выглядит примерно так:
git init
vi README
git add README
git commit
git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib
git status
git submodule init
git submodule update
cd stm32_std_lib/
git reset --hard V3.1.2
cd ..
git commit -a
git submodule status
Может быть, это помогает (хотя я использую тег, а не ветку)?
В существующих ответах отсутствует второй шаг и они перегружены деталями.
Чтобы переключить существующий подмодуль для отслеживания нового удаленного URL-адреса и/или новой ветки:
- Отредактируйте источник правды в .
Например, из
[submodule "api"]
path = api
url = https://github.com/<original_repo>/api.git
к
[submodule "api"]
path = api
url = https://github.com/<another_repo>/api.git
branch = work-in-progress
Обновите описание подмодулей, кэшированных git, в
.git/modules
из только что отредактированного источника правды, указанного в.gitmodules
запустивgit submodule sync
.Обновите извлеченные подмодули в рабочей копии, используя
git submodule update --init --recursive --remote
.Зафиксируйте изменения.
По моему опыту, переключение ветвей в суперпроекте или будущих проверках будет по-прежнему вызывать отдельные заголовки подмодулей, независимо от того, правильно ли добавлен и отслеживается подмодуль (т.е. ответы @djacobs7 и @Johnny Z).
И вместо того, чтобы вручную проверять правильную ветку вручную или через скрипт git submodule, можно использовать foreach.
Это проверит файл конфигурации подмодуля для свойства ветки и извлечет установленную ветку.
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
Подмодули Git немного странные - они всегда находятся в режиме "отстраненной головы" - они не обновляются до последнего коммита на ветке, как вы могли ожидать.
Это имеет некоторый смысл, когда вы думаете об этом, хотя. Допустим, я создаю репозиторий foo с панелью субмодулей. Я отправляю свои изменения и говорю вам проверить коммит a7402be из репозитория foo.
Затем представьте, что кто-то вносит изменения в панель репозитория, прежде чем вы сможете сделать свой клон.
Когда вы проверяете коммит a7402be из репозитория foo, вы ожидаете получить тот же код, который я нажал. Вот почему подмодули не обновляются, пока вы не скажете им явно, а затем сделаете новый коммит.
Лично я думаю, что подмодули - самая запутанная часть Git. Есть много мест, которые могут объяснить подмодули лучше, чем я. Я рекомендую Pro Git от Скотта Чакона.
Чтобы переключить ветку для подмодуля (при условии, что у вас уже есть подмодуль как часть репозитория):
cd
в корне вашего репозитория, содержащего подмодули- открыто
.gitmodules
для редактирования - Добавить строку ниже
path = ...
а такжеurl = ...
это говоритbranch = your-branch
для каждого подмодуля; сохранить файл.gitmodules
, - затем без изменения каталога сделать
$ git submodule update --remote
... это должно получить последние коммиты в указанной ветви для каждого измененного таким образом подмодуля.
У меня есть это в моем файле.gitconfig. Это все еще черновик, но оказался полезным на данный момент. Это помогает мне всегда подключать субмодули к их ветке.
[alias]
######################
#
#Submodules aliases
#
######################
#git sm-trackbranch : places all submodules on their respective branch specified in .gitmodules
#This works if submodules are configured to track a branch, i.e if .gitmodules looks like :
#[submodule "my-submodule"]
# path = my-submodule
# url = git@wherever.you.like/my-submodule.git
# branch = my-branch
sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'"
#sm-pullrebase :
# - pull --rebase on the master repo
# - sm-trackbranch on every submodule
# - pull --rebase on each submodule
#
# Important note :
#- have a clean master repo and subrepos before doing this !
#- this is *not* equivalent to getting the last committed
# master repo + its submodules: if some submodules are tracking branches
# that have evolved since the last commit in the master repo,
# they will be using those more recent commits !
#
# (Note : On the contrary, git submodule update will stick
#to the last committed SHA1 in the master repo)
#
sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' "
# git sm-diff will diff the master repo *and* its submodules
sm-diff = "! git diff && git submodule foreach 'git diff' "
#git sm-push will ask to push also submodules
sm-push = push --recurse-submodules=on-demand
#git alias : list all aliases
#useful in order to learn git syntax
alias = "!git config -l | grep alias | cut -c 7-"
Мы используем Quack для извлечения определенного модуля из другого репозитория Git. Нам нужно извлекать код без всей кодовой базы предоставленного репозитория - нам нужен очень специфический модуль / файл из этого огромного репозитория, и его следует обновлять каждый раз, когда мы запускаем обновление.
Итак, мы достигли этого следующим образом:
Создать конфигурацию
name: Project Name
modules:
local/path:
repository: https://github.com/<username>/<repo>.git
path: repo/path
branch: dev
other/local/path/filename.txt:
repository: https://github.com/<username>/<repo>.git
hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9
path: repo/path/filename.txt
profiles:
init:
tasks: ['modules']
В описанной выше конфигурации он создает один каталог из предоставленного репозитория GitHub, как указано в конфигурации первого модуля, а другой - извлечь и создать файл из данного репозитория.
Другие разработчики просто нужно запустить
$ quack
И это тянет код из вышеупомянутых конфигураций.
Единственный эффект выбора ветви для подмодуля заключается в том, что всякий раз, когда вы передаете --remote
вариант в git submodule update
Git будет проверять в автономном режиме HEAD (если по умолчанию --checkout
поведение выбрано) последняя фиксация выбранной удаленной ветви.
Вы должны быть особенно осторожны при использовании этой функции удаленного отслеживания ветвей для подмодулей Git, если вы работаете с мелкими клонами подмодулей. Выбранная для этого ветка в настройках субмодуля НЕ является той, которая будет клонирована во время git submodule update --remote
, Если вы передаете также --depth
параметр, и вы не указываете Git, какую ветку вы хотите клонировать - и на самом деле вы не можете в git submodule update
командная строка!! - он будет неявно вести себя, как объяснено в git-clone(1)
документация для git clone --single-branch
когда явное --branch
параметр отсутствует, и поэтому он будет клонировать только первичную ветвь.
Неудивительно, что после этапа клонирования в исполнении git submodule update
Команда, наконец, попытается проверить последнюю фиксацию для удаленной ветви, которую вы ранее настроили для подмодуля, и, если она не является основной, она не является частью вашего локального мелкого клона, и поэтому она потерпит неудачу с
фатальный: требуется одна ревизия
Невозможно найти текущую версию источника / версию NotThePrimaryBranch в пути к субмодулю 'mySubmodule'
Подмодуль git add -b development - имя-ветви-имя- https://branch.git/
Используйте приведенные ниже команды
Добавить подмодуль (ветвь-ветвь)
git submodule add -b stage git@github.optum.com:orgname/${reponame}.git
Подмодуль обновления (ветка-ветвь)
######Clone########
> git clone -b master --single-branch --recurse-submodules git@github.com:orgname/project.git
or
> git clone -b stage --single-branch --recurse-submodules git@github.com:orgname/project.git
######Update#######
> git submodule update --remote (only for remote branch -ie master)
or
> git submodule update --recursive --remote
> git submodule update --init --recursive (for remaining branchs)
if you get fatal need single revision error then use below commands:-
before:-
*** stage
remotes/origin/stage**
git branch -a
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/{branch name}
ex:- git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/stage
after:-
*** stage
remotes/origin/HEAD -> origin/stage
remotes/origin/stage**
then
> git reset --hard
#hard reset revisions#
> git submodule foreach git reset --hard origin/develop
> git submodule foreach git pull origin develop
после фиксации и нажатия соответственно. Теперь подмодули будут обновляться.