【问题标题】:Easy way to pull latest of all git submodules拉取最新的所有 git 子模块的简单方法
【发布时间】:2010-11-05 00:51:10
【问题描述】:

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

git 是否有内置命令来执行此操作?如果没有,那么可以使用 Windows 批处理文件或类似文件怎么样?

【问题讨论】:

  • git-deep 应该对此有所帮助。
  • @Brad 你想更新你的子模块副本到主项目中指定的提交版本吗?还是您想从每个子模块中提取最新的 HEAD 提交?这里的大多数答案都针对前者;很多人想要后者。

标签: git git-submodules


【解决方案1】:

如果是第一次您签出一个 repo,您​​需要首先使用--init

git submodule update --init --recursive

git 1.8.2或以上版本增加--remote选项,支持更新远程分支最新提示:

git submodule update --recursive --remote

这有一个额外的好处,即尊重.gitmodules.git/config 文件中指定的任何“非默认”分支(如果你碰巧有,默认是origin/master,在这种情况下,这里有一些其他答案也可以)。

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

git submodule update --recursive

或:

git pull --recurse-submodules

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

详情请见git-submodule(1)

【讨论】:

  • 现在你应该使用git submodule update --recursive
  • 性能提升:git submodule foreach "(git checkout master; git pull)&"
  • update 会将每个子模块更新到指定的版本,而不是将其更新到该存储库的最新版本。
  • 只是添加,如果您的某些子模块正在跟踪该特定子模块的不同分支或位置名称,则在此命令末尾盲目粘贴origin master 可能会产生意外结果。对某些人来说很明显,但可能不是对所有人。
  • 只是为大家澄清一下。 git submodule update --recursive 查看父存储库为每个子模块存储了哪个修订版,然后在每个子模块中检查该修订版。它确实 NOT 拉取每个子模块的最新提交。 git submodule foreach git pull origin mastergit pull origin master --recurse-submodules 是您想要的,如果您打算将每个子模块从其原始存储库更新到最新版本。只有这样,您才能在父 repo 中获得更新的子模块修订哈希值的未决更改。检查这些,你很好。
【解决方案2】:
git pull --recurse-submodules --jobs=10

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

bug 修复之前,第一次确实需要运行

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

【讨论】:

  • 赞成,我用这个:别名 update_submodules='git pull --recurse-submodules && git submodule update'
  • 如果子模块已经被拉出至少一次,但对于从未被签出的子模块,请参阅下面的 gahooa 的答案。
  • 这将拉到顶级仓库指定的版本;它不会拉头。例如,如果 TopRepo 为 SubRepo 指定 HEAD 后面的版本 2,这将使用该版本落后 2 的 SubRepo 拉取。这里的其他答案在 SubRepo 中拉 HEAD。
  • 请注意,git pull --recurse-submodulesgit submodule update --recursive初始化新添加的子模块。要初始化它们,您需要运行git submodule update --recursive --init。来自manual 的引用:如果子模块尚未初始化,而您只想使用存储在 .gitmodules 中的设置,则可以使用 --init 选项自动初始化子模块。跨度>
  • 可能会向git submodule update --recursive --remote 添加一个提示,这也会将子模块更新为远程最新版本,而不是存储的 SHA-1。
【解决方案3】:

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

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 目录,最适合我。

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

【讨论】:

  • 是的——投票最高的答案是 09 年最好的方法,但现在这绝对更简单、更直观。
  • @MichaelScottCuthbert 谢谢,我相信再过 3 年这个命令也会很疯狂
  • 尽管如此,这不会从子模块中检出最新版本,而只会检出父模块正在跟踪的最新版本。
  • @NathanOsman 这就是你想要的......如果不遵循父母的修订跟踪,你最终会得到损坏的代码。如果您是父级的维护者,您可以自己更新并提交它们。
  • 是的,但据我了解,这不是 OP 想要的。
【解决方案4】:

注意:这是 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 是最新的分支一样简单,等等......

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

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

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

也就是说,从某种意义上说,您使用所描述的脚本正在做什么,但只是更加自动。需要小心!

更新 2:

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

需要任何说明吗?只需发表评论。

【讨论】:

  • 我不认为这就是我想要的。这不会拉取超级项目最后提交的子模块的版本。我要拉出所有子模块的头部版本。
  • 这很好用,不仅可以更新子模块,还可以在需要时首次获取它们。
  • 我刚刚收到“当前分支没有跟踪信息。请指定要合并的分支。”无论我尝试什么:/
  • 为什么不为它创建一个别名呢? git config --global alias.pup '!git pull &amp;&amp; git submodule init &amp;&amp; git submodule update &amp;&amp; git submodule status',然后将其用作git pup,无需任何脚本。
  • 谢谢,出于某种原因,即使我有 git 1.9.1,我必须在第一次拉取包含子模块后执行 git submodule init,以便一切都开始正常工作。
【解决方案5】:

亨里克走在正确的轨道上。 'foreach' 命令可以执行任意的 shell 脚本。拉出最新版本的两个选项可能是,

git submodule foreach git pull origin master

和,

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

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

