Обновить подмодуль Git до последней фиксации в origin

у меня есть проект с подмодулем Git. Это из ssh://... URL, и находится на commit A. Commit B был нажат на этот URL, и я хочу, чтобы подмодуль извлек фиксацию и изменился на нее.

теперь, насколько я понимаю, это git submodule update должен сделать это, но это не так. Он ничего не делает (нет вывода, код выхода успеха). Вот пример:

$ mkdir foo
$ cd foo
$ git init .
Initialized empty Git repository in /.../foo/.git/
$ git submodule add ssh://user@host/git/mod mod
Cloning into mod...
user@host's password: hunter2
remote: Counting objects: 131, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 131 (delta 54), reused 0 (delta 0)
Receiving objects: 100% (131/131), 16.16 KiB, done.
Resolving deltas: 100% (54/54), done.
$ git commit -m "Hello world."
[master (root-commit) 565b235] Hello world.
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 mod
# At this point, ssh://user@host/git/mod changes; submodule needs to change too.
$ git submodule init
Submodule 'mod' (ssh://user@host/git/mod) registered for path 'mod'
$ git submodule update
$ git submodule sync
Synchronizing submodule url for 'mod'
$ git submodule update
$ man git-submodule 
$ git submodule update --rebase
$ git submodule update
$ echo $?
0
$ git status
# On branch master
nothing to commit (working directory clean)
$ git submodule update mod
$ ...

Я также пробовал git fetch mod, который, похоже, выполняет выборку (но не может, потому что это не подсказка пароль!), но git log и git show отрицать наличие новых коммитов. До сих пор я просто rm-ing модуль и повторное добавление его, но это как неправильно в принципе, так и утомительно на практике.

9 ответов


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

таким образом:

# get the submodule initially
git submodule add ssh://bla submodule_dir
git submodule init

# time passes, submodule upstream is updated
# and you now want to update

# change to the submodule directory
cd submodule_dir

# checkout desired branch
git checkout master

# update
git pull

# get back to your project root
cd ..

# now the submodules are in the state you want, so
git commit -am "Pulled down update to submodule_dir"

или, если вы занятой человек:

git submodule foreach git pull origin master

Git 1.8.2 имеет новую опцию --remote Это позволит именно такое поведение. Бег!--4-->

git submodule update --remote --merge

будет извлекать последние изменения из upstream в каждом подмодуле, объединять их и проверять последнюю версию подмодуля. As документы это:

--remote

эта опция действительна только для команды update. Вместо использования записанного SHA-1 суперпроекта для обновления подмодуля используйте состояние ветвь дистанционного слежения подмодуля.

Это эквивалентно запуску git pull в каждом подмодуле, что, как правило, именно то, что вы хотите.


в вашем Родительском каталоге проекта запустите:

git submodule update --init 

или если у вас есть рекурсивные подмодули:

git submodule update --init --recursive

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

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

git submodule update --init --recursive 

ваш основной проект указывает на конкретную фиксацию, в которой должен находиться подмодуль. Что?!--3--> делает, чтобы попытаться проверить, что фиксация в каждом подмодуле, который был инициализирован. Подмодуль действительно является независимым репозиторием - просто создайте новую фиксацию в подмодуле и нажмите, что недостаточно, вам также нужно явно добавить новую версию подмодуля в основной проект.

Итак, в вашем случае вы должны найти правильную фиксацию в подмодуле-давайте предположим, что это подсказка мастера:

cd mod
git checkout master
git pull origin master

теперь вернитесь к основному проекту, выполните подмодуль и зафиксируйте это:

cd ..
git add mod
git commit -m "Updating the submodule 'mod' to the latest version"

теперь нажмите новую версию основного проекта:

git push origin master

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


похоже, что в этом обсуждении смешиваются 2 разных сценария:

Сценарий 1

используя указатели моего родительского РЕПО на подмодули, я хочу проверить фиксацию в каждом подмодуле, на которую указывает родительское РЕПО, возможно, после первой итерации через все подмодули и обновления/вытягивания их из удаленного.

это, как указывалось, сделано с

git submodule foreach git pull origin BRANCH
git submodule update

Сценарий 2, который я подумайте, на что нацелен OP

новый материал произошел в 1 или более подмодулях, и я хочу 1) вытащить эти изменения и 2) обновить родительское репо, чтобы указать на головную (последнюю) фиксацию этого/этих подмодулей.

это будет сделано с помощью

