我有一个带有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
和git show
拒绝新提交的存在。到目前为止,我刚刚rm
- 模块并重新添加它,但这在原则上是错误的,在实践中是乏味的。
答案 0 :(得分:1245)
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
答案 1 :(得分:379)
Git 1.8.2提供了一个新选项--remote
,可以实现此行为。运行
git submodule update --remote --merge
将从每个子模块的上游获取最新的更改,将它们合并,并检查子模块的最新版本。正如the docs所说:
- 远程
此选项仅对更新命令有效。不使用超级项目记录的SHA-1来更新子模块,而是使用子模块的远程跟踪分支的状态。
这相当于在每个子模块中运行git pull
,这通常正是您想要的。
答案 2 :(得分:107)
在项目父目录中运行:
git submodule update --init
或者如果你有递归子模块运行:
git submodule update --init --recursive
有时这仍然不起作用,因为在更新子模块时,本地子模块目录中有局部更改。
大多数情况下,本地更改可能不是您要提交的更改。它可能由于子模块中的文件删除等原因而发生。如果是这样,请在本地子模块目录和项目父目录中重新运行:
git submodule update --init --recursive
答案 3 :(得分:70)
您的主项目指向子模块应该处于的特定提交。 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
从现在开始,如果其他人更新了他们的主项目,那么git submodule update
为他们将更新子模块,假设它已被初始化。
答案 4 :(得分:19)
在本次讨论中似乎将两种不同的场景混合在一起:
情景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命令 - 这意味着上一个命令必须执行w / o错误。
在可能的成功拉动之后(如果在遥控器上发现新的东西),我做了一个推动以确保在客户端上不会留下可能的合并提交。再次,只有如果拉实际上带来了新的东西。
最后,最终|| true
确保脚本继续出错。为了使这项工作,迭代中的所有内容必须用双引号括起来,并且git-commands包含在parantheses中(运算符优先级)。
我最喜欢的部分:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
迭代所有子模块 - 使用--quiet
,删除'Entering MODULE_PATH'输出。使用'echo $path'
(必须使用单引号),子模块的路径将写入输出。
这个相对子模块路径列表是在一个数组($(...)
)中捕获的 - 最后迭代它并执行git add $i
来更新父仓库。
最后,提交一些消息,说明父代表已更新。如果没有做任何事情,默认情况下将忽略此提交。把它推到原点,你就完成了。
我有一个在jenkins-job中运行它的脚本,之后链接到计划的自动部署,它就像一个魅力。
我希望这会对某人有所帮助。
答案 5 :(得分:17)
简单明了,要获取子模块:
git submodule update --init --recursive
现在继续将它们更新到最新的主分支(例如):
git submodule foreach git pull origin master
答案 6 :(得分:4)
git pull --recurse-submodules
这将提取所有最新提交。
答案 7 :(得分:3)
@Jason在某种程度上是正确的,但并非完全正确。
更新
更新已注册的子模块, 即克隆缺失的子模块和 签出中指定的提交 包含存储库的索引。 这将使子模块HEAD成为 除非--rebase或--merge是分离的 指定或密钥 子模块。$ name.update设置为 改变或合并。
因此,git子模块更新执行checkout,但事实是,它是对包含存储库的索引中的提交。它根本不知道上游的新提交。所以转到你的子模块,获得你想要的提交并在主repo中提交更新的子模块状态然后执行git submodule update
答案 8 :(得分:2)
就我而言,我希望f = open("guru99.txt", "a")
data = "some data"
f.write(data)
更新到最新版本,同时重新填充所有丢失的文件。
以下内容恢复了丢失的文件(感谢git
,在这里似乎没有提到),但是它没有提取任何新的提交:
--force
这样做:
git submodule update --init --recursive --force
答案 9 :(得分:1)
这是一个非常棒的单行程序,可以将所有内容更新为最新的主人:
git submodule foreach 'git fetch origin --tags; git checkout master; git pull' && git pull && git submodule update --init --recursive
答案 10 :(得分:1)
如果您不知道主机分支,请执行以下操作:
git submodule foreach git pull origin $(git rev-parse --abbrev-ref HEAD)
它将获得主git的分支,然后对于每个子模块,将pull设置为相同的分支
答案 11 :(得分:1)
如果您希望为每个子模块检出master
分支,则可以为此使用以下命令:
git submodule foreach git checkout master
答案 12 :(得分:1)
这对我来说可以更新到最新的提交
git submodule update --recursive --remote --init
答案 13 :(得分:0)
请注意,更新子模块提交的现代形式是:
git submodule update --recursive --remote --merge --force
较旧的形式是:
git submodule foreach --quiet git pull --quiet origin
除了...第二种形式不是真的“安静”。
请参见commit a282f5a的Nguyễn Thái Ngọc Duy (pclouds
)(2019年4月12日)。
(由Junio C Hamano -- gitster
--在commit f1c9f6c中合并,2019年4月25日)
submodule foreach
:修复“<command> --quiet
”不被尊重罗宾报道
git submodule foreach --quiet git pull --quiet origin
不再安静了。
在fc1b924(submodule
:端口submodule
子命令'foreach
'从外壳到C,2018-05-10,Git v2.19.0-rc0)之前应该保持安静parseopt
不能再误食。“
git pull
”的行为就像没有给出--quiet
。发生这种情况是因为
parseopt
中的submodule--helper
会尝试解析 两个--quiet
选项都好像是foreach的选项,而不是git-pull
的选项。
解析的选项从命令行中删除。所以当我们这样做 稍后再拉,我们就这样执行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
传递的路径视为选项,即使它们看起来像一个。
答案 14 :(得分:0)
处理包含子模块的git项目的最简单方法是始终添加
--recurse-submodules
在每个git命令末尾的例如:
git fetch --recurse-submodules
另一个
git pull --update --recurse-submodules
等...