【讨论】:

    【解决方案6】:

    以下内容在 Windows 上对我有用。

    git submodule init
    git submodule update
    

    【讨论】:

    • 这显然不是 OP 所要求的。它只会更新到关联的子模块提交,而不是最新的。
    • 然而,这是我第一次签出 repo 时让 git 拉取子模块的唯一页面
    • 也可以使用:git submodule update --init --recursive(特别是如果有问题的子模块是来自新克隆的 RestKit)
    【解决方案7】:

    第一次

    克隆和初始化子模块

    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
    • 这个分析器实际上是一个很好的答案,可以在这里提出一个问题:为什么我必须“.. --recursive-submodules..”,然后是“... update 。 ..” 甚至“...foreach...” 之后才能获得最新的提交?这一切看起来一点也不像 GIT!什么是“更新”,为什么我必须手动去每个模块拉?这不是“... --recurse-submodules ..”在做什么吗?有什么提示吗?
    【解决方案8】:

    由于您的子模块的默认分支可能是 not 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'
    

    【讨论】:

    • 在众多问题的众多答案中,这个对我有用(2019,带有特定哈希 id 的 github 错误)
    【解决方案9】:

    编辑

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

    git submodule foreach --recursive git pull
    

    -----下面的过时评论-----

    这不是官方的做法吗?

    git submodule update --init
    

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

    编辑:

    我刚刚发现你可以使用:

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

    这也将递归提取所有子模块,即依赖项。

    【讨论】:

    • 您的回答没有回答 OP 的问题,但要按照您的建议去做,您可以说 git submodule update --init --recursive
    • 我明白了,需要最新版本。如果有嵌套的子模块,这可能很有用:git submodule foreach --recursive git pull
    • 我无法让其中任何一个实际下载任何东西——“git submodule update --init --recursive”对我有用。
    【解决方案10】:

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

    git submodule update --recursive
    

    我也将它与git pull 一起使用来更新根存储库:

    git pull && git submodule update --recursive
    

    【讨论】:

      【解决方案11】:

      对于我来说,git 2.24.03,更新到 .gitmoodule 中定义的远程分支的最新提交。

      git submodule update --recursive --init

      git submodule update --recursive --remote

      git 版本 2.24.3 (Apple Git-128)

      请注意: 有人这么说 git pull --recurse-submodulesgit submodule update --recursive --remote 相同。但根据我的测试,git pull --recurse-submodules 可能无法更新为 .gitmoodule 中定义的远程分支的最新提交。

      【讨论】:

        【解决方案12】:

        上面的答案很好,但是我们使用 git-hooks 来简化它,但事实证明,在 git 2.14 中,您可以将 git config submodule.recurse 设置为 true 以使子模块能够更新当你拉到你的 git 存储库时。

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

        可以使用:

        git config submodule.recurse true
        

        【讨论】:

        • 很喜欢这个选项,不幸的是,如果您的子模块尚未初始化,您仍需要事先使用git submodule init
        【解决方案13】:

        我经常使用这个命令,到目前为止还有效。

        git pull
        git submodule foreach --recursive git checkout master
        git submodule foreach --recursive git pull
        

        希望这更快。

        【讨论】:

          【解决方案14】:

          Git for windows 2.6.3

          git submodule update --rebase --remote

          【讨论】:

          • 这是唯一对我有用的。我什至无法初始化或更新,因为子模块指针指向一个不在远程的版本
          【解决方案15】:

          从 repo 的顶层开始:

          git submodule foreach git checkout develop
          git submodule foreach git pull
          

          这将切换所有分支以开发和拉最新

          【讨论】:

          • 您是否有类似 Everything sln 文件的东西,它将所有项目引用添加到树中?你还看到什么错误?你也可以检查你的 gitignore 文件吗
          • git submodule foreach git pull origin master 必须附加我想要获取的分支。除此之外,工作完美。
          【解决方案16】:

          根据从远程提取每个子模块的“最新”代码的现有答案来澄清一些事情。

          如果“latest”表示已签入的子模块指针,那么一定要使用:

          git submodule update --recursive
            - or -
          git pull --recurse-submodules --jobs=X
          

          如果 "latest" 表示 ma​​in 的最新版本,则可以使用以下方法:

          git submodule foreach "git checkout main && git pull"
          

          不幸的是,这意味着没有“--jobs”选项,所以我们不能并行运行它。我见过的最接近并行运行的方法是使用pfs python 代码。

          【讨论】:

            【解决方案17】:

            我通过改编gahooaanswer above来做到这一点:

            将其与 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
            

            我的environment setup repo 中有一个example

            【讨论】:

              【解决方案18】:

              您现在需要做的只是一个简单的git checkout

              只要确保通过这个全局配置启用它:git config --global submodule.recurse true

              【讨论】:

                【解决方案19】:

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

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

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

                【讨论】:

                  【解决方案20】:

                  备注:方法不太简单,但可行,有其独特的优点。

                  如果只想克隆存储库的HEAD 修订版和其所有子模块的HEADs(即检查“主干”),那么可以使用以下 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 只包含相对 URLs。

                  -- 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
                  

                  【讨论】:

                    【解决方案21】:

                    我认为您必须编写一个脚本来执行此操作。老实说,我可能会安装 python 来执行此操作,以便您可以对每个目录使用 os.walkcd 并发出相应的命令。使用 python 或其他脚本语言,而不是批处理,可以让您轻松添加/删除子项目,而无需修改脚本。

                    【讨论】:

                      猜你喜欢
                      • 2014-12-08
                      • 2012-11-26
                      • 2018-07-04
                      • 2021-09-13
                      • 1970-01-01
                      • 2012-02-29
                      • 1970-01-01
                      相关资源
                      最近更新 更多