You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Git filter-branch/filter-repo更新子模块Git链接?

问题:仓库中子模块历史重写后更新Git链接

我有一个Git仓库A,它依赖子模块B。子模块B在LFS迁移后历史被重写,我希望仓库A的完整历史仍能正常使用。现在我已经拿到了B的OldSHA1→NewSHA1映射表,需要在A中将旧的Git链接从OldSHA1替换为NewSHA1。

已尝试的方法

方法1:使用filter-repo

我尝试在仓库A上运行带完整OldSHA1==>NewSHA1映射参数的filter-repo命令,但它似乎无法识别Git链接。

方法2:使用filter-branch

我参考相关教程尝试了filter-branch命令,先测试单个OldSHA1=>NewSHA1映射,执行的命令如下:

git filter-branch --commit-filter '
  if [ "$GIT_COMMIT" = <OLDSHA1> ];
  then
    cd <SUBMODULE_ABSOLUTE_PATH>;
    git checkout <NEWSHA1>;
    cd ..;
    git add -u;
    git commit -m "updated gitlink";
  else
    git commit-tree "$@";
  fi' HEAD 

遇到的错误

执行上述命令后持续收到以下错误:

fatal: reference is not a tree: <NEWSHA1>

即使改用git -C <子模块绝对路径> checkout指定路径,仍出现相同错误。

我的问题

  • 我是否存在明显的操作错误?
  • 是否有更好的实现方法?我只是想在对象数据库中替换字符串,但找不到简单的方式。
  • 是否有像filter-repo那样能在整个仓库执行的方法?还是需要在每个分支单独运行?

感谢任何帮助、建议或实现思路!


编辑1

根据建议修改脚本为:

git filter-branch --commit-filter '
  if [ "$GIT_COMMIT" = <SpecificCommitID> ];
  then
    git update-index --add --cacheinfo 160000,<SpecificNewSha1>,<SubmodulePath>;
  fi
  git commit-tree "$@";
  ' HEAD

但没有效果,提示:

WARNING: Ref 'refs/heads/develop' is unchanged

编辑2

非常感谢用户@torek!以下是可用的代码片段:

git filter-branch --index-filter '
if [ "$(git rev-parse --quiet --verify :<SUBMODULEPATH>)" = <OLDSHA1> ];
then
  git update-index --cacheinfo 160000,<NEWSHA1>,<SUBMODULEPATH>;
fi' HEAD --all

之后你需要遍历所有OldSHA1/NewSHA1对,或者使用回答中提到的case字典。再次感谢!


内容的提问来源于stack exchange,提问作者Bibzball

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:55:20