无法使用相对路径添加Git子模块

48

我正在尝试向我的git仓库添加一个子模块,但我收到了以下错误提示:

remote origin does not have a url defined in .git/config

有没有什么想法?我试着在谷歌上搜索,但只有一个模糊的链接。

我正在做这个:

git submodule add ../extern/Lib1 lib  

我希望这将创建一个子模块lib/Lib1
我知道这只会创建一个引用,然后我需要更新/初始化(对此部分不是非常清楚,还没有进一步了解;我正在学习子模块命令)。


刚刚完成了我的回答,并提供了一些额外的建议。 - VonC
我认为绝对路径仅在此处起作用,因为您的extern/Lib1 Git存储库...没有“远程源在.git/config中没有定义url” ;). 需要在那个.git/config中进行一些调查。 - VonC
我不确定你的意思。我只是查看了extern/Lib1的.git/config文件,它只有[core]部分: repositoryformatversion=0,filemode=true,bare=false,legalrefupdates=true - deepblue
刚刚添加了一个关于“远程源”应该在哪里定义的示例。请查看我的编辑后的答案。 - VonC
你的最后一条评论让我重新阅读了git子模块手册。我已经编辑了我的答案,以获得相关.git/config文件更精确的位置。 - VonC
3个回答

43

../extern/Lib1 是指一个 Git 仓库吗?
如果不是的话,Git 就不会知道如何将 Git 仓库的 URL 添加到它的 .gitmodule 文件中。
另外,请尝试以下操作:

  • 目标路径 lib 不存在(即使是空的)
  • 使用绝对路径而不是相对路径(虽然可以使用相对路径,但为了确保,这里值得一试)

关于子模块的一些好资源:


由于这里只能使用绝对路径,这意味着相对路径需要一个参考对象进行比较。
该参考对象是“远程源”,应该在您的DirName/NewRepo_withSubmodules/.git/config文件中,如下所示:
$ cat .git/config
    ...
    [remote "origin"]
    url = /path/to/DirName/NewRepo_withSubmodules/.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    ...

如果您在`../DirName/NewRepo_withSubmodules/.git/config`文件中有该部分,您应该能够使用相对路径将`../Extern/Lib1`添加为子模块。
上述内容的灵感来自于git子模块手册的以下部分:
<repository>是新子模块源仓库的URL。
这可以是绝对URL,也可以是(如果以./../开头)相对于超级项目的origin仓库的位置

因此,如果`NewRepo_withSubmodules`是一个刚创建的本地Git仓库(当然没有"origin"),则应定义一个人工的"remote origin"(即使该origin指向自身),只是为了允许使用其他子模块仓库的相对URL。
Git 2.13 (Q2 2017)将改进对子模块默认源的检测。
请参阅commit d1b3b81(2017年2月25日)由Stefan Beller (stefanbeller)提交。
(由Junio C Hamano -- gitster --commit ae900eb中合并,2017年3月10日)

submodule init: 警告回退到本地路径

根据现在的记录:

<repository> 是新子模块源代码库的URL。
它可以是绝对URL,也可以是相对于超级项目默认远程代码库的位置(如果以./../开头)
(请注意,要指定一个位于超级项目'bar.git'旁边的仓库'foo.git',您必须使用'../foo.git'而不是'./foo.git' - 这与遵循相对URL规则时所期望的相对目录的评估在Git中是相同的)。

默认远程是当前分支的远程跟踪分支的远程。
如果不存在这样的远程跟踪分支或者HEAD处于分离状态,则假定"origin"为默认远程。
如果超级项目没有配置默认远程,则超级项目本身是其自己的上游权威,使用当前工作目录。


Git 2.20 (Q4 2018) 改进了子模块的本地路径支持。
请参阅 commit e0a862f(2018年10月16日)由 Stefan Beller (stefanbeller) 提交。
(由 Junio C Hamano -- gitster -- 合并于 commit 3fc8522, 2018年11月6日)

submodule helper: 如果需要,将相对URL转换为绝对URL

The submodule helper update_clone called by "git submodule update", clones submodules if needed.
As submodules used to have the URL indicating if they were active, the step to resolve relative URLs was done in the "submodule init" step. Nowadays, submodules can be configured active without calling an explicit init, e.g. via configuring submodule.active.

When trying to obtain submodules that are set active this way, we'll fallback to the URL found in the .gitmodules, which may be relative to the superproject, but we do not resolve it, yet:

git clone https://gerrit.googlesource.com/gerrit
cd gerrit && grep url .gitmodules
  url = ../plugins/codemirror-editor
  ...
git config submodule.active .
git submodule update
  fatal: repository '../plugins/codemirror-editor' does not exist
  fatal: clone of '../plugins/codemirror-editor' into submodule path '/tmp/gerrit/plugins/codemirror-editor' failed
  Failed to clone 'plugins/codemirror-editor'. Retry scheduled
  [...]
  fatal: clone of '../plugins/codemirror-editor' into submodule path '/tmp/gerrit/plugins/codemirror-editor' failed
  Failed to clone 'plugins/codemirror-editor' a second time, aborting
  [...]

To resolve the issue, factor out the function that resolves the relative URLs in "git submodule init" (in the submodule helper in the init_submodule function) and call it at the appropriate place in the update_clone helper.


"

