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

这篇博客探讨了如何将Git子模块更新到最新的原始提交。内容包括使用不同的Git命令,如`git submodule update --remote`,`git pull`以及解决在更新过程中遇到的问题,如本地更改、丢失的文件和递归更新。还提供了一个Bash脚本示例,用于自动迭代和更新所有子模块,并更新父存储库的提交指针。
摘要由CSDN通过智能技术生成

我有一个带有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 -ing模块并重新添加它,但是这是在原则上都是错误的和繁琐的做法。


#1楼

在项目父目录中,运行:

git submodule update --init

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

git submodule update --init --recursive

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

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

git submodule update --init --recursive

#2楼

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

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

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

前几节是检查参数是否存在的一些部分。 然后我拉出父存储库的最新东西(我更喜欢使用--ff(快速转发),每当我做拉动时。我已经关闭了,BTW)。

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 || true是确保脚本继续上的错误。 为了实现这一点,迭代中的所有内容都必须用双引号括起来,Git命令用括号括起来(运算符优先级)。

我最喜欢的部分:

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

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

这个相对子模块路径列表在一个数组中捕获( $(...) ) - 最后迭代这个并执行git add $i来更新父存储库。

最后,提交一些消息,说明父存储库已更新。 如果没有做任何事情,默认情况下将忽略此提交。 把它推到原点,你就完成了。

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

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


#3楼

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

git submodule update --remote --merge

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

- 远程

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

这相当于在每个子模块中运行git pull ,这通常就是你想要的。


#4楼

这是一个很棒的单行程序,可以将所有内容更新为最新的主服务器:

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

感谢Mark Jaquith


#5楼

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

git submodule update --init --recursive

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

git submodule foreach git pull origin master

#6楼

在我的情况下,我希望git更新到最新版本,同时重新填充任何丢失的文件。

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

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

这样做:

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


#7楼

git pull --recurse-submodules

这将提取所有最新提交。


#8楼

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

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

它将获得主Git存储库的一个分支,然后为每个子模块将拉动相同的分支。


#9楼

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

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

较旧的形式是:

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

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

NguyễnTháiNgọcDuy( pclouds 提交a282f5a (2019年4月12日
(由Junio C gitster合并- gitster -提交f1c9f6c ,2019年4月25日)

submodule foreach :修复“ <command> --quiet ”没有得到尊重

罗宾报道说

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

不再那么安静了。
它应该在fc1b924之前安静submodule :port submodule子命令' foreach '从shell到C,2018-05-10,Git v2.19.0-rc0)因为parseopt不能随意吃掉选项。

git pull ”表现得好像没有给出--quiet

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

 git pull origin 

调用子模块助手时,在“ git pull ”前添加“ -- ”将停止parseopt以解析实际上不属于submodule--helper foreach选项submodule--helper foreach

删除PARSE_OPT_KEEP_UNKNOWN作为安全措施。 parseopt永远不会看到未知选项或出现问题。 我正在查看它们时还有一些用法字符串更新。

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


并且Git 2.23(Q3 2019)解决了另一个问题:当使用“ --recursive ”选项时,“ git submodule foreach ”不保护传递给命令的命令行选项在每个子模块中正确运行。

参见由momoson Sonnet( momoson 提交的30db18b (2019年6月24日
(由Junio C gitster合并- gitster -提交968eecb ,2017年7月9日)

submodule foreach :修复选项的递归

呼叫:

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

导致出现错误,指出submodule--helper未知选项--<option>
当然,这只是当<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中删除了参数解析git submodule foreachPARSE_OPT_KEEP_UNKNOWN标志。
因此,现在抱怨未知选项,因为参数解析未通过双破折号正确结束。

此提交通过在递归期间在子命令前添加双短划线来解决问题。


#10楼

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

#11楼

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

更新

更新已注册的子模块,即克隆缺少的子模块,并检查包含的存储库索引中指定的提交。 这将使子模块HEAD被分离,除非指定了--rebase或--merge或密钥子模块。$ name.update设置为rebase或merge。

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


#12楼

您的主项目指向子模块应该处于的特定提交。 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将更新子模块,假设它已被初始化。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值