将 Git 子模块更新为 origin 上的最新提交

发布于 2024-11-04 04:48:32 字数 1422 浏览 1 评论 0 原文

我有一个带有 Git 子模块的项目。它来自 ssh://... URL,位于提交 A 上。提交 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< /code> 和 git show 否认新提交的存在。到目前为止,我只是rm-ing模块并重新添加它,但这在原则上是错误的,而且在实践中很乏味。

I have a project with a Git submodule. It is from an ssh://... URL, and is on commit A. Commit B has been pushed to that URL, and I want the submodule to retrieve the commit, and change to it.

Now, my understanding is that git submodule update should do this, but it doesn't. It doesn't do anything (no output, success exit code). Here's an example:

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

I've also tried git fetch mod, which appears to do a fetch (but can't possibly, because it's not prompting for a password!), but git log and git show deny the existence of new commits. Thus far I've just been rm-ing the module and re-adding it, but this is both wrong in principle and tedious in practice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

放低过去 2024-11-11 04:48:33

如何更新存储库中的所有 git 子模块(两种方法可以完成两件非常不同的事情!)

快速摘要详细

# Option 1: as a **user** of the outer repo, pull the latest changes of the
# sub-repos as previously specified (pointed to as commit hashes) by developers
# of this outer repo.
# - This recursively updates all git submodules to their commit hash pointers as
#   currently committed in the outer repo.
git submodule update --init --recursive

# Option 2. As a **developer** of the outer repo, update all subrepos to force
# them each to pull the latest changes from their respective upstreams (ex: via
# `git pull origin main` or `git pull origin master`, or similar, for each
# sub-repo). 
git submodule update --init --recursive --remote
#
# For just Option 2 above: now add and commit these subrepo changes 
# you just pulled
git add -A
git commit -m "Update all subrepos to their latest upstream changes"

信息

  1. 选项 1:作为外部存储库的用户,尝试让所有子模块进入外部存储库开发人员预期的状态:
    git 子模块更新 --init --recursive
    
  2. 选项 2:作为外部存储库的开发人员,尝试将所有子模块更新为推送到每个远程存储库的默认分支的最新提交(即:将所有子存储库更新为每个子存储库的开发人员):
    git 子模块更新 --init --recursive --remote
    

    ...代替使用 git submodule foreach --recursive git pull origin master 或 git submodule foreach --recursive git pull origin main。

在我看来,上述两个选项的最佳答案是使用我在一些文件中看到的--merge--force选项其他答案。

上面使用的选项的说明:

  • 上面的 --init 部分会初始化子模块,以防您刚刚克隆了存储库但尚未执行此操作
  • --recursive 会执行此操作子模块内的子模块,永远递归下去
  • --remote表示将子模块更新到子模块默认远程上默认分支上的最新提交。在大多数情况下,这就像为每个子模块执行 git pull origin master 或 git pull origin main 。如果您想更新到最外层存储库(超级存储库)指定的提交,请关闭 --remote

git submodule foreach --recursive git pull (不要使用这个——它经常失败) vs git submodule update --recursive --remote (使用这个!--它总是有效)

我在在此答案下留下了以下评论。我认为它们很重要,所以我也将它们放入我的答案中。

基本上,在某些情况下, git submodule foreach --recursive git pull 可能会起作用。对于其他人, git submodule foreach --recursive git pull origin master 可能正是您所需要的。对于其他人, git submodule foreach --recursive git pull origin main 可能就是您所需要的。而对于其他人来说,这些都可能不起作用!例如,您可能需要git submodule foreach --recursive git pull upper upload。或者,更糟糕的是,可能没有任何适用于您的外部存储库的 git submodule foreach 命令,因为每个子模块可能需要不同的命令来从其默认远程更新自身和默认分支。然而,在所有情况下,我可以发现这确实有效,包括对于所有情况,您可能会使用多个git子模块之一我刚刚在上面介绍过 foreach 命令。因此,请改用这个:

git submodule update --recursive --remote

无论如何,以下是我对此在此答案下的几点评论:

(1/4) @DavidZ,很多人认为 git submodule foreach git pull 和 git submodule update --remote 是同一件事,后者只是较新的命令。然而,它们并不是同一件事。 git submodule foreach git pull在多种情况下失败,而 git submodule update --remote 工作得很好!如果您的子模块指向没有分支指向它的提交哈希(在现实开发中经常出现这种情况,您需要为外部存储库使用特定版本的子模块),那么该子模块...< /p>

