将 Git 子模块更新为最新的原始提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5828324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Update Git submodule to latest commit on origin
提问by Thanatos
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.
我有一个带有 Git 子模块的项目。它来自一个 ssh://... URL,并且在提交 A 上。提交 B 已被推送到该 URL,我希望子模块检索提交,并更改为它。
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:
现在,我的理解是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
$ ...
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.
我也试过git fetch mod
,这似乎做取(但不能可能,因为它不要求输入密码!),但git log
并git show
否认新提交的存在。到目前为止,我只是在rm
对模块进行-ing 并重新添加它,但这在原则上是错误的,而且在实践中很乏味。
回答by Jason
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 updateyour submodules to the latest commit available from their remote, you will need to do this directly in the submodules.
该git submodule update
命令实际上告诉 Git 你希望你的子模块每次检出已经在超级项目的索引中指定的提交。如果要将子模块更新为远程可用的最新提交,则需要直接在子模块中执行此操作。
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
回答by David Z
Git 1.8.2 features a new option, --remote
, that will enable exactly this behavior. Running
Git 1.8.2 具有一个新选项,--remote
,它将启用此行为。跑步
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 documentationputs 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.
- 偏僻的
此选项仅对更新命令有效。不要使用超级项目记录的 SHA-1 来更新子模块,而是使用子模块的远程跟踪分支的状态。
This is equivalent to running git pull
in each submodule, which is generally exactly what you want.
这相当于git pull
在每个子模块中运行,这通常正是您想要的。
回答by pinux
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
回答by Mark Longair
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.
您的主项目指向子模块应该位于的特定提交。git submodule update
尝试检查每个已初始化的子模块中的提交。子模块实际上是一个独立的存储库——仅仅在子模块中创建一个新的提交并推送是不够的。您还需要在主项目中显式添加子模块的新版本。
So, in your case, you should find the right commit in the submodule - let's assume that's the tip of master
:
因此,在您的情况下,您应该在子模块中找到正确的提交 - 让我们假设这是提示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.
从现在开始,如果其他人更新了他们的主项目,那么git submodule update
他们将更新子模块,假设它已被初始化。
回答by Frederik Struck-Sch?ning
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
场景 2,我认为这是 OP 的目标
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.
一个或多个子模块中发生了新的事情,我想 1) 提取这些更改和 2) 更新父存储库以指向此/这些子模块的 HEAD(最新)提交。
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.
不太实用,因为您必须在例如脚本中硬编码所有 n 个子模块的 n 个路径,以更新父存储库的提交指针。
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).
通过每个子模块进行自动迭代,更新父存储库指针(使用git add
)以指向子模块的头部会很酷。
For this, I made this small Bash script:
为此,我制作了这个小 Bash 脚本:
git-update-submodules.sh
git-update-submodules.sh
#!/bin/bash
APP_PATH=
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=
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.
首先,我假设所有存储库中都存在名为 $BRANCH(第二个参数)的分支。随意使这更复杂。
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).
前几节是一些检查参数是否存在。然后我拉取父存储库的最新内容(我更喜欢使用 --ff(快进),无论何时我只是在做拉取。顺便说一句,我已经变基了)。
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.
请注意以下几点: 首先,我使用&&
-链接一些 Git 命令- 意味着前一个命令必须正确执行。
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 ifa 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).
最后,最后|| true
是确保脚本继续出现错误。为了实现这一点,迭代中的所有内容都必须用双引号括起来,并且 Git 命令用括号括起来(运算符优先级)。
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.
迭代所有子模块 - with --quiet
,这将删除“输入 MODULE_PATH”输出。使用'echo $path'
(必须在单引号中),子模块的路径被写入输出。
This list of relative submodule paths is captured in an array ($(...)
) - finally iterate this and do git add $i
to update the parent repository.
这个相对子模块路径列表被捕获在一个数组 ( $(...)
) 中 - 最后迭代它并git add $i
更新父存储库。
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 Jenkinsjob that chains to a scheduled automated deployment afterwards, and it works like a charm.
我有一个在Jenkins作业中运行它的脚本,该脚本随后链接到预定的自动部署,它的工作原理很有魅力。
I hope this will be of help to someone.
我希望这会对某人有所帮助。
回答by Daniel Andrei Minc?
Plain and simple, to fetch the submodules:
简单明了,获取子模块:
git submodule update --init --recursive
And now proceed updating them to the latest master branch (for example):
现在继续将它们更新到最新的 master 分支(例如):
git submodule foreach git pull origin master
回答by VonC
Note, while the modern form of updating submodule commits would be:
请注意,虽然更新子模块提交的现代形式是:
git submodule update --recursive --remote --merge --force
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)
请参阅Nguy?n Thái Ng?c Duy ( ) 的commit a282f5a(2019 年 4 月 12 日)。(由Junio C Hamano合并-- --在提交 f1c9f6c 中,2019 年 4 月 25 日)pclouds
gitster
submodule foreach
: fix "<command> --quiet
" not being respectedRobin reported that
git submodule foreach --quiet git pull --quiet origin
is not really quiet anymore.
It should be quiet before fc1b924(submodule
: portsubmodule
subcommand 'foreach
' from shell to C, 2018-05-10, Git v2.19.0-rc0) becauseparseopt
can't accidentally eat options then."
git pull
" behaves as if--quiet
is not given.This happens because
parseopt
insubmodule--helper
will try to parse both--quiet
options as if they are foreach's options, notgit-pull
's.
The parsed options are removed from the command line. So when we do pull later, we execute just thisgit pull origin
When calling submodule helper, adding "
--
" in front of "git pull
" will stopparseopt
for parsing options that do not really belong tosubmodule--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 "$@
" tosubmodule--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 bygit-submodule
to be options even if they look like one.
submodule foreach
: 修复 "<command> --quiet
" 不被尊重罗宾报告说
git submodule foreach --quiet git pull --quiet origin
真的不再安静了。
在fc1b924(submodule
: portsubmodule
subcommand 'foreach
' from shell to C, 2018-05-10, Git v2.19.0-rc0)之前应该是安静的,因为parseopt
那时不能不小心吃选项。"
git pull
"表现得好像--quiet
没有给出。发生这种情况是因为
parseopt
insubmodule--helper
会尝试解析这两个--quiet
选项,就好像它们是 foreach 的选项,而不是git-pull
's。
解析的选项将从命令行中删除。所以当我们稍后拉动时,我们只执行这个git pull origin
调用子模块助手时,
--
在“ ”前加“git pull
”会停止parseopt
解析不属于submodule--helper foreach
.
PARSE_OPT_KEEP_UNKNOWN
作为安全措施被删除。parseopt
永远不应该看到未知的选项或出现问题。在我查看它们时,还有一些用法字符串更新。同时,我还将“
--
”添加到将“ ”传递$@
给submodule--helper
. “$@
”在这些情况下是路径,不太可能是--something-like-this
。
但重点仍然存在,git-submodule
已经解析和分类什么是选项,什么是路径。submodule--helper
永远不要将经过的路径视为git-submodule
选项,即使它们看起来像一个选项。
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.
和Git 2.23(Q3 2019)解决另一个问题:“ git submodule foreach
”没有传递到命令保护命令行选项来在每个子模块正常运行,当“ --recursive
”选项是在使用中。
See commit 30db18b(24 Jun 2019) by Morian Sonnet (momoson
).
(Merged by Junio C Hamano -- gitster
--in commit 968eecb, 09 Jul 2019)
参见Morian Sonnet ( momoson
) 的commit 30db18b(24 Jun 2019 )。
(由Junio C gitster
Hamano合并-- --在提交 968eecb 中,2019 年 7 月 9 日)
submodule foreach
: fix recursion of optionsCalling:
git submodule foreach --recursive <subcommand> --<option>
leads to an error stating that the option
--<option>
is unknown tosubmodule--helper
.
That is of course only, when<option>
is not a valid option forgit 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
callgit --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 ofgit 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.
submodule foreach
: 修复选项的递归调用:
git submodule foreach --recursive <subcommand> --<option>
导致错误,指出该选项
--<option>
未知submodule--helper
。
这当然只是,when<option>
不是 的有效选项git submodule foreach
。这样做的原因是,上述调用在内部转换为对子模块--helper 的调用:
git submodule--helper foreach --recursive \ -- <subcommand> --<option>
这个调用与它的第一级子模块中选择执行子开始,并通过调用的下一次迭代继续
submodule foreach
通话git --super-prefix <submodulepath> submodule--helper \ foreach --recursive <subcommand> --<option>
在第一级子模块内。请注意,缺少子命令前面的双破折号。
这个问题最近才开始出现,因为在提交a282f5a中删除
PARSE_OPT_KEEP_UNKNOWN
了参数解析的标志。 因此,现在抱怨未知选项,因为参数解析没有被双破折号正确结束。git submodule foreach
此提交通过在递归期间在子命令前添加双破折号来解决该问题。
回答by VonC
git pull --recurse-submodules
This will pull all the latest commits.
这将拉取所有最新提交。
回答by noseratio
In my case, I wanted git
to update to the latest and at the same time re-populate any missing files.
就我而言,我想git
更新到最新版本,同时重新填充任何丢失的文件。
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:
以下恢复了丢失的文件(感谢--force
这里似乎没有提到),但它没有提取任何新的提交:
git submodule update --init --recursive --force
git submodule update --init --recursive --force
This did:
这做到了:
git submodule update --recursive --remote --merge --force
git submodule update --recursive --remote --merge --force
回答by manojlds
@Jason is correct in a way but not entirely.
@Jason 在某种程度上是正确的,但不完全正确。
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.
更新
更新已注册的子模块,即克隆丢失的子模块并检出包含存储库索引中指定的提交。这将使子模块 HEAD 被分离,除非指定了 --rebase 或 --merge 或者键 submodule.$name.update 设置为 rebase 或 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
.
所以,git submodule update
签出,但它是包含存储库的索引中的提交。它根本不知道上游的新提交。因此,转到您的子模块,获取您想要的提交并在主存储库中提交更新的子模块状态,然后执行git submodule update
.