当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《将Git子模块更新为最新的原始提交》经验,为你挑选了7个好方法。

我有一个带有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 loggit show否认新提交的存在.到目前为止,我刚刚rm对模块进行了重新添加,但这在原则上是错误的,在实践中也是乏味的.



1> Jason..:

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 submodule foreach git pull`
@Nicklas在这种情况下,使用`git submodule foreach git pull origin master`.
在这一点上,通过对更正的所有这些更正,我需要有人写一个解释性博客文章并指出我.请.
对'foreach'方法的微小改进 - 如果你在子模块中有子模块,你可能想在那里添加--recursive.所以:`git submodule foreach --recursive git pull origin master`.
@Abdull`-a`开关用于`git commit`"告诉[s]命令自动暂存已经修改和删除的文件,但是你没有告诉Git的新文件不受影响."
@MathiasBynens:您必须检查子模块上的分支,因为它默认处于分离状态.
我认为解决方案是正确的,但解释`git submodule update`的做法是错误的.在初始化的子模块上,该命令将检查父级"记住"的子模块的提交.
git commit ...之前缺少git add ...

2> David Z..:

Git 1.8.2提供了一个新选项--remote,可以实现这种行为.运行

git submodule update --remote --merge

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

- 远程

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

这相当于git pull在每个子模块中运行,这通常正是您想要的.


*"相当于在每个子模块中运行`git pull`"*为了澄清,你的答案与`git submodule foreach git pull`之间没有区别(从用户的角度来看)?
I wish I could upvote this 10,000X. Why isn't this shown in git's documentation anywhere? Huge oversight.
对我来说,他们实际上差别很大; `foreach git pull`只检查了它们,但没有更新主repo的指针指向子模块的较新提交.只有`--remote`它才能指向最新的提交.
为什么--merge选项?它有什么不同?
@Dennis它的功能基本相同,但我不确定功能是否与_exactly_相同.可能存在一些我不知道的细微差别,例如,两个命令响应某些配置设置的方式.

3> pinux..:

在您的项目父目录中运行:

git submodule update --init

或者如果你有递归子模块运行:

git submodule update --init --recursive

有时这仍然无法正常工作,因为在更新子模块时,您在本地子模块目录中进行了本地更改.

大多数情况下,本地更改可能不是您要提交的更改.这可能是由于子模块中的文件删除等原因造成的.如果是这样,请在本地子模块目录和项目父目录中重新运行:

git submodule update --init --recursive


这是真正的答案.我能以某种方式将它推送到我的远程存储库吗?

4> Mark Longair..:

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

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

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

从这一点开始,如果其他人更新了他们的主项目,那么master他们将更新子模块,假设它已被初始化.



5> Frederik Str..:

在本次讨论中,似乎有两种不同的场景混合在一起:

场景1

使用我的父repo指向子模块的指针,我想检查父repo指向的每个子模块中的提交,可能是在首次迭代所有子模块并从远程更新/拉取这些子模块之后.

正如所指出的那样,这是完成的

git submodule foreach git pull origin BRANCH
git submodule update

场景2,我认为是OP的目标

在1个或多个子模块中发生了新的事情,我想1)拉出这些变化,2)更新父repo以指向这个/这些子模块的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个路径,例如脚本来更新父repo的提交指针.

通过每个子模块进行自动迭代,更新父repo指针(使用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

首先,我假设所有repo上都存在名为$ BRANCH(第二个参数)的分支.随意使这更复杂.

前几节是检查参数是否存在的一些部分.然后我拉出父回购的最新东西(我更喜欢使用--ff(快进)每当我做拉动时.我已经关闭了,顺便说一句).

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命令git add- 意味着前一个命令必须执行w/o错误.

在可能成功拉动之后(如果在遥控器上发现了新的东西),我做了一个推动,以确保在客户端上不会留下可能的合并提交.同样,只有发生如果拉新的东西实际上带来的.

最后,最后一步&&是确保脚本继续出错.为了使这项工作,迭代中的所有内容必须用双引号括起来,并且git-commands包含在parantheses(operator precedence)中.

我最喜欢的部分:

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

迭代所有子模块 - 使用|| true,删除'Entering MODULE_PATH'输出.使用--quiet(必须使用单引号),子模块的路径将写入输出.

这个相对子模块路径列表在一个数组('echo $path')中捕获- 最后迭代这个并做$(...)更新父存储库.

最后,提交一些消息,解释父代表已更新.如果没有做任何事情,默认情况下将忽略此提交.把它推到原点,你就完成了.

我有一个在jenkins工作中运行它的脚本,之后链接到计划的自动部署,它就像一个魅力.

我希望这会对某人有所帮助.


!@#$%因此,我们正在使用与您相似的脚本;一个注意事项:我们在for循环内使用git子模块foreach --recursive --quiet pwd而不是git子模块foreach --quiet'echo $ path'。pwd命令为每个存在的子模块打印正确的“绝对路径”。--recursive确保我们访问*所有*子模块,包括可能存在于大型项目中的submodules-within-submodules-...。这两种方法都会导致目录包含空格的麻烦,例如`/ c / Users / Ger / Project \ Files / ...`,因此策略是*绝不要在项目的任何地方使用空格。
很好,您是对的,甚至对问题的答案有些误解,但是正如David Z的出色答案所指出的那样,您的脚本是不必要的,因为该功能自2013年中期以来已内置到Git中他们添加了--remote选项。git submodule update --remote的行为近似于脚本的行为。

6> Daniel Andre..:

简单明了,要获取子模块:

git submodule update --init --recursive

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

git submodule foreach git pull origin master



7> VonC..:

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

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

较旧的形式是:

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

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

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

leads to an error stating that the option -- is unknown to submodule--helper.
That is of course only, when 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 \
    --  --

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  submodule--helper \
   foreach --recursive  --

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.

推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有