(2/4)...处于分离的 HEAD 状态。在这种情况下,git submodule foreach git pull 无法在该子模块上运行 git pull ,因为分离的 HEAD 不能有上游分支。 git submodule update --remote,但是,工作得很好!如果origin,它似乎会在该子模块上调用git pull origin main 是默认远程,main 是该默认远程上的默认分支,或者 git pull origin master,例如,如果 origin 是默认遥控器,但 master 是默认遥控器分支。

(3/4) 此外,在许多情况下,git submodule foreach git pull origin master 甚至会失败,而 git submodule update --remote 工作得很好,因为许多情况子模块使用 master 作为默认分支,并且许多其他子模块使用 main 作为默认分支,因为 GitHub 从 master 更改为 main< /code> 最近为了摆脱相关条款美国的奴隶制(“主人”和“奴隶”)。


(4/4) 因此,我添加了显式远程和分支,以更清楚地表明它们是经常需要的,并提醒人们 git pull 经常是不够的,并且 git pull origin master 可能不起作用,而 git pull origin main 可能在前者不起作用时起作用,但也可能不起作用,并且 它们本身与 git submodule update 相同--remote,因为后一个命令足够智能,只需执行 git pull ; 为您的每个子模块,显然根据每个子模块的需要调整远程和分支。

另请参阅

  1. 我的 eRCaGuy_dotfiles 存储库中的指南:git 子模块“快速入门”指南。用它来让您的团队加入。

相关、&其他研究

  1. 我的一般git子模块注释:https://github.com/ElectricRCAaircraftGuy/eRCaGuy_dotfiles#git-submodules-and-git-lfs-how-to-clone-this-repo-and-all-git-submodules-and-git-lfs-files
  2. 如何查找存储库的主分支:https://stackoverflow.com/a/49384283/4561887
  3. 如何通过 git 子模块 foreach : https://stackoverflow.com/a/45744725/4561887
  4. man git submodule - 然后搜索 < code>foreach、--remote 等。
  5. 我对 如何解决包含 git 子模块的外部存储库中的冲突

How to update all git submodules in a repo (two ways to do two very different things!)

Quick summary

# Option 1: as a **user** of the outer repo, pull the latest changes of the
# sub-repos as previously specified (pointed to as commit hashes) by developers
# of this outer repo.
# - This recursively updates all git submodules to their commit hash pointers as
#   currently committed in the outer repo.
git submodule update --init --recursive

# Option 2. As a **developer** of the outer repo, update all subrepos to force
# them each to pull the latest changes from their respective upstreams (ex: via
# `git pull origin main` or `git pull origin master`, or similar, for each
# sub-repo). 
git submodule update --init --recursive --remote
#
# For just Option 2 above: now add and commit these subrepo changes 
# you just pulled
git add -A
git commit -m "Update all subrepos to their latest upstream changes"

Details

  1. Option 1: as a user of the outer repo, trying to get all submodules into the state intended by the developers of the outer repo:
    git submodule update --init --recursive
    
  2. Option 2: as a developer of the outer repo, trying to update all submodules to the latest commit pushed to the default branch of each of their remote repos (ie: update all subrepos to the latest state intended by the developers of each subrepo):
    git submodule update --init --recursive --remote
    

    ...in place of using git submodule foreach --recursive git pull origin master or git submodule foreach --recursive git pull origin main.

It seems to me that the best answer for both options above is to not use the --merge and --force options I see in some other answers.

Explanation of the options used above:

  • the --init part above initializes the submodule in case you just cloned the repo and haven't done that yet
  • --recursive does this for submodules within submodules, recursively down forever
  • and --remote says to update the submodule to the latest commit on the default branch on the default remote for the submodule. It is like doing git pull origin master or git pull origin main in most cases, for example, for each submodule. If you want to update to the commit specified by the outer-most repo (super repo) instead, leave --remote off.

