我们使用git子模块来管理一些依赖于我们开发的许多其他库的大型项目。每个库都是一个单独的repo,作为子模块引入到依赖项目中。在开发过程中,我们经常想要获取每个依赖子模块的最新版本。
如何获取所有git子模块的最新更改?
我们使用git子模块来管理一些依赖于我们开发的许多其他库的大型项目。每个库都是一个单独的repo,作为子模块引入到依赖项目中。在开发过程中,我们经常想要获取每个依赖子模块的最新版本。
如何获取所有git子模块的最新更改?
当前回答
备注:不太容易,但可行,它有自己独特的优点。
若要只克隆存储库的HEAD修订版和所有子模块的HEAD(即签出“trunk”),那个么可以使用以下Lua脚本。有时,简单的命令git submodule update--init--recursive--remote--no fetch--depth=1会导致不可恢复的git错误。在这种情况下,需要清理.git/modules目录的子目录,并使用gitclone--separate gitdir命令手动克隆子模块。唯一的复杂性是在超级项目树中查找子模块的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
其他回答
上面的答案很好,不过我们使用了git钩子来简化这一过程,但事实证明,在git2.14中,您可以将git-config子模块.recure设置为true,以便在您拉到git存储库时更新子模块。
如果所有子模块都在分支上,这会产生一个副作用,即推动所有子模块的更改,但如果您已经需要这种行为,这可以完成任务。
可通过以下方式完成:
git config submodule.recurse true
以下内容在Windows上适用。
git submodule init
git submodule update
注:这是从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内部没有这个命令。为了做到这一点,您需要确定HEAD对于子模块的真正含义。这可能很简单,比如说master是最新的分支,等等。。。
接下来,创建一个简单的脚本,执行以下操作:
检查git子模块状态以查找“已修改”的存储库。输出行的第一个字符表示这一点。如果子回购被修改,您可能不想继续。对于列出的每个回购,将其cd到其目录中,并运行gitcheckout-master和gitpull。检查错误。最后,我建议您向用户打印一个显示,以指示子模块的当前状态——也许会提示他们添加全部并提交?
我想指出的是,这种风格并不是git子模块的设计初衷。通常,你想说“LibraryX”的版本是“2.32”,在我告诉它“升级”之前,它会一直这样。
从某种意义上说,这就是您使用所描述的脚本所做的事情,但只是更加自动。需要小心!
更新2:
如果您使用的是windows平台,您可能需要考虑使用Python来实现脚本,因为它在这些方面非常有用。如果您使用的是unix/linux,那么我建议您使用bash脚本。
需要澄清吗?只需发表评论。
从回购协议的顶层:
git submodule foreach git checkout develop
git submodule foreach git pull
这将切换所有分支机构以开发和拉动最新的
对我来说,git2.24.03,更新到.gitmodules中定义的远程分支的最新提交。
git子模块更新--递归--init
git子模块更新--递归--远程
git版本2.24.3(Apple git-128)
请注意:有人说过git pull-递归子模块与git子模块update-递归-远程相同。但根据我的测试,gitpull-recurse子模块可能不会更新为.gitmodules中定义的远程分支的最新提交。