简单的方法来提取所有git子模块的最新信息


1846

我们正在使用git子模块来管理几个大型项目,这些项目依赖于我们开发的许多其他库。每个库都是作为子模块带入相关项目的单独的存储库。在开发过程中,我们经常只想获取每个依赖子模块的最新版本。

git有内置命令可以做到这一点吗?如果不是,那么可以执行Windows批处理文件或类似文件?


git-deep应该可以帮助您。
Mathew Kurian

9
@Brad是否要将子模块的副本更新为主项目中命名的commit revs?还是要从每个子模块中提取最新的HEAD提交?这里的大多数答案都针对前者。许多人想要后者。
chrisinmtown

Answers:


2462

如果这是您第一次签出回购协议,则需要先使用--init

git submodule update --init --recursive

对于git 1.8.2或更高版本,--remote添加了该选项以支持更新到远程分支的最新提示:

git submodule update --recursive --remote

这样做有一个额外的好处,.gitmodules.git/config可以遵守or 文件中指定的任何“非默认”分支(如果碰巧有默认分支,则默认为origin / master,在这种情况下,此处的其他一些答案也可以使用)。

对于git 1.7.3或更高版本,您可以使用(但以下有关更新的陷阱仍然适用):

git submodule update --recursive

要么:

git pull --recurse-submodules

如果您想将子模块拉到最新的提交,而不是当前的提交,则仓库指向该提交。

混帐子模块(1)了解详细信息


299
也许您git submodule update --recursive现在应该使用。
詹斯·科尔

38
性能提升:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev

18
更新会将每个子模块更新为指定的修订版,而不是将其更新为该存储库的最新版本。
彼得·德威斯

21
只需添加一下,origin master如果您的某些子模块跟踪该特定子模块的不同分支或位置名称,则盲目地粘贴在此命令的末尾可能会产生意外结果。对某些人很明显,但可能对每个人都不是。
内森·霍恩比

31
只是为了向大家澄清。git submodule update --recursive会查看父存储库为每个子模块存储了哪个修订,然后在每个子模块中检出该修订。它拉的最新提交的每个子模块。git submodule foreach git pull origin master或者git pull origin master --recurse-submodules如果您打算将每个子模块从其原始存储库更新到最新版本,则是您想要的。只有这样,您才能在父存储库中获得待处理的更改,并带有子模块的更新的修订哈希。检查那些就可以了。
CHEV

636
git pull --recurse-submodules --jobs=10

git在1.8.5中首次学习的功能。

错误修复之前,您第一次需要运行

git子模块更新--init --recursive


29
upvoted,我使用这样的:别名update_submodules =“git的拉--recurse-子模块&& git的子模块更新”
斯蒂芬Ç

3
如果子模块至少已被拉出一次,但对于从未检出的子模块,则此方法有效,请参见下面的gahooa答案。
马特·布朗

8
这将拉到最高仓库指定的版本;它不会拉头。例如,如果TopRepo在SubRepo的HEAD后面指定了版本2,则这会将SubRepo拉到落后2的版本。这里的其他答案在SubRepo中拉HEAD。
克里斯·

11
需要注意的是既不git pull --recurse-submodulesgit submodule update --recursive不会初始化新添加的子模块。要初始化它们,您需要运行git submodule update --recursive --init。引自手册如果尚未初始化子模块,而您只想使用存储在.gitmodules中的设置,则可以使用--init选项自动初始化子模块。
patryk.beza

1
可能会添加提示,git submodule update --recursive --remote该提示还会将子模块更新为远程最新版本,而不是存储的SHA-1。
Hanno S.

386

在初始化时运行以下命令:

git submodule update --init --recursive

从git repo目录中,最适合我。

这将拉动所有最新的包括子模块。

讲解

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            --init without the explicit init step if you do not intend to customize
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

之后,您可以运行:

git submodule update --recursive

从git repo目录中,最适合我。

这将拉动所有最新的包括子模块。


10
是的-投票得最高的答案是'09做到这一点的最好方法,但是现在这绝对是更简单和直观的方法。
Michael Scott Cuthbert 2015年

2
@MichaelScottCuthbert谢谢,我敢肯定,再过3年,这个命令也会太疯狂了
abc123

5
但是,这不会从子模块中检出最新修订,而只会签出父级正在跟踪的最新修订。
内森·奥斯曼

4
@NathanOsman是您想要的...您将不遵循父修订版跟踪而导致代码损坏。如果您是父母的维护者,则可以自己更新并提交。
abc123 2016年

2
是的,但是据我了解,这不是OP想要的。
内森·奥斯曼

305

注意:这是从2009年开始的,那时可能还不错,但是现在有更好的选择。