git submodule foreach --recursive git pull (don't use this--it frequently fails) vs git submodule update --recursive --remote (use this!--it always works)

I left the following comments under this answer. I think they are important so I am putting them in my answer too.

Basically, for some situations, git submodule foreach --recursive git pull might work. For others, git submodule foreach --recursive git pull origin master might be what you need instead. For others, git submodule foreach --recursive git pull origin main might be what you need. And for others still, none of those might work! You might need git submodule foreach --recursive git pull upstream develop, for instance. OR, even worse, there might not be any git submodule foreach command which works for your outer repo, as each submodule might require a different command to update itself from its default remote and default branch. In all cases I can find, however, this does work, including for all cases you might use one of the several git submodule foreach commands I just presented above. So, use this instead:

git submodule update --recursive --remote

Anyway, here are my several comments about that under this answer:

(1/4) @DavidZ, a lot of people think that git submodule foreach git pull and git submodule update --remote are the same thing, with the latter simply being the newer command. They aren't the same thing, however. git submodule foreach git pull will fail under multiple circumstances for which git submodule update --remote works just fine! If your submodule points to a commit hash that doesn't have a branch pointing to it, which is frequently the case in real-life development where you want a particular version of the submodule for your outer repo, then that submodule...

(2/4)...is in a detached HEAD state. In this case, git submodule foreach git pull fails to run git pull on that submodule since a detached HEAD cannot have an upstream branch. git submodule update --remote, however, works just fine! It appears to call git pull origin main on that submodule if origin is the default remote and main is the default branch on that default remote, or git pull origin master, for instance, if origin is the default remote but master is the default branch.

(3/4) Furthemore, git submodule foreach git pull origin master will even fail in many cases where git submodule update --remote works just fine, since many submodules use master as the default branch, and many other submodules use main as the default branch since GitHub changed from master to main recently in order to get away from terms related to slavery in the United States ("master" and "slave").

(4/4) So, I added the explicit remote and branch to make it more clear that they are frequently needed, and to remind people that git pull is frequently not enough, and git pull origin master may not work, and git pull origin main may work when the former doesn't, but also may not even work, and that none of them by themselves are the same as git submodule update --remote, since that latter command is smart enough to just do git pull <default_remote> <default_branch> for you for each submodule, apparently adjusting the remote and branch as necessary for each submodule.

See also

  1. My guide from my eRCaGuy_dotfiles repo: git submodule "Quick Start" guide. Use it to get your team on-boarded.

Related, & other research

  1. My general git submodule notes: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles#git-submodules-and-git-lfs-how-to-clone-this-repo-and-all-git-submodules-and-git-lfs-files
  2. How to find the primary branch of a repo: https://stackoverflow.com/a/49384283/4561887
  3. How to update each subrepo by running a custom command in it via git submodule foreach <cmd>: https://stackoverflow.com/a/45744725/4561887
  4. man git submodule - then search for foreach, --remote, etc.
  5. My answer on How to resolve conflicts with git submodules, in your outer repo containing them
拧巴小姐 2024-11-11 04:48:33
git pull --recurse-submodules

这将拉取所有最新的提交。

git pull --recurse-submodules

This will pull all the latest commits.

青巷忧颜 2024-11-11 04:48:33

这对我来说可以更新到最新的提交

git submodule update --recursive --remote --init

This works for me to update to the latest commits

git submodule update --recursive --remote --init

萌化 2024-11-11 04:48:33

就我而言,我希望 git 更新到最新版本,同时重新填充任何丢失的文件。

以下恢复了丢失的文件(感谢 --force ,这里似乎没有提到),但它没有拉取任何新的提交:

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

这做到了:

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

In my case, I wanted git to update to the latest and at the same time re-populate any missing files.

The following restored the missing files (thanks to --force which doesn't seem to have been mentioned here), but it didn't pull any new commits:

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

This did:

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

无名指的心愿 2024-11-11 04:48:33

如果您不知道主机分支,请执行以下操作:

git submodule foreach git pull origin $(git rev-parse --abbrev-ref HEAD)

它将获取主 Git 存储库的一个分支,然后对于每个子模块将拉取同一分支。

If you don't know the host branch, make this:

git submodule foreach git pull origin $(git rev-parse --abbrev-ref HEAD)

It will get a branch of the main Git repository and then for each submodule will make a pull of the same branch.

风为裳 2024-11-11 04:48:33

@Jason 在某种程度上是正确的,但不完全正确。

更新

更新已注册的子模块,
即克隆缺少的子模块和
签出指定的提交
包含存储库的索引。
这将使子模块 HEAD 成为
除非 --rebase 或 --merge 是分离的
指定或键
submodule.$name.update 设置为
变基或合并。

因此,git submodule update 会签出,但它是在包含存储库的索引中进行提交。它还不知道上游有新的提交。因此,转到您的子模块,获取所需的提交并在主存储库中提交更新的子模块状态,然后执行 git submodule update 。

@Jason is correct in a way but not entirely.

update

Update the registered submodules,
i.e. clone missing submodules and
checkout the commit specified in the
index of the containing repository.
This will make the submodules HEAD be
detached unless --rebase or --merge is
specified or the key
submodule.$name.update is set to
rebase or merge.

So, git submodule update does checkout, but it is to the commit in the index of the containing repository. It does not yet know of the new commit upstream at all. So go to your submodule, get the commit you want and commit the updated submodule state in the main repository and then do the git submodule update.

傾旎 2024-11-11 04:48:33

如果您希望签出每个子模块的 master 分支 - 您可以使用以下命令来实现此目的:

git submodule foreach git checkout master

If you are looking to checkout master branch for each submodule -- you can use the following command for that purpose:

git submodule foreach git checkout master
仲春光 2024-11-11 04:48:33

对我来说,所有git子模块不起作用。但这是有效的:

cd <path/to/submodule>
git pull

它会下载并更新第三方存储库。
然后

cd <path/to/repo>
git commit -m "update latest version" <relative_path/to/submodule>
git push

更新您的远程存储库(带有最后一次提交的链接repo@xxxxxx)。

For me all git submodule did not work. But this worked:

cd <path/to/submodule>
git pull

It downloads and thus updates the third party repo.
Then

cd <path/to/repo>
git commit -m "update latest version" <relative_path/to/submodule>
git push

which updates your remote repo (with the link to the last commit repo@xxxxxx).

夏雨凉 2024-11-11 04:48:33

这是一个很棒的单行代码,可以将 master 上的所有内容更新到最新版本:

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

谢谢马克·贾奎斯

Here's an awesome one-liner to update everything to the latest on master:

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

Thanks to Mark Jaquith

花海 2024-11-11 04:48:33

处理包含子模块的 git 项目的最简单方法是始终

--recurse-submodules 

在每个 git 命令的末尾 添加
例如:

git fetch --recurse-submodules

另一个

git pull --update --recurse-submodules

等等...

the simplest way to handle git projects containing submodules is to always add

--recurse-submodules 

at the end of each git command
example:

git fetch --recurse-submodules

another

git pull --update --recurse-submodules

etc...

寻找我们的幸福 2024-11-11 04:48:32

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

The git submodule update command actually tells Git that you want your submodules to each check out the commit already specified in the index of the superproject. If you want to update your submodules to the latest commit available from their remote, you will need to do this directly in the submodules.

So in summary:

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

Or, if you're a busy person:

git submodule foreach git pull origin master
美胚控场 2024-11-11 04:48:32

Git 1.8.2 提供了一个新选项 --remote,它将实现这种行为。运行

git submodule update --remote --merge

将从每个子模块的上游获取最新更改,将它们合并,并检查子模块的最新版本。正如 文档 所说:

--远程

该选项仅对更新命令有效。不要使用超级项目记录的 SHA-1 来更新子模块,而是使用子模块的远程跟踪分支的状态。

这相当于运行 git pull 每个子模块中的 (通常是 git pull origin mastergit pull origin main),这通常正是您想要的。

Git 1.8.2 features a new option, --remote, that will enable exactly this behavior. Running

git submodule update --remote --merge

will fetch the latest changes from upstream in each submodule, merge them in, and check out the latest revision of the submodule. As the documentation puts it:

--remote

This option is only valid for the update command. Instead of using the superproject’s recorded SHA-1 to update the submodule, use the status of the submodule’s remote-tracking branch.

This is equivalent to running git pull <remote> <default_branch> (usually git pull origin master or git pull origin main) in each submodule, which is generally exactly what you want.

玩心态 2024-11-11 04:48:32

在项目父目录中,运行:

git submodule update --init

或者,如果您有递归子模块,则运行:

git submodule update --init --recursive

有时这仍然不起作用,因为在更新子模块时,您在本地子模块目录中进行了本地更改。

大多数时候,本地更改可能不是您想要提交的更改。这可能是由于子模块中的文件删除等导致的。如果是这样,请在本地子模块目录和项目父目录中进行重置,然后再次运行:

git submodule update --init --recursive

In your project parent directory, run:

git submodule update --init

Or if you have recursive submodules run:

git submodule update --init --recursive

Sometimes this still doesn't work, because somehow you have local changes in the local submodule directory while the submodule is being updated.

Most of the time the local change might not be the one you want to commit. It can happen due to a file deletion in your submodule, etc. If so, do a reset in your local submodule directory and in your project parent directory, run again:

git submodule update --init --recursive
り繁华旳梦境 2024-11-11 04:48:32

您的主项目指向子模块应位于的特定提交。 git submodule update 尝试检查每个已初始化子模块中的提交。子模块实际上是一个独立的存储库 - 仅在子模块中创建一个新的提交并推送它是不够的。您还需要在主项目中显式添加新版本的子模块。

因此,就您的情况而言,您应该在子模块中找到正确的提交 - 让我们假设这是 master 的提示:

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 将会更新子模块,假设它已经初始化了。

Your main project points to a particular commit that the submodule should be at. git submodule update tries to check out that commit in each submodule that has been initialized. The submodule is really an independent repository - just creating a new commit in the submodule and pushing that isn't enough. You also need to explicitly add the new version of the submodule in the main project.

So, in your case, you should find the right commit in the submodule - let's assume that's the tip of master:

cd mod
git checkout master
git pull origin master

Now go back to the main project, stage the submodule and commit that:

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

Now push your new version of the main project:

git push origin master

From this point on, if anyone else updates their main project, then git submodule update for them will update the submodule, assuming it's been initialized.

薄凉少年不暖心 2024-11-11 04:48:32

请注意,虽然更新子模块提交的现代形式是:

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

请参阅 Gabriel Staples 的答案以获取替代方案, 使用--merge --force

--force 选项 允许进行签出,即使包含存储库的索引中指定的提交已经与子模块中签出的提交匹配。

在这种情况下,--merge选项似乎没有必要:“超级项目中记录的提交将被合并到子模块中的当前分支中。”


旧的形式是:

git submodule foreach --quiet git pull --quiet origin

除了......这第二种形式并不是真正的“安静”。

请参阅 提交 a282f5a(2019 年 4 月 12 日),作者:阮Thái Ngọc Duy (pclouds)
(由 Junio C Hamano -- gitster -- 合并于 提交f1c9f6c,2019 年 4 月 25 日)

submodule foreach:修复“ --quiet”不被尊重

罗宾报道

git 子模块 foreach --quiet git pull --quiet origin

不再安静了。
fc1b924子模块:端口submodule 子命令 'foreach' 从 shell 到 C, 2018-05-10,Git v2.19.0-rc0)因为 parseopt 不会意外地吃掉选项。

git pull”的行为就像未给出--quiet一样。

发生这种情况是因为 submodule--helper 中的 parseopt 将尝试解析
两个 --quiet 选项就好像它们是 foreach 的选项,而不是 git-pull 的选项。
已解析的选项将从命令行中删除。所以当我们这样做时
稍后拉出,我们就执行这个

git pull 原点

调用子模块助手时,在“git pull”前面添加“--”将
停止 parseopt 来解析不真正属于的选项
子模块--helper foreach

作为安全措施,

PARSE_OPT_KEEP_UNKNOWN 已被删除。 parseopt 应该
永远不会看到未知的选项或出现问题。还有
当我查看它们时,会更新一些用法字符串。

同时,我还将“--”添加到将“$@”传递给的其他子命令中
子模块--helper。在这些情况下,“$@”是路径,不太可能是
--类似这样的
但要点仍然成立,git-submodule已经解析并分类了什么是选项,什么是路径。
submodule--helper 永远不应该将 git-submodule 传递的路径视为选项,即使它们看起来像一个。


Git 2.23(2019 年第 3 季度)修复了另一个问题:当“--recursive”时,“git submodule foreach”没有保护传递给要在每个子模块中正确运行的命令的命令行选项”选项正在使用中。

请参阅 提交 30db18b(2019 年 6 月 24 日),作者:莫里安十四行诗(momoson
(由 Junio C Hamano -- gitster -- 合并于 提交968eecb,2019 年 7 月 9 日)

子模块 foreach:修复选项递归

调用:

git submodule foreach --recursive <子命令>; --<选项>

导致错误,指出选项 -- 未知
子模块--helper
当然,这只是当 不是 git submodule foreach 的有效选项时。

这样做的原因是,上面的调用在内部转换为
调用子模块--helper:

git submodule--helper foreach --recursive \
   -- <子命令> --<选项>

此调用首先执行子命令,其选项位于
第一级子模块并继续调用下一个迭代
子模块 foreach 调用

git --super-prefix ;子模块--helper \
  foreach --recursive <子命令> --<选项>

在第一级子模块内。注意前面的双破折号
缺少子命令。

这个问题最近才开始出现,因为 git submodule foreach 参数解析的 PARSE_OPT_KEEP_UNKNOWN 标志在提交 a282f5a
因此,现在会抱怨未知选项,因为参数解析没有以双破折号正确结束。

此提交通过在递归过程中在子命令前面添加双破折号解决了该问题。


请注意,在 Git 2.29(2020 年第 4 季度)之前,“<代码>git子模块更新--安静(man) 没有压制底层的“rebase”和“pull”命令。

请参阅 提交 3ad0401(2020 年 9 月 30 日),作者:西奥多·杜波依斯(tbodt
(由 Junio C Hamano -- gitster -- 合并于 提交300cd14,2020 年 10 月 5 日)

子模块更新:沉默底层合并/变基“--安静

签字人:Theodore Dubois

命令如

$ git pull --rebase --recurse-submodules --quiet  

从合并或变基中产生非安静输出。
调用“rebase”和“merge”时向下传递 --quiet 选项。

还修复了 git 子模块的解析更新() -v.

e84c3cf3 ("git-submodule.sh :接受 cmd_update 中的详细标志以保持非安静状态”, 2018-08-14,Git v2.19.0-rc0 -- 合并)教“<一个href="https://github.com/git/git/blob/3ad0401e9e6d3e243a21a3f376e36453572dcf0d/Documentation/git-submodule.txt#L136" rel="noreferrer">git 子模块更新" (man) 采取“--quiet”,它显然不知道如何 ${GIT_QUIET:+- -quiet} 有效,审阅者似乎错过了将变量设置为“0”,而不是取消设置它,仍然导致“--quiet”被传递给底层命令。


在 Git 2.38(2022 年第 3 季度)中,git-submodule.sh 已准备好转为内置函数,这意味着存在上述问题的 submodule--helper 正在消失出去。

请参阅 提交 5b893f7提交 2eec463, 提交 8f12108, 提交 36d4516, 提交 6e556c4, 提交 0d68ee7, 提交 d9c7f69, 提交 da3aae9, 提交 757d092, 提交 960fad9, 提交 8577525(2022 年 6 月 28 日),作者:Ævar Arnfjörð Bjarmason (avar)
请参阅 提交 b788fc6(2022 年 6 月 28 日),作者:Glen Choo (chooglen
(由 Junio C Hamano -- gitster -- 合并于 提交361cbe6,2022 年 7 月 14 日)

git-submodule.sh:使用“<代码>$quiet”,而不是“$GIT_QUIET”

签字人:Ævar Arnfjörð Bjarmason

"$GIT_QUIET" 变量的使用,转而使用我们自己的 "$quiet" 变量。 com/git/git/commit/b3c5f5cb04854b56b39a40696c366053c8f09b58“ rel="noreferrer">b3c5f5c (“子模块:将核心cmd_update()逻辑移至C”,2022-03-15,Git v2.36.0- rc0 -- merge)我们没有在 git-sh-setup 中使用“say”功能。 sh,这是唯一受使用影响的东西“GIT_QUIET”

我们仍然希望支持 --quiet 供我们自己使用,但让我们使用我们自己的变量。
现在很明显,我们只关心将“--quiet”传递给git submodule--helper,而不是更改任何“say”调用。


Note, while the modern form of updating submodule commits would be:

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

See Gabriel Staples's answer for an alternative take, not using --merge --force.

The --force option allows for the checkout to take place even if the commit specified in the index of the containing repository already matches the commit checked out in the submodule.

The --merge option seems not necessary in this case: "the commit recorded in the superproject will be merged into the current branch in the submodule."


The older form was:

git submodule foreach --quiet git pull --quiet origin

Except... this second form is not really "quiet".

See commit a282f5a (12 Apr 2019) by Nguyễn Thái Ngọc Duy (pclouds).
(Merged by Junio C Hamano -- gitster -- in commit f1c9f6c, 25 Apr 2019)

submodule foreach: fix "<command> --quiet" not being respected

Robin reported that

git submodule foreach --quiet git pull --quiet origin

is not really quiet anymore.
It should be quiet before fc1b924 (submodule: port submodule subcommand 'foreach' from shell to C, 2018-05-10, Git v2.19.0-rc0) because parseopt can't accidentally eat options then.

"git pull" behaves as if --quiet is not given.

This happens because parseopt in submodule--helper will try to parse
both --quiet options as if they are foreach's options, not git-pull's.
The parsed options are removed from the command line. So when we do
pull later, we execute just this

git pull origin

When calling submodule helper, adding "--" in front of "git pull" will
stop parseopt for parsing options that do not really belong to
submodule--helper foreach.

PARSE_OPT_KEEP_UNKNOWN is removed as a safety measure. parseopt should
never see unknown options or something has gone wrong. There are also
a couple usage string update while I'm looking at them.

While at it, I also add "--" to other subcommands that pass "$@" to
submodule--helper. "$@" in these cases are paths and less likely to be
--something-like-this.
But the point still stands, git-submodule has parsed and classified what are options, what are paths.
submodule--helper should never consider paths passed by git-submodule to be options even if they look like one.


And Git 2.23 (Q3 2019) fixes another issue: "git submodule foreach" did not protect command line options passed to the command to be run in each submodule correctly, when the "--recursive" option was in use.

See commit 30db18b (24 Jun 2019) by Morian Sonnet (momoson).
(Merged by Junio C Hamano -- gitster -- in commit 968eecb, 09 Jul 2019)

submodule foreach: fix recursion of options

Calling:

git submodule foreach --recursive <subcommand> --<option>

leads to an error stating that the option --<option> is unknown to
submodule--helper.
That is of course only, when <option> is not a valid option for git submodule foreach.

The reason for this is, that above call is internally translated into a
call to submodule--helper:

git submodule--helper foreach --recursive \
   -- <subcommand> --<option>

This call starts by executing the subcommand with its option inside the
first level submodule and continues by calling the next iteration of
the submodule foreach call

git --super-prefix <submodulepath> submodule--helper \
  foreach --recursive <subcommand> --<option>

inside the first level submodule. Note that the double dash in front of
the subcommand is missing.

This problem starts to arise only recently, as the PARSE_OPT_KEEP_UNKNOWN flag for the argument parsing of git submodule foreach was removed in commit a282f5a.
Hence, the unknown option is complained about now, as the argument parsing is not properly ended by the double dash.

This commit fixes the problem by adding the double dash in front of the subcommand during the recursion.


Note that, before Git 2.29 (Q4 2020), "git submodule update --quiet"(man) did not squelch underlying "rebase" and "pull" commands.

See commit 3ad0401 (30 Sep 2020) by Theodore Dubois (tbodt).
(Merged by Junio C Hamano -- gitster -- in commit 300cd14, 05 Oct 2020)

submodule update: silence underlying merge/rebase with "--quiet"

Signed-off-by: Theodore Dubois

Commands such as

$ git pull --rebase --recurse-submodules --quiet  

produce non-quiet output from the merge or rebase.
Pass the --quiet option down when invoking "rebase" and "merge".

Also fix the parsing of git submodule update(man) -v.

When e84c3cf3 ("git-submodule.sh: accept verbose flag in cmd_update to be non-quiet", 2018-08-14, Git v2.19.0-rc0 -- merge) taught "git submodule update"(man) to take "--quiet", it apparently did not know how ${GIT_QUIET:+--quiet} works, and reviewers seem to have missed that setting the variable to "0", rather than unsetting it, still results in "--quiet" being passed to underlying commands.


With Git 2.38 (Q3 2022), git-submodule.sh is prepared to be turned into a builtin, meaning the submodule--helper which has issues described above is being faded out.

See commit 5b893f7, commit 2eec463, commit 8f12108, commit 36d4516, commit 6e556c4, commit 0d68ee7, commit d9c7f69, commit da3aae9, commit 757d092, commit 960fad9, commit 8577525 (28 Jun 2022) by Ævar Arnfjörð Bjarmason (avar).
See commit b788fc6 (28 Jun 2022) by Glen Choo (chooglen).
(Merged by Junio C Hamano -- gitster -- in commit 361cbe6, 14 Jul 2022)

git-submodule.sh: use "$quiet", not "$GIT_QUIET"

Signed-off-by: Ævar Arnfjörð Bjarmason

Remove the use of the "$GIT_QUIET" variable in favor of our own "$quiet", ever since b3c5f5c ("submodule: move core cmd_update() logic to C", 2022-03-15, Git v2.36.0-rc0 -- merge) we have not used the "say" function in git-sh-setup.sh, which is the only thing that's affected by using "GIT_QUIET".

We still want to support --quiet for our own use though, but let's use our own variable for that.
Now it's obvious that we only care about passing "--quiet" to git submodule--helper, and not to change the output of any "say" invocation.

等你爱我 2024-11-11 04:48:32

在此讨论中似乎将两种不同的场景混合在一起:

场景 1

使用父存储库指向子模块的指针,我想检查父存储库可能指向的每个子模块中的提交第一次迭代所有子模块并从远程更新/拉取这些子模块之后。

正如所指出的,这是通过

git submodule foreach git pull origin BRANCH
git submodule update

场景 2 完成的,我认为这就是 OP 的目标

在一个或多个子模块中发生了新的事情,我想 1)拉动这些更改 2)更新父存储库以指向此/这些子模块的 HEAD(最新)提交。

这将通过

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=$1
shift

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

BRANCH=$1
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

Elaboration

首先,我假设所有存储库中都存在名为 $BRANCH (第二个参数)的分支。请随意使其变得更加复杂。

前几个部分是检查参数是否存在。然后我拉出父存储库的最新内容(每当我只是拉动时,我更喜欢使用 --ff (快进)。顺便说一句,我已经关闭了 rebase)。

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 命令;& - 意味着先前的命令必须执行而不会出现错误。

在可能成功拉取之后(如果在远程发现新内容),我会进行推送以确保可能的合并提交不会留在客户端上。再说一次,只有当拉动确实带来了新东西时,才会发生这种情况。

最后,最后的|| true 确保脚本在出现错误时继续执行。为了实现这一点,迭代中的所有内容都必须用双引号括起来,并且 Git 命令用括号括起来(运算符优先级)。

我最喜欢的部分:

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 来更新父存储库。

最后,提交包含一些消息,解释父存储库已更新。如果什么都不做,默认情况下此提交将被忽略。将其推至原点,就完成了。

我有一个脚本在 Jenkins 作业中运行此脚本,该作业链接到计划的自动部署之后,它就像一个魅力。

我希望这对某人有帮助。

It seems like two different scenarios are being mixed together in this discussion:

Scenario 1

Using my parent repository's pointers to submodules, I want to check out the commit in each submodule that the parent repository is pointing to, possibly after first iterating through all submodules and updating/pulling these from remote.

This is, as pointed out, done with

git submodule foreach git pull origin BRANCH
git submodule update

Scenario 2, which I think is what OP is aiming at

New stuff has happened in one or more submodules, and I want to 1) pull these changes and 2) update the parent repository to point to the HEAD (latest) commit of this/these submodules.

This would be done by

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

Not very practical, since you would have to hardcode n paths to all n submodules in e.g. a script to update the parent repository's commit pointers.

It would be cool to have an automated iteration through each submodule, updating the parent repository pointer (using git add) to point to the head of the submodule(s).

For this, I made this small Bash script:

git-update-submodules.sh

#!/bin/bash

APP_PATH=$1
shift

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

BRANCH=$1
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

To run it, execute

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

Elaboration

First of all, I assume that the branch with name $BRANCH (second argument) exists in all repositories. Feel free to make this even more complex.

The first couple of sections is some checking that the arguments are there. Then I pull the parent repository's latest stuff (I prefer to use --ff (fast-forwarding) whenever I'm just doing pulls. I have rebase off, BTW).

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

