无法检出git子模块路径

38

我在使用Git子模块时遇到了问题。

每当我从上游存储库接收到一个新的子模块引用时,执行git submodule update命令会给出以下结果:

fatal: reference is not a tree: dd208d46ecdd1ac0d2b2594a610fe4c9150fece1
Unable to checkout 'dd208d46ecdd1ac0d2b2594a610fe4c9150fece1' in submodule path 'submodule/path'

需要注意的是,子模块具有多个远程仓库,其中上游远程仓库应该用于更新子模块引用树。我猜我的问题就在那里,但我不确定。

我的设置如下:

Git 项目

远程仓库:

  1. origin(我的 Git 分支)
  2. upstream(项目存储库)

子模块“module”有以下远程仓库:

  1. origin(我的 Git 分支)
  2. upstream(项目存储库)

有人知道是什么原因导致了我的问题吗?

9个回答

42

在执行git submodule update时,Git 会尝试检出保存在超级项目中的提交 / 树(例如您的示例中的提交 ID 为 dd208d4... 的项目)。

我认为您遇到错误是因为子模块中没有该对象。您需要确保它存在。通常这意味着您首先需要从远程获取 / 拉取它。

可能您需要执行以下操作:

git submodule foreach git fetch
git submodule update

或许

git fetch --recurse-submodules

假设子模块已配置好,可以从远程origin获取缺失的提交。最终,必须知道从哪里获取丢失的提交,并且您必须获取它。

您可以通过类似以下方式检查是否拥有dd208d4 ...:

cd ./module
git log dd208d46ecdd1ac0d2b2594a610fe4c9150fece1
git cat-file -p dd208d46ecdd1ac0d2b2594a610fe4c9150fece1
git ls-tree dd208d46ecdd1ac0d2b2594a610fe4c9150fece1

这种问题的一个可能原因是,发布超级模块的新提交的人没有发布子模块所需的提交。他必须首先发布子模块的提交。


子模块提交已发布,问题仍然存在。 - marknuzz
1
在将特性分支rebase到更新的master之前,我需要做的事情又多了一项,那就是撤销子模块的意外更改。目前为止,我需要运行以下命令:git submodule foreach git fetch && git submodule deinit -f . && git submodule update --init - ijoseph

7
确保子模块已经被推送。
cd submodule-dir
git push

在我的情况下,我已经:

  • 提交子模块
  • 未进行推送
  • 提交了包含更新后子模块的父模块
  • 推送了父模块

因此不难理解为什么找不到它。

如果您正在使用像GitHub这样的Web界面,则还可以转到子模块存储库网页,并仔细检查您需要显示的提交是否显示在其中。

push.recurseSubmodules on-demand

也可以使用上述命令进一步自动化推送。

git push --recurse-submodules=on-demand

此外,它还会在需要的时候推送子模块,或从2.7版本开始:

git config push.recurseSubmodules on-demand
git push

基本上和之前的答案相同,但即使推动了它,有时这个问题仍然会出现。 - marknuzz
@Nuzzolilo,你能否生成一个最小可重现的本地示例,例如 mkdir repo && cd repo && git init && touch a && git add . ... - Ciro Santilli OurBigBook.com
请参见 https://github.com/projectkudu/kudu/issues/1972 - 可能会发生在通过Github上的部署密钥访问的子模块中。抱歉,没有时间做更多的事情。 - marknuzz

1
我曾遇到同样的问题,解决方法是为父项目添加一个新的提交并将所有内容推送。请检查子项目提交和模块提交。

0

另一种方法是手动操作,而不使用命令行git选项。

这种情况通常发生在子模块路径已经被移动/替换(但没有正确处理),因此仍然指向本地检出存储库中的旧引用。

1)找到存储库和子模块。

ls -la .git/modules
   rm -f .git/modules/<module-with-issue>

2) 删除旧的本地子模块配置

 gedit .git/config

(在此删除子模块URL条目)

它看起来像这样;

 *[submodule "module-with-issue"]
       url = ...*

3) 现在,获取并更新子模块 git fetch git submodule update --recursive --init

注意: 在尝试更新子模块之前,您可能还需要删除本地检出的子模块文件夹。


0
git submodule unable to checkout

请注意:
你可能需要检查一下你的远程分支是否区分大小写。 例如:IB_Certs,但你使用的是ib_certs。
我发现了这个问题,并花了很长时间才找到原因,最后发现它是区分大小写的。
希望这能解决你的问题。

0

在 GitLab 上,使用 git rm --cached <submodule-directory> 命令可以帮助我解决问题:

.prepare_deploy: &prepare_deploy
  before_script:
    - bundle install -j $(nproc) --path vendor
    - which ssh-agent || (apt-get update -y && apt-get install openssh-client -y)
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - eval $(ssh-agent -s)
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - (echo "$SSH_PRIVATE_KEY" | base64 --decode) > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - git rm --cached <submodule-directory>
    - git submodule sync --recursive
    - git submodule update --init --recursive

0
我的问题是,在对我的存储库进行cat .gitmodules操作时,我指向了子模块存储库的错误远程地址(最初我使用原始远程克隆了它,但后来切换到了它的一个分支;gitmodules文件从未更新以反映这种变化)。

0

我在其中一个子模块中忘记推送更改时遇到了这个问题。

确保更改已经被推送。


0
我的问题是在子模块的build.gradle文件中有未提交的更改(我认为这些更改是自动更改的)。它们出现在git diff中。我只需执行git checkout .将子模块存储库重置为没有更改,然后git submodule update就可以正常工作了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接