我们用这个。叫做git-pup

#!/bin/bash
# Exists to fully update the git repo that you are sitting in...

git pull && git submodule init && git submodule update && git submodule status

只需将其放在合适的bin目录中(/ usr / local / bin)。如果在Windows上,则可能需要修改语法才能使其起作用:)

更新:

为了回应原始作者关于引入所有子模块的所有HEAD的评论,这是一个好问题。

我很确定git内部没有此命令。为此,您需要确定子模块的真正含义是什么。那可能很简单master最新分支,等等。

之后,创建一个简单的脚本,该脚本执行以下操作:

  1. 检查git submodule status“修改后的”存储库。输出行的第一个字符表明了这一点。如果修改了子仓库,您可能不想继续。
  2. 对于列出的每个存储库,cd进入其目录并运行git checkout master && git pull。检查错误。
  3. 最后,我建议您向用户打印显示以指示子模块的当前状态-也许提示他们添加所有并提交?

我想提一下,这种样式并不是git子模块真正设计的目的。通常,您想说“ LibraryX”的版本是“ 2.32”,并且会一直保持这种状态,直到我告诉它“升级”为止。

也就是说,从某种意义上讲,您正在描述的脚本中执行的操作只是自动进行。需要小心!

更新2:

如果您使用的是Windows平台,则可能要考虑使用Python来实现脚本,因为它在这些方面非常有能力。如果您使用的是unix / linux,那么我建议您只使用bash脚本。

需要任何澄清吗?只需发表评论。


我认为那不是我想要的。不会拉出上次提交超级项目的子模块的版本。我想拉所有子模块的头版。
布拉德·罗宾逊

3
这很好用,不仅可以更新子模块,而且还可以在需要时首次获取它们。
马特·布朗

我刚得到“当前分支没有跟踪信息。请指定要合并的分支。” 无论我尝试什么:/
Nathan Hornby 2014年

9
为什么不为其创建别名?git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'然后将其用作git pup无需任何脚本。
fracz

谢谢,由于某些原因,即使我拥有git 1.9.1,我也必须git submodule init在第一次拉动之后执行该操作,其中包括子模块,以便一切都能正常工作。
Ben Usman

164

亨里克走在正确的轨道上。“ foreach”命令可以执行任何任意的shell脚本。有两种选择可以获取最新的信息,

git submodule foreach git pull origin master

和,

git submodule foreach /path/to/some/cool/script.sh

这将遍历所有初始化的子模块并运行给定的命令。


144

以下在Windows上对我有用。

git submodule init
git submodule update

6
这显然不是OP所要求的。它只会更新到关联的子模块提交,而不是最新的。
Patrick

52
但是,这是此页面上唯一让git在我第一次签出存储库时提取子模块的东西
theheadofabroom 2013年

