Git子模块:无法将子模块更新到早期版本

5

我花了很多时间来阅读和尝试git子模块,但我已经放弃了。

我的问题:

我正在将一个git仓库作为子模块进行克隆。所以,我执行以下操作:

git submodule add -b master url localpath

代码库开始下载,.gitmodules文件中会有对应的条目。使用git submodule status命令可以显示最新的提交。

到目前为止都很顺利。

在开发过程中,发现子模块中的HEAD提交存在一个bug。因此,需要将提交从master更改为某个提交ID。

于是,我在.gitmodule文件中将commit id(7位字母数字)从branch = master更改了。

branch = <commitid> -> .gitmodule file

And did

git submodule update --remote

错误信息为:

致命错误:需要一个单一的修订版本

无法在子模块路径中找到当前的 origin/ 修订版本

我还尝试了

 git submodule foreach git pull

所以它将拉取提交ID,但它只是简单地返回

输入子模块的名称

已经是最新的。

有人能帮我吗?

P.S:我已经阅读了许多教程和问答。如果你想为了好玩而对此进行投票,那么请先指出一个答案,我会删除这篇文章。

2个回答

3

经过一番研究和自己回答问题,我认为以下内容对他人可能有所帮助:

理解git子模块非常困难,但一旦掌握,一切就都变得清晰易懂了!

以下文章展示:

  • 如何添加子模块,并让其他人同步更新您的子模块。
  • 如何更新子模块,并让其他人同步更新您的子模块。
  • 如何移除子模块,并让其他人同步更新您的子模块。
  • 如何更新已移除的子模块。

添加子模块

git submodule add -b

.gitmodules中的条目(名称、路径、URL、分支)通过下载相应的子模块进行操作。

git submodule update --init

这个操作有三个重要的作用,其中前两个对用户隐藏:
  1. 更新.git/config文件,增加一个额外的条目(submodules)

  2. 以裸形式在.git/modules下下载存储库。这意味着,在.git内部还有一个.git。

  3. 将git子模块从.git/modules检出到父目录中。

现在,在第二天,提交者意识到应该将子模块更改为其他提交而不是HEAD。因此,他会进入本地存储库,然后进入子模块路径,并通过简单调用来检出所需的提交:
git checkout <hash>
cd <parent dir>
git submodule status

此时,git子模块状态仍未显示新的哈希值。只有在更改被暂存时,新的哈希值才会显示出来。现在,提交者只需要暂存(添加)、提交和推送更改,以便所有其他开发人员都能看到。

更新已添加的子模块

第三天,其他开发人员只需调用命令来更新他们的存储库:

git pull # this is to get the latest commit of the parent git repository.
git submodule update --force # update the submodule with latest hash

基本上,这里的要点很简单:子模块在没有被告知之前不会做出反应。仅仅执行git pull并不能更新git子模块。开发人员可以继续在本地子模块上工作,并且不必将其与服务器上的子模块同步“永远”不变。只有在显式调用git submodule update命令时,子模块才会更新。

删除子模块

现在,在第四天,提交者决定完全删除git子模块。这里的步骤也不简单,因为没有称为git submodule rm的东西应该等价于git submodule add。只有按照以下顺序进行操作才能完成:

git submodule deinit submodulename
  1. 这将删除 .git/config 条目。

  2. 这将清空子模块目录!!执行此命令后,您将在子模块目录中看不到任何内容。

  3. 但是子模块的内容仍然可以在 .git/modules 下找到。

因此,在此处执行 git status -u 命令仍会显示所有内容都是最新的!

因此要显示移除的内容,

git rm submodulepath

现在,执行git status命令会返回.gitmodules文件已更改(子模块已删除),并且子模块路径已被删除。提交并推送更改。

删除子模块后的更新

第五天,开发人员想要像使用git submodule update一样“自动”删除子模块。因此,他们首先执行git pull命令,成功地删除了所有与git子模块相关的索引。

 git submodule status # shows nothing

但是,.git/config仍然包含有效的子模块条目,子模块文件夹以及.git/submodules下的裸仓库也都在那里!没有命令可以删除它们。所有这些必须通过手动显式移除。(如果我说错了,请纠正我)

2

在按照您的问题描述克隆子模块之后:

git submodule add -b master url localpath

然后你应该能够使用changedir命令切换到子模块目录:

cd localpath

一旦进入子模块,您可以使用任何git命令,它们只会影响子模块的代码库。例如,您可以检出那个重要的分支或版本:

git checkout <branch|tag|hash>

或者检出主分支中倒数第二个版本:
git checkout HEAD~1

然后 changedir 回到主 git 仓库:

cd ..

而且 git status 应该会返回类似以下的内容:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitmodules
    new file:   localpath

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   localpath (new commits)

然后只需将子模块中所做的更改添加到您的项目中即可:

git add localpath

提交更改

git commit -m "Add submodule url to localpath with older working commit"

明白了!有一些教程提到要用<提交 ID>更改.gitmodule文件。但是全部都失败了,这让人感到困惑。最简单的方法是克隆整个分支(不管提交 ID 是什么),然后在你想要的提交 ID 的子模块中进行git checkout,接着在父分支中执行git commit,最后推送变更。 - infoclogged
还有一件事。已经下载了整个包括子模块的代码的其他开发人员需要调用git pull,然后使用git submodule update或git submodule update --remote来与最新的子模块更改同步。 - infoclogged
是的,每次更改子模块引用时,在父存储库上执行 git pull 时,子模块将显示为“已修改”。要将子模块更新到新引用,请在主存储库上运行 git submodule update - Thibault D.

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