Как указать ветку/тег при добавлении подмодуля Git?

Как работает git submodule add -b?

После добавления подмодуля с определенной веткой новый клонированный репозиторий (после git submodule update --init) будет при определенной фиксации, а не сама ветвь (git status в подмодуле показывает "В настоящее время не в какой-либо ветке").

Я не могу найти никакой информации в .gitmodules или .git/config о ветке подмодулей или о каком-либо конкретном коммите, так как Git это выясняет?

Кроме того, возможно ли указать тег вместо ветки?

Я использую версию 1.6.5.2.

Ответы

Ответ 1

Примечание: в 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 --init

Изменения git pull которые указывает их каталог подмодулей. git submodule update фактически сливается с новым кодом.

Ответ 2

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

Вы знаете, что у вас есть подмодуль Git, когда у вас есть эти две вещи.

  1. Ваш .gitmodules имеет такую запись:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. У вас есть объект субмодуля (в данном примере с именем 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
    

    Примечание: в файле .gitmodules поддерживается только имя ветки, но SHA и TAG не поддерживаются! (вместо этого фиксация ветвей каждого модуля может отслеживаться и обновляться с помощью " git add. ", например, как git add./SubmoduleTestRepo, и вам не нужно каждый раз .gitmodules файл .gitmodules)

    Объект подмодуля по-прежнему указывает на конкретный коммит. Единственная вещь, -b покупает опция -b, - это возможность добавить флаг --remote к вашему обновлению согласно ответу Vogella:

    git submodule update --remote
    

    Вместо того, чтобы заполнять содержимое подмодуля коммитом, на который указывает субмодуль, он заменяет этот коммит последним коммитом в основной ветке, ПОТОМ он заполняет субмодуль этим коммитом. Это можно сделать в два шага с помощью ответа djacobs7. Поскольку вы обновили коммит, на который указывает объект подмодуля, вы должны зафиксировать измененный объект субмодуля в своем Git-репозитории.

    git submodule add -b не является каким-то волшебным способом поддерживать все в актуальном состоянии с помощью ветки. Он просто добавляет информацию о ветке в файл .gitmodules и дает вам возможность обновить объект подмодуля до последней фиксации указанной ветки перед ее .gitmodules.

Ответ 3

(Git 2.22, Q2 2019, представил git submodule set-branch --branch aBranch -- <submodule_path>)

Обратите внимание, что если у вас есть субмодуль, который еще не отслеживает ветку, то (если у вас 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

Обратите внимание, что результатом для каждого обновленного подмодуля почти всегда будет отдельная ГОЛОВА, как отмечает Дэн Кэмерон в своем ответе.

(Клинт отмечает в комментариях, что если вы запустите 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, рекомендованное в комментариях Александра Погребняка.
$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)'

Ответ 4

В Git 1.8.2 добавлена возможность отслеживать ветки.

# add submodule to track master branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

Смотрите также Git submodules

Ответ 5

Пример того, как я использую подмодули Git.

  1. Создать новый репозиторий
  2. Затем клонируйте другой репозиторий как подмодуль
  3. Тогда у нас есть этот подмодуль, использующий тег V3.1.2
  4. И тогда мы совершаем.

И это выглядит примерно так:

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 

Может быть, это помогает (хотя я использую тег, а не ветку)?

Ответ 6

По моему опыту переключение ветвей в суперпроект или будущие проверки все равно вызовет отсоединенные HEADs подмодулей, независимо от того, правильно ли добавлен и отслеживается подмодуль (т.е. ответы @djacobs7 и @Johnny Z).

И вместо ручной проверки правильной ветки вручную или через script git подмодуль foreach можно использовать.

Это проверит файл конфигурации подмодуля для свойства ветвления и проверит установленную ветвь.

git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'

Ответ 7

Подмодули Git немного странные - они всегда находятся в режиме "отстраненной головы" - они не обновляются до последнего коммита на ветке, как вы могли ожидать.

Это имеет некоторый смысл, когда вы думаете об этом, хотя. Допустим, я создаю репозиторий foo с панелью субмодулей. Я отправляю свои изменения и говорю вам проверить коммит a7402be из репозитория foo.

Затем представьте, что кто-то вносит изменения в панель репозитория, прежде чем вы сможете сделать свой клон.

Когда вы проверяете коммит a7402be из репозитория foo, вы ожидаете получить тот же код, который я нажал. Вот почему подмодули не обновляются, пока вы не скажете им явно, а затем сделаете новый коммит.

Лично я думаю, что подмодули - самая запутанная часть Git. Есть много мест, которые могут объяснить подмодули лучше, чем я. Я рекомендую Pro Git от Скотта Чакона.

Ответ 8

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

  • cd в корневой каталог вашего репозитория, содержащего подмодули
  • Откройте .gitmodules для редактирования
  • Добавьте строку под path =... и url =... которой написано branch = your-branch, для каждого подмодуля; сохранить файл .gitmodules.
  • затем без изменения каталога выполните $ git submodule update --remote

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

Ответ 9

У меня есть это в моем файле .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 = [email protected]/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-"

Ответ 10

Мы используем Quack для извлечения определенного модуля из другого репозитория Git. Нам нужно извлекать код без всей кодовой базы предоставленного репозитория - нам нужен очень специфический модуль/файл из этого огромного репозитория, и его следует обновлять каждый раз, когда мы запускаем update.

Итак, мы достигли этого следующим образом:

Создать конфигурацию

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

И это тянет код из вышеуказанных конфигураций.

Ответ 11

Единственный эффект выбора ветки для подмодуля состоит в том, что всякий раз, когда вы передаете --remote в командной строке git submodule update, Git будет проверять в режиме отсоединенного HEAD (если --checkout поведение по умолчанию --checkout) самую последнюю коммит этой выбранной удаленной ветки.

Вы должны быть особенно осторожны при использовании этой функции удаленного отслеживания ветвей для подмодулей Git, если вы работаете с мелкими клонами подмодулей. Ветвь, которую вы выбираете для этой цели в настройках подмодуля, НЕ является той, которая будет клонирована при git submodule update --remote. Если вы также --depth параметр --depth и не будете --depth Git, какую ветку вы хотите клонировать - и на самом деле вы не можете это сделать в командной строке git submodule update !! -, он будет неявно вести себя так, как описано в документации git-clone(1) для git clone --single-branch когда явный параметр --branch отсутствует, и поэтому он будет клонировать только первичную ветвь.

Неудивительно, что после этапа клонирования, выполненного командой git submodule update, он, наконец, попытается проверить последний коммит для удаленной ветки, которую вы ранее настроили для подмодуля, и, если это не основной модуль, это не является частью вашего локального мелкого клона, и поэтому он потерпит неудачу с

фатальный: требуется одна ревизия

Невозможно найти текущую версию источника/версию NotThePrimaryBranch в пути к субмодулю 'mySubmodule'

Ответ 12

подмодуль git add -b разработка --name имя-ветки - https://branch.git