2
还可使用:git子模块更新--init --recursive(特别是如果所涉及的子模块是来自新克隆的
RestKit

33

编辑

在评论中(由philfreo指出),需要最新版本。如果有任何嵌套子模块需要最新版本:

git submodule foreach --recursive git pull

-----以下过时的评论-----

这不是官方的方式吗?

git submodule update --init

我每次都用它。到目前为止没有问题。

编辑:

我刚刚发现您可以使用:

git submodule foreach --recursive git submodule update --init 

这也将递归地拉动所有子模块,即依赖关系。


5
您的回答没有回答OP的问题,但是您可以按照建议的去做git submodule update --init --recursive
philfreo 2011年

2
我知道,需要最新版本。那么,如果存在嵌套的子模块,这可能会很有用: git submodule foreach --recursive git pull

1
我无法真正下载所有这些文件,但是“ git子模块更新--init --recursive”对我有用。
BrainSlugs83

33

可能会发生子模块的默认分支不是 master,这就是我自动完成Git子模块完整升级的方式:

git submodule init
git submodule update
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'

在许多问题的众多答案中,这一个对我
有用

30

第一次

克隆和初始化子模块

git clone git@github.com:speedovation/kiwi-resources.git resources
git submodule init

休息

在开发过程中,只需拉出并更新子模块

git pull --recurse-submodules  && git submodule update --recursive

将Git子模块更新为最新的原始提交

git submodule foreach git pull origin master

首选方式应该在下面

git submodule update --remote --merge

注意:最后两个命令具有相同的行为


我做了一个git clone,错误地没有子模块,所有其他选项都没有用,没有人克隆子模块。用你的,git submodule update把戏。现在,我正在下载克隆第一步中缺少的子模块数据。谢谢。我不太擅长git:C
m3nda

这雁实际上是一个很好的答案在这里提出在上面一个问题:为什么我要为“.. --recursive-子模块。”然后另外的“...更新中...” 连” .. .foreach ...”稍后获取最新提交?所有这些看起来都不像GIT!“更新”在做什么,为什么我必须手动进入每个模块才能拉动?这不是“ ... --recurse-submodules ..”在做什么吗?有什么提示吗?
Peter Branforn

20

我不知道这是从哪个版本的git开始工作,但这就是您要搜索的内容:

git submodule update --recursive

我也使用它git pull来更新根存储库:

git pull && git submodule update --recursive

10

上面的答案很好,但是我们使用git-hooks使其更容易,但事实证明,在git 2.14中,可以将其设置git config submodule.recurse为true,以使子模块在拉到git存储库时得以更新。

但是,如果所有子模块都在分支上,这将产生推动所有子模块更改的副作用,但是如果您已经需要这种行为,则可以完成此工作。

可以使用以下方法完成:

git config submodule.recurse true

一定喜欢这个选项,不幸的git submodule init是,即使您的子模块尚未初始化,仍需要手动使用。
Pellet

5

适用于Windows 2.6.3的 Git :

git submodule update --rebase --remote


那是唯一为我工作的人。我什至无法初始化或更新,因为子模块指针所指向的版本不再是远程版本
Pavel P

4

从仓库的顶层:

git submodule foreach git checkout develop
git submodule foreach git pull

这将切换所有分支机构以开发并拉动最新的


2
不适用于我,与git 2.7。
Bruno Haible

您是否有类似Everything sln文件的内容,该文件在树中添加了所有项目引用?您还会看到什么错误?您也可以检查您的gitignore文件吗
Srayan Guhathakurta,

1
git submodule foreach git pull origin master必须追加我要提取的分支。除此之外,效果很好。
19:10

3

我是通过改写gahooa上述回答来做到这一点的:

将其与git集成[alias]...

如果您的父项目在中具有以下内容.gitmodules

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = git@github.com:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = git@github.com:jkaving/intellij-colors-solarized.git

在您的.gitconfig中添加类似的内容

[alias]
    updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "

然后,要更新您的子模块,请运行:

git updatesubs

我有一个例子我在它的环境设置回购


3

您现在所要做的就是一个简单的 git checkout

只要确保通过以下全局配置启用它即可: git config --global submodule.recurse true


2

这是从所有git存储库中提取命令行的命令行,无论它们是否是子模块:

ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'

如果您在顶级git存储库中运行它,则可以替换"$ROOT".


1

我认为您必须编写脚本才能执行此操作。说实话,我可能会安装Python来做到这一点,这样就可以使用os.walkcd每个目录,并发出相应的指令。使用python或其他批处理语言(批处理除外)可以使您轻松添加/删除子项目,而无需修改脚本。


1

备注:不太容易,但是可行,并且它有自己独特的优点。

如果只想克隆HEAD一个版本库和HEAD它的所有子模块中的一个(即检出“ trunk”),则可以使用以下Lua脚本。有时,简单的命令git submodule update --init --recursive --remote --no-fetch --depth=1可能会导致无法恢复的git错误。在这种情况下,需要清理目录的.git/modules子目录并使用git clone --separate-git-dir命令手动克隆子模块。唯一的复杂性是找出URL的路径.git在超级项目树中子模块目录的路径和子模块的路径。

备注:该脚本仅针对https://github.com/boostorg/boost.git存储库进行测试。它的特点:所有子模块都托管在同一主机上,并且.gitmodules仅包含相对URL

-- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git .
local module_url = arg[1] or 'https://github.com/boostorg/boost.git'
local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git')
local branch = arg[3] or 'master'
function execute(command)
    print('# ' .. command)
    return os.execute(command)
end
-- execute('rm -rf ' .. module)
if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then
    io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n')
    return 1
end
-- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1
execute('mkdir -p ' .. module .. '/.git/modules')
assert(io.input(module .. '/.gitmodules'))
local lines = {}
for line in io.lines() do
    table.insert(lines, line)
end
local submodule
local path
local submodule_url
for _, line in ipairs(lines) do
    local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$')
    if submodule_ then
        submodule = submodule_
        path = nil
        submodule_url = nil
    else
        local path_ = line:match('^%s*path = (.+)$')
        if path_ then
            path = path_
        else
            submodule_url = line:match('^%s*url = (.+)$')
        end
        if submodule and path and submodule_url then
            -- execute('rm -rf ' .. path)
            local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$')
            -- execute('rm -rf ' .. git_dir)
            execute('mkdir -p $(dirname "' .. git_dir .. '")')
            if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then
                io.stderr:write('can\'t clone submodule ' .. submodule .. '\n')
                return 1
            end
            path = nil
            submodule_url = nil
        end
    end
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.