git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH

не очень практично, так как вам придется жестко закодировать N путей ко всем N подмодулям, например, в скрипте для обновления указателей фиксации родительского РЕПО.

что было бы круто бы автоматическая итерация через каждый подмодуль, обновление родительского указателя РЕПО(с помощью git add), чтобы указать на головку подмодуля (ов).

для этого я сделал этот маленький bash-скрипт:

git-update-submodules.sh

#!/bin/bash

APP_PATH=
shift

if [ -z $APP_PATH ]; then
  echo "Missing 1st argument: should be path to folder of a git repo";
  exit 1;
fi

BRANCH=
shift

if [ -z $BRANCH ]; then
  echo "Missing 2nd argument (branch name)";
  exit 1;
fi

echo "Working in: $APP_PATH"
cd $APP_PATH

git checkout $BRANCH && git pull --ff origin $BRANCH

git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"

for i in $(git submodule foreach --quiet 'echo $path')
do
  echo "Adding $i to root repo"
  git add "$i"
done

git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH

, чтобы запустить его, выполните

git-update-submodules.sh /path/to/base/repo BRANCH_NAME

разработки

прежде всего, я предполагаю, что ветвь с именем $BRANCH (2-й аргумент) существует на всех РЕПО. Не стесняйтесь, чтобы сделать это еще более сложным.

первая пара разделов - это проверка наличия аргументов. Затем я вытаскиваю последние вещи родительского РЕПО (я предпочитаю использовать --ff (fast-forwarding) всякий раз, когда я просто делаю тянет. У меня есть rebase off, кстати).

git checkout $BRANCH && git pull --ff origin $BRANCH

тогда может потребоваться инициализация некоторых подмодулей, если новые подмодули были добавлены или еще не инициализированы:

git submodule sync
git submodule init
git submodule update

затем я обновляю/вытягиваю все подмодули:

git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"

обратите внимание на несколько вещей: прежде всего, я связываю некоторые команды git с помощью && - значение предыдущей команды должны выполнить W ошибка ввода-вывода.

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

наконец, заключительный || true это сделать сценарий на ошибки. Чтобы сделать эту работу, все в итерации должны быть заключены в двойные кавычки и Git-команды обернуты в parantheses (приоритет операторов).

моя любимая часть:

for i in $(git submodule foreach --quiet 'echo $path')
do
  echo "Adding $i to root repo"
  git add "$i"
done

повторите все подмодули-с --quiet, который удаляет вывод "ввод MODULE_PATH". Используя 'echo $path' (должно быть в одинарных кавычках), путь к подмодулю записывается на вывод.

этот список относительный пути подмодулей захватываются в массив ($(...)) - наконец повторите это и сделайте git add $i для обновления родительского РЕПО.

наконец, фиксация с некоторым сообщением, объясняющим, что родительское РЕПО было обновлено. Эта фиксация будет проигнорирована по умолчанию, если ничего не было сделано. Подтолкните это к origin, и вы закончите.

у меня есть скрипт, выполняющий это в Jenkins-job, который после этого привязывается к запланированному автоматическому развертыванию, и он работает как шарм.

я надеюсь это кому-то поможет.


простой и простой, чтобы получить подмодули:

git submodule update --init --recursive

и теперь продолжайте обновлять их до последней главной ветви (например):

git submodule foreach git pull origin master

@Jason верен в некотором смысле, но не полностью.

обновление

обновить зарегистрированные подмодули, т. е. клонировать отсутствующие подмодули и проверка фиксации, указанной в индекс содержащего репозитория. Это сделает головку submodules отсоединен, если --rebase или --merge не задано или ключ подмодуль.$имя.update имеет значение rebase или слияния.

Итак, обновление подмодуля git делает проверку, но дело в том,, это-фиксация в индексе содержащего репозитория. Он еще не знает о новом commit upstream вообще. Поэтому перейдите в свой подмодуль, получите нужную фиксацию и зафиксируйте обновленное состояние подмодуля в главном РЕПО, а затем выполните git submodule update


вот удивительный однострочный, чтобы обновить все до последней версии на master:

git submodule foreach 'git fetch origin --tags; git checkout master; git pull' && git pull && git submodule update --init --recursive

спасибо Mark Jaquith


в моем случае, я хотел git обновить до последней и в то же время повторно заполнить все недостающие файлы.

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

git submodule update --init --recursive --force

это сделал:

git submodule update --recursive --remote --merge --force