Як я можу вказати гілку / тег при додаванні підмодуля Git?


756

Як git submodule add -bпрацює?

Після додавання підмодуля з певною гілкою, новий клонований сховище (після git submodule update --init) буде в конкретному комітеті, а не самій гілці ( git statusна підмодулі відображається "Наразі немає жодної гілки").

Я не можу знайти будь-яку інформацію про .gitmodulesабо .git/configпро відділення підмодуля чи якесь певне завдання, так як Git розібрається в цьому?

Також, чи можна вказати тег замість гілки?

Я використовую версію 1.6.5.2.


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

Відповіді:


745

Примітка: 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

Потім інший розробник, який хоче, щоб субмодуль_директорія змінено на цей тег, робить це

git pull
git submodule update --init

git pullзміни, на які вказує їх каталог підмодулів. git submodule updateфактично зливається в новому коді.


8
Це дуже вдале пояснення, дякую! І звичайно, прочитавши вашу відповідь, я зрозумів, що фіксація зберігається всередині самого підмодуля (submodule / .git / HEAD).
Іван

4
Схоже, це не працює на git 1.7.4.4. cd my_submodule; git checkout [ref in submodule's repositoryврожайність fatal: reference is not a tree: .... Це як би gitпрацюватиме лише в батьківському сховищі.
Джеймс А. Росен

3
Корисно використовувати підмодулі git навіть для проектів, які часто оновлюються. Ядро linux використовує це, і це не так вже й погано

10
Це git checkout v1.0гілка чи тег?
Бернхард Дьоблер

8
Розгляньте тег, який читається людиною, псевдонім до комітету. І фіксація - це набір конкретного стану для кожного файлу. Гілка - це по суті те саме, за винятком того, що ви можете внести зміни до неї.
deadbabykitten

656

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

Ви знаєте, що у вас є підмодуль Git, коли у вас є ці дві речі.

  1. У вас .gitmodulesє такий запис:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. У вашому репозиторії Git у вас є об'єкт підмодуля (названий SubmoduleTestRepo в цьому прикладі). 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файл щоразу)

    Об'єкт підмодуля все ще вказує на певний коміт. Єдине, що -bопція купує вам - це можливість додавати--remote купуєте прапор до оновлення відповідно до відповіді Vogella:

    git submodule update --remote
    

    Замість того, щоб заповнити вміст підмодуля до комітету, на який вказує підмодуль, він замінює цю команду останньою командою на головній гілці; Це можна зробити за два етапи за допомогою відповіді djacobs7. Оскільки ви зараз оновили фіксацію, на яку вказує об'єкт підмодуля, вам слід скористатись зміненим об'єктом субмодуля у вашому сховищі Git.

    git submodule add -bце не якийсь магічний спосіб, щоб все було в курсі гілки. Він просто додає інформацію про гілку у .gitmodulesфайл і надає можливість оновити об'єкт підмодулю до останнього коміту зазначеної гілки перед його заповненням.


14
Ця відповідь повинна мати більше голосів. Я читав багато дописів за минулий день, і це очищує всю плутанину. Виходячи зі світу SVN та користуючись зовнішніми, хочеться повірити, що відстеження гілок підмодуля git магічно підтримує все в курсі цієї гілки - але це неправда! Ви повинні їх явно оновити! Як ви вже згадували, ви повинні вчинити змінені об'єкти підмодуля.
dtmland

12
Чи працює це відстеження гілок і з тегами ? Замість гілки я вказав тег у своєму, .gitmodulesі після цього $ git submodule update --init --remote TestModuleя отримав помилку із зазначенням fatal: Needed a single revisionі Unable to find current origin/TestTag revision in submodule path 'TestModule'. Коли це робиться з справжньою гілкою, вона працює. Чи все-таки потрібно вказати тег, .gitmodulesне вказуючи точну комісію?
Hhut

5
Це, здається, не працює. Я оновив хеш .gitmodulesі побіг, git submodule updateі нічого не сталося?
CMCDragonkai

2
Якось це не працює для мене. Ідентифікатор комісії SHA завжди отримує помилку "Неможливо знайти поточну версію (я двічі перевірив номер редакції HEAD та його правильність). Однак, якщо я використовую master, він працює.
infoclogged

2
Введення SHA в атрибут гілки також не працює для мене. Це використання також не підтримується документами: git-scm.com/docs/gitmodules
Якуб

339

(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
    

         (З «» походження є ім'я вищого віддалений репозиторій підмодуля був клонований з.
         А 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+ (Q3 2016) ви можете використовувати " ." як ім'я гілки:

Назва філії записується як submodule.<name>.branchу .gitmodulesдля update --remote.
Особливе значення .використовується для вказівки на те, що назва гілки в підмодулі має бути тим самим іменем, що і поточна гілка в поточному сховищі .

Але , як зауважив по LubosD

Якщо git checkout, якщо назва гілки, яку слід слідувати, " .", це вб'є вашу незайняту роботу!
Використовуйте git switchзамість цього.

Це означає Git 2,23 (серпень 2019 року) або більше.

Див. " Плутатиgit checkout "


Якщо ви хочете оновити всі свої підмодулі за галуззю:

    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 switch $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 switch $branch' –

Та сама команда, але її легше читати:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git switch $branch' –

umläute уточнює команду dtmland зі спрощеною версією у коментарях :

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

кілька рядків:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

Перед Git 2.26 (I квартал 2020 р.) Виборка, яку повідомляють рекурсивно отримувати оновлення в підмодулях, неминуче створює перетворення результатів, і стає важко помітити повідомлення про помилки.

Команду вчили перелічувати підмодулі, які мали помилки в кінці операції .

Див. Комітет 0222540 (16 січня 2020 р.) Емілі Шаффер ( nasamuffin) .
(Об'єднав Хуніо С Хамано - gitster- у комітеті b5c71cc , 05 лютого 2020 р.)

fetch: підкреслити збій під час отримання субмодуля

Підписався: Емілі Шаффер

У випадках, коли підбір модуля виходить з ладу, коли є багато підмодулів, помилка від самотнього виходу з ладу підмодуля переховується під активністю на інших підмодулях, якщо більше одного з них випало fetch-by-oid.
Викликайте помилку пізно, щоб користувач усвідомлював, що щось пішло не так, і де .

Тому що fetch_finish()викликається лише синхронізуванням, run_processes_parallel,ніколи не вимагається навколо них submodules_with_errors.


1
Питання: якщо у мене є папка subModule1 і я хочу відстежувати головну гілку, чи отримана команда виглядатиме так: git config -f .gitmodules submodule.subModule1.branch master
BraveNewMath

1
foreachСценарій не буде залежати від захисту <path>, якщо ви замінюєте <path>з $toplevel/.
Олександр Погребняк

1
foreachСкрипт НЕ касові підмодулі, які не є гілкою. Однак ця команда дає вам обоє:git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch'
dtmland

2
ось спрощена версія сценарію @ dtmland:git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
umläute

1
Ох! Насправді сценарій foreach зайвий. Ми повинні виконати оновлення підмодуля за допомогою перемикача --merge або --rebase: git submodule update --remote --mergeабо git submodule update --remote --rebase. Ці команди виконують відстеження віддаленої гілки.
GregTom

206

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


4
Чи стосується це і тегів?
ThorSummoner

1
Як таким чином додавання підмодуля відображається на .gitmodulesфайлі?
Євген

1
Дякую, я щойно використав інформацію про те, щоб допомогти мені створити папку підмодуля, яка синхронізується з веб-сайтом gh-сторінок GitHub: повний приклад на github.com/o2platform/fluentnode/isissue/22
Дініс Крус

4
Ви можете заблокувати тег, з git submodule add -b tags/<sometag> <url>яким ви можете бачити рядок branch = tags/<sometag>у.gitmodules
KCD

9
@KCD Яка версія git може це робити з тегами. Моя не працює?
CMCDragonkai

58

Приклад того, як я використовую підмодулі 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 

Можливо, це допомагає (хоча я використовую тег, а не гілку)?


4
Це в основному така ж відповідь, як і djacobs7, але все одно дякую :)
Іван

1
Чи маєте ви змогу здійснити зміни після своїх git reset --hard V3.1.2? Я просто отримую "нічого робити" з git statusбатьківського каталогу.
Нік Радфорд

1
@Ivan: Чи можете ви пояснити, як це те саме, що відповідь djacobs7? Наскільки я бачу, його відповідь навіть не включає команду "додавання субмодуля", натомість репо додається безпосередньо, без будь-якого посилання на початковий git repo модуля. Принаймні, коли я спробував такий підхід, у .gitmodules не було зв’язку.
Мішель Мюллер

Відповідь djacobs7 не включає все пояснення, починаючи з додавання підмодуля. Він припускає, що у вас це вже є.
CodeMonkey

це не просто додає весь вміст підмодулю як відстежувані об'єкти до вашої основної репо?
користувач1312695

38

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

І замість того, щоб вручну перевірити правильну гілку вручну або через скрипт git, підмодуль може використовуватися foreach .

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

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


Приємно. +1. Я включив вашу команду у свою відповідь .
VonC

33

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

Це має певний сенс, коли ви думаєте про це. Скажімо, я створюю foo сховища з рядком субмодуля . Я натискаю свої зміни і кажу вам перевірити фіксацію a7402be з foo сховища .

Тоді уявіть, що хтось здійснює зміну бару сховищ, перш ніж ви зможете зробити свій клон.

Коли ви перевіряєте, виконувати a7402be з foo сховища , ви очікуєте отримати той самий код, який я натиснув. Ось чому підмодулі не оновлюються, поки ви не скажете їм їх чітко та не зробите нове зобов'язання.

Особисто я вважаю, що субмодулі є найбільш заплутаною частиною Git. Є багато місць, які можуть пояснити підмодулі краще, ніж я. Я рекомендую Pro Git від Скотта Чакона.


Я думаю, що настав час я почати читати деякі книги з git, дякую за рекомендацію.
Іван

Вибачте, але ви не уточнили, чи ви отримаєте те саме, що ви натиснули на a7402be, або отримаєте останню смугу, хоча ваша версія foo. Дякую :)
ммм

6
Проблема полягає в тому, що повинна бути опція сказати "зберегти цей підмодуль на гілці X", щоб, якщо ви ХОЧЕТЕ, щоб він автоматично оновлювався, то ви можете це зробити. Це зробить підмодулі набагато кориснішими для керування, наприклад, установкою WordPress, де плагіни - це все репост Git без необхідності повторного збереження надпроекту для кожного оновленого плагіна.
jerclarke

@jeremyclark git clone git://github.com/git/git.gitі натиснути цю функцію ...? = D
Аластер

1
Найбільш заплутаною частиною щодо Git є те, що навіть після більш ніж десятиліття розробки інструмент, який покликаний допомогти мені виконати свою роботу, все ще має такий поганий досвід користування, і з цілком інших причин люди люблять показувати пальцем Git all час.
0xC0000022L

20

Для перемикання гілки на підмодуль (якщо припустимо, що підмодуль вже є частиною сховища):

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

... це має містити останні коміти на вказаній гілці для кожного модифікованого таким чином підмодуля.


10

Я маю це у своєму файлі .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-"

3

Ми використовуємо 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

І він витягує код із наведених конфігурацій.


2

Єдиний ефект вибору гілки для підмодуля полягає в тому, що кожен раз, коли ви передаєте --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'


як виправити помилку - Потрібна була одна редакція?
NidhinSPradeep

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.