更改Git子模块提交

时间:2018-08-17 12:22:55

标签: git ubuntu

尝试使用Apache Ant从存储库“构建”时,我收到类似于此错误

Fetched in submodule path 'externals/ringojs-fork', but it did not contain 
298e62daa64923b7bc1e4a085233529f907ba7bf. Direct fetching of that commit 
failed.

从我读到的内容来看,我认为我需要更改子模块之一在其中进行提交的提交。

如图所示,我的ringojs-fork外部子模块从298e开始的提交中拉出。我如何将其更改为主人?

我在Linux Ubuntu上。

enter image description here

1 个答案:

答案 0 :(得分:1)

  

...从我读过的书中,我认为我需要更改我的一个子模块正在拉动的提交。

也许。在某些情况下,您只需要戳一个人即可更新上游子模块。或者,也许您应该只在超级项目中使用其他提交。或者,也许您的子模块被克隆为 shallow 存储库,但不应复制。 (基于https://github.com/ringo/ringojs/tree/298e62daa64923b7bc1e4a085233529f907ba7bf存在的事实,我认为最后一种可能性最大。)

如果问题实际上是浅表克隆,则导航至子模块存储库并运行git fetch --unshallow应该可以解决此问题。您可以使用git submodule foreach git fetch --unshallow来做到这一点。

背景

您可能已经知道Git存储库是什么:它是 commits 的集合(或数据库),每次提交都代表整个源树的完整完整快照。某些特定的提交现在或总是非常重要,因此这些提交具有名称:分支名称,例如master,将 latest 提交命名为该分支。这很重要,因为它是新!发光!或其他任何东西。同时,标记名称(如v1.2)会标明一些 person 重要的提交,例如稳定的发布。

这些名称中的每一个(分支或标签,或者实际上,您可以在Git存储库中使用的任何其他可读名称,如origin/master或其他名称)实际上只是原始哈希ID的名称。这些哈希ID包括298e62daa64923b7bc1e4a085233529f907ba7bf之类的东西,显然是随机的,丑陋的十六进制数字,对人类没有用。您刚刚看到了这样一个数字对您没有用的示例。但是它们是 Git 用来签出特定提交的东西。当您使用masterv1.2之类的名称时,Git将该名称转换为正确的哈希ID,然后签出该提交。

由于Git存储库至少通常是 ,因此变得非常重要,完全自包含,因此Git可以确保所有名称均有效并标识有效的提交。当您告诉Git:签出master 时,从来就不会存在名称master和名称提交a123456...以及 commit 不存在。提交不存在,并且master可以命名它,或者提交存在,而主不能命名它。 1

当您使用分支名称来检出一个特定的提交时(例如,通过运行git checkout mastergit checkout develop),Git会将名称转换为哈希ID,在数据库中找到该提交,然后将提交提取到工作树中,您可以在其中使用和/或对其进行处理。数据库内部的提交格式仅可由Git本身使用,因此,如果没有工作树,您将无法进行任何工作。在Git提取提交的同时,Git为您记住名称​​ ,这样您现在就处于“分支”上。

但是,您还可以通过其原始哈希ID选择所需的任何历史提交,然后运行git checkout a123456...。当然,该提交必须存在,但是假设确实如此,Git会将那个提交提取到您的工作树中,并记住您不在任何地方。 em>现在分支。相反,Git说您有一个“分离的头”。

通常,您通过克隆获得 Git存储库:

git clone <url> <directory>

克隆在给定URL处找到的存储库,并将其放在特定目录中。 git clone的最后一步是git checkout的分支或标记-通常是分支名称master,但是您可以在git clone上添加参数以说明要检出的内容。< / p>


1 这引起了一个有趣的案例,即新的完全空的Git存储库。在这样的Git存储库中,尚无提交。这意味着没有分支!在新的完全空的存储库中,分支名称master不存在。您创建的第一个提交成为 在分支master上的最新提交,这样,还会创建 name {{ 1}}。这是因为名称必须始终包含有效的提交哈希ID。


子模块

考虑到所有这些,让我们花点时间描述子模块是什么。简短的版本是子模块只是另一个Git存储库。子模块唯一的特别之处是它存在,因为一些 other Git存储库(Git称为 superproject )说:“当我在我自己的Git存储库,我也想使用另一个Git存储库。”超级项目必须提供您将传递给master的信息:URL和路径。

但是,如果您开始在子模块中工作,您会发现它几乎总是处于特殊的“分离式HEAD”状态。那是因为超级项目 also 而不是签出 branch tag ,而是告诉子模块Git:顺便说一句,您已经克隆或获取了所有内容,我想一个特定的提交,这里是哈希ID:_______ 。超级项目提供原始哈希ID,而不是git clonemaster之类的名称,而只是原始哈希ID。

这是您看到的错误的来源。您选择的超级项目存储库(Ant的某些版本)按名称列出了子模块存储库(显然是ringojs-fork东西)。您可以很好地克隆其他Git存储库。但是,然后,您的超级项目告诉您的Git系统:从ringojs-fork获取最新版本后,签出提交v1.2但是提交298e62daa64923b7bc1e4a085233529f907ba7bf 不存在

谁错了?当它说“ use commit 298e62daa64923b7bc1e4a085233529f907ba7bf”时,它是超级项目吗?还是说“提交298e62daa64923b7bc1e4a085233529f907ba7bf还不存在”的子模块?也许甚至两者都是错误的。好吧,有点。子模块存储库是一个存储库,因此它应该是自包含的,并具有所有功能。

哪里可能出错

Git是一个分布式版本控制系统,这意味着每个存储库都有许多副本。毕竟,每个克隆都是副本。但是某些克隆可能比其他克隆更新。假设控制此ringojs-fork的某人忘记运行298e62daa64923b7bc1e4a085233529f907ba7bf来更新GitHub克隆。这样,某人可能已经提交了git push,但从未将其发送给其他所有人。在这种情况下,您只需要让控制该ringojs-fork的任何人发送该提交,就可以将其取回。

或者,298e62daa64923b7bc1e4a085233529f907ba7bf可能同时存在,可供所有人使用。它甚至可能在某些克隆中存在。但是298e62daa64923b7bc1e4a085233529f907ba7bf中发生了一件可怕的事情,因此,控制ringojs-fork的人都将其小心切除了。换句话说,它在那里,但现在已经不复存在了,没有人应该要求它。 (这种情况是有问题的,因为其他人可能会依赖它,或者将其放回去,或者至少尝试将其放回去。将提交内容从这样的公共存储库中剔除很少有好处。)在这种情况下,我们看到您的Ant项目(您的超级项目)依赖于它。

更准确地说,您的超级项目中的至少一个特定提交取决于子模块中的此提交。也许超级项目中的其他提交,在这种情况下,如果切换到超级项目中的其他提交之一,也许可以解决问题。不能更改任何提交,因此,您现在正在使用的超级项目中的特定提交将始终在子模块中要求该其他特定提交(通过哈希ID)。如果不应该要求子模块的提交,则超级项目中的该特定提交绝对不应使用

或者,还有另一种可能性。我在上面提到,存储库通常是完全独立的。但是,有一个特殊的例外,这很常见,称为浅克隆。浅层克隆是故意忽略很多提交以使克隆更快的克隆。

省略很多提交以加快克隆速度是非常棒的,直到有人要求其中一个提交为止。现在,Git并不完全是愚蠢的,它只是大多数情况下是愚蠢的,因此,浅表克隆忽略了某些提交,也忽略了该提交的任何 name 。但是,超级项目不要求使用 name 进行提交,而是直接通过原始哈希ID进行请求。这意味着,如果您要对子模块进行浅表克隆,那么超级项目就很容易调用未在克隆步骤中复制的提交。

问题的根源在于,超级项目通过原始哈希ID列出了子模块的提交,而两个Git存储库只是松散耦合。在超级项目存储库中导致提交的任何事物都列出了一个无论出于何种原因,子模块存储库中不可用的哈希ID都会导致此错误。这包括偶尔无法推动的情况,但大多数情况下包括浅克隆的情况。

(请注意,如果子模块移动,例如,从一个GitHub URL移至另一个GitHub URL,则可能必须调整子模块克隆,该克隆可能会列出旧URL,其方式与您必须相同。如果超级项目的URL发生更改,请调整超级项目的URL。)