git submodule(man) 代码过于依赖来自配置文件(以及树内的 .gitmodules 文件)的数据,而没有进行验证,导致如果用户对存储库进行了更改(例如删除了 submodule.<name>.url),会出现空指针解引用的问题。
这个问题已在 Git 2.42(2023 年第三季度)中得到修复。

"
查看 commit fbc806a(2023年5月24日)由 Taylor Blau (ttaylorr) 提交。
(由 Junio C Hamano -- gitster -- 合并于 commit 9cd234e,2023年6月20日)

builtin/submodule--helper.c:处理缺失的子模块网址 报告者:Tribo Dar 签名者:Taylor Blau

In e0a862f ("submodule helper: convert relative URL to absolute URL if needed", 2018-10-16, Git v2.20.0-rc0 -- merge listed in batch #9), prepare_to_clone_next_submodule() lost the ability to handle URL-less submodules, due to a change from:

if (repo_get_config_string_const(the_repostiory, sb.buf, &url))
    url = sub->url;

to

if (repo_get_config_string_const(the_repostiory, sb.buf, &url)) {
    if (starts_with_dot_slash(sub->url) ||
        starts_with_dot_dot_slash(sub->url)) {
            /* ... */
        }
}

,which will segfault when sub->url is NULL, since both starts_with_dot_slash() does not guard its arguments as non-NULL.

Guard the checks to both of the above functions by first checking whether sub->url is non-NULL.
There is no need to check whether sub itself is NULL, since we already perform this check earlier in prepare_to_clone_next_submodule().

By adding a NULL-ness check on sub->url, we'll fall into the 'else' branch, setting url to sub->url (which is NULL).
Before attempting to invoke git submodule--helper clone, check whether url is NULL, and die() if it is.


是的,它确实是这样。然而,“git submodule add ../extern/Lib1 lib”中的“./lib”文件夹是空的。 - deepblue
3
该死,绝对路径可行,相对路径不行......这个问题在任何地方都没有提到(我已经读了好几个小时的教程,它们都使用 Web URL 作为示例)。
问题在于当其他人克隆我的存储库,并且没有正确的目录嵌套时,"submodule init/update" 就无法为他们工作......
有什么想法吗?
谢谢 Von,感激不尽。
- deepblue
你建议怎么做?问题是:这样做不就是将超级仓库(我们要放置子模块的仓库)中的绝对路径移动到子模块所引用的仓库中吗?在我的情况下,超级仓库和子模块内所引用的仓库(位于子模块中的DirName/extern/Lib1和DirName/NewRepo_withSubmodules)都在同一个主目录DirName下。因此,我希望能够移动该主目录(DirName)而不会破坏其中的配置。 - deepblue
2
太好了!它起作用了。为了使用外部子模块的相对路径,我必须首先执行以下操作(在新的非克隆存储库上):“git remote add origin ..”,然后“git submodule add ../extern/LibName lib”。再次感谢Vic! - deepblue
@deepblue:不用谢 :) 你已经接近成功了 ;) 它是 VonC,而不是 Von。但无论如何,回答你的问题让我在这个子模块主题上学到了更多,所以你可以随便叫我什么。 - VonC
显示剩余2条评论

5
我正在尝试同样的事情,并发现以下方法似乎有效:
我在Windows上有以下文件目录:
D:/phd/analyses
    /analysis1/ #这是一个现有的仓库
    /analysis2/ #另一个现有的仓库
    /analysis3.tex
    /analysis4.tex
    ...
    /analysisN.tex
analysis1.tex ... analysisN.tex 包含我尚未处理的想法(例如“存根”),而 analysis1/analysis2/ 是我正在处理的内容(因此其中包含代码、tex等)。一旦我开始处理其他分析,它们将被移动到自己的文件夹中,因此也会有自己的仓库。
我所做的是(在Git Bash中进行):

git init
git add *.tex
git remote add self .
git submodule add self:/analysis2/.git analysis2
git submodule add self:/analysis5/.git analysis5
git commit -m "Initial commit"

这似乎已经奏效。

D:/phd/analyses/.git/config 看起来没问题,.gitmodules 看起来像:


[submodule "analysis2"]
    path = analysis2
    url = self:analysis2/.git
[submodule "analysis5"]
    path = analysis5
    url = self:analysis5/.git

敬礼, 西蒙·纳普


3
对我来说不起作用(在Linux上)。它试图通过互联网访问计算机“self”。 - Mechanical snail
也不适用于达尔文系统:...[852]$ git submodule add -b myBranch self:../relativeRepo Cloning into relativeRepo... ssh: 无法解析主机名 self: nodename nor servname provided, or not known fatal: 远程端意外挂起 将 'self:../relativeRepo' 克隆到子模块路径 'relativeRepo' 失败。 - john.k.doe

1

(我在这里总结了解决方案。感谢VonC的贡献。)

在包含库中(例如containing.git/),git将相对路径解释为相对于未定义的origin远程路径。我们希望它相对于containing.git/目录,因此运行以下命令:

git remote add origin ..

不确定为什么是..而不是.

现在您可以添加子模块:

git submodule add ../extern/Lib1 lib

这对我没有用 - 它仍然尝试在本地路径中查找 ../extern/Lib1。我不得不执行 git remote rename myrem origin,然后 git submodule add ../extern/Lib1 lib,接着 git remote rename origin myremgit submodule foreach git remote rename origin myrem - M.M

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