Then some submodule initializing, might be necessary, if new submodules have been added or are not initialized yet:

git submodule sync
git submodule init
git submodule update

Then I update/pull all submodules:

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

Notice a few things: First of all, I'm chaining some Git commands using && - meaning previous command must execute without error.

After a possible successful pull (if new stuff was found on the remote), I do a push to ensure that a possible merge-commit is not left behind on the client. Again, it only happens if a pull actually brought in new stuff.

Finally, the final || true is ensuring that script continues on errors. To make this work, everything in the iteration must be wrapped in the double-quotes and the Git commands are wrapped in parentheses (operator precedence).

My favourite part:

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

Iterate all submodules - with --quiet, which removes the 'Entering MODULE_PATH' output. Using 'echo $path' (must be in single-quotes), the path to the submodule gets written to output.

This list of relative submodule paths is captured in an array ($(...)) - finally iterate this and do git add $i to update the parent repository.

Finally, a commit with some message explaining that the parent repository was updated. This commit will be ignored by default, if nothing was done. Push this to origin, and you're done.

I have a script running this in a Jenkins job that chains to a scheduled automated deployment afterwards, and it works like a charm.

I hope this will be of help to someone.

缱绻入梦 2024-11-11 04:48:32

简单明了,获取子模块:

git submodule update --init --recursive

现在继续将它们更新到最新的主分支(例如):

git submodule foreach git pull origin master

Plain and simple, to fetch the submodules:

git submodule update --init --recursive

And now proceed updating them to the latest master branch (for example):

git submodule foreach git pull origin master
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文