【问题标题】:git asks to commit submodule modified contentgit 要求提交子模块修改的内容
【发布时间】:2017-07-01 12:57:30
【问题描述】:

最近我用这个命令更新了我的 vim 配置库中的子模块:

git submodule update --recursive --remote

当我打电话给git status 时,我得到了这个:

On branch master
Your branch is ahead of 'origin/master' by 5 commits.
  (use "git push" to publish your local commits)
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)
  (commit or discard the untracked or modified content in submodules)

        modified:   .vim/pack/starter-pack/start/YouCompleteMe (modified content)

no changes added to commit (use "git add" and/or "git commit -a")

然后我跟踪了具有“修改内容”的子模块链,发现唯一的修改是子模块的未跟踪提交:

On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
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:   vendor/bottle (new commits)
        modified:   vendor/jedi (new commits)
        modified:   vendor/waitress (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

这些子模块(bottle、jedi、waitress)的主分支位于其远程来源的主分支之后,所以我想git submodule update 所做的不仅仅是拉取每个 repo 的来源,而是找到父存储库需要的适当版本。

如果它是父模块需要的确切提交,为什么 git 甚至用 (new commits) 标记这个 repos?那里发生了什么?

【问题讨论】:

    标签: git git-submodules youcompleteme


    【解决方案1】:

    这里发生的情况是您的超级项目现在不一致。具体来说,您的超级项目有 gitlinks 需要提交。

    您应该添加新的 gitlinks(像往常一样使用 git add)并提交(像往常一样)。然后你可以推送你的新提交(像往常一样)。

    子模块意味着超级项目

    子模块 只是一个 Git 存储库,它被另一个 Git 存储库直接使用。在这种情况下,子模块本身只是一个普通的 Git 存储库:它不知道另一个 Git 存储库。另一个存储库是我们称为 superproject 的存储库,它确实知道子模块。

    任何 Git 存储库都需要一个包含一些数据的 .git 目录

    通常,创建 Git 存储库的方式是从其他地方克隆它:

    git clone http://...
    

    或其他。或者,您可以在目录中运行git init。无论哪种方式,您最终都会得到一个包含 Git 存储库本身的 .git 目录。在这个.git 中,您通常会定义一个名为originremote。这是一个记录 URL 的短名称(特别是名称 origin!),也就是您在上面给 git clone 的 URL。此 URL 甚至可能指向您自己在 GitHub 上的存储库。

    (如果您从其他人的存储库开始,然后决定在 GitHub 上创建自己的存储库,您甚至可能有 两个 遥控器。通常您将自己的存储库命名为 origin,另一个命名为 @ 987654332@,但就 Git 本身而言,这些只是任意名称。我们都同意 origin 的唯一原因是这是 git clone 在我们第一次运行 git clone <em>url</em> 时为我们创建的名称。)

    反正.git目录下的数据包括以下内容:

    • origin 的 URL。
    • 任何分支的名称,以及这些分支标识的提交哈希 ID。
    • 同样,标签的名称及其提交。
    • 当前 提交:在存储库中签出的究竟是什么?这可能是一个分支名称,在这种情况下,存储库是在一个分支上,或者它可能是一个原始提交哈希 ID,在这种情况下,存储库处于“分离”状态HEAD”模式。

    如果超级项目创建子模块怎么办?

    一个超级项目需要了解其每个子模块的几件事情。首先,超级项目有一个名为.gitmodules 的文件。在这个.gitmodules 文件中,您将找到每个子模块的URL。您还将为每个子模块找到一个路径

    此文件的确切形式和内容在the gitmodules documentation 中进行了描述。稍微引用一​​下,假设它说:

    [submodule "libfoo"]
            path = include/foo
            url = git://foo.com/git/lib.git
    

    这意味着,当您克隆超级项目,然后运行 ​​git submodule init,您的 Git 将知道它应该运行 git clone git://foo.com/git/lib.git——这是 url 部分——克隆进入 @987654343 @目录:路径部分。

    这个谜题缺少一个关键部分。在您的 Git 将另一个 Git 克隆到 include/foo 之后,在子模块中签出什么提交?

    在大多数普通存储库中,这并不是什么大问题。签出什么提交?我不知道,我只是运行git checkout master,对吗?这让我获得了分支master 上的最新 提交,这正是我想要的。

    超级项目和子模块不能这样工作。当我使用我的超级项目中的子模块时,我会围绕子模块中的一个特定提交构建我的超级项目代码。例如,我可能特别依赖于别人库的v3.4.1,所以我会进入子项目并运行git checkout v3.4.1 来检查那个特定的标签

    理想情况下,我可能会让我的超级项目记录该标签(这很好,gitlinks 应该允许这样做,但目前他们不允许这样做)。1 但是在 Git 中,标签实际上只是一个特定提交的人类可读名称。标签v3.4.1 可能是提交feeddadac0ffee... 的名称或类似名称。那个——又大又丑的哈希 ID——才是真正进入 gitlink 的东西。

    gitlink 本身存储在每个提交中,就像一个常规文件存储在每个提交中一样。如果我在超级项目中使用新的或修改的README 文件进行新提交,则README 的新版本将进入Git 存储库,新提交引用新的README。之后的每次提交都会继续引用新的README

    同样适用于 gitlink:如果我的 include/foo 引用子模块的 v3.4.1 的哈希 ID,那么从这里开始的每个提交都有一个 gitlink 条目,上面写着:“当你检查这个提交时,你应该还可以进入include/foo 子模块并查看哈希 ID feeddadac0ffee..."。


    1如果有人想尝试添加它,我认为有一种方法可以做到,甚至可能有点向后兼容:像往常一样存储原始哈希 ID,然后是 NUL字节,后跟参考名称。不理解新型 gitlink 的较旧 Git 可以直接使用哈希 ID,而较新的 Git 可以检测并使用该名称。 Gitlink 条目无论如何都需要在从 SHA-1 到 Git 将来使用的任何哈希转换中进行类似的更改,所以这可能是添加它的好时机。


    如果子模块的所有者发布了新版本怎么办?

    所以,我用v3.4.1 测试了我的超级项目,一切正常。伟大的!但是现在负责这个include/foo 库的人已经更新了他们的 代码并发布了版本v3.4.2。这个新版本有一些新功能,我想使用它。

    我,作为超级项目的所有者,现在应该进入我的子模块和git fetch,然后是git checkout v3.4.2。 (这可能不是 feeddadac0ffee,而是哈希 ID deadcabbadcab005e...。)然后我应该返回我的超级项目,进行使用新子模块所需的任何更改,测试所有内容并提交.

    当我做出新的提交以使用子模块的v3.4.2 时,我不应该只提交 my 更改。我还需要更新我的 gitlink。由于我已经在子模块中完成了git checkout deadcabbadcab005egit checkout v3.4.2,实际上是完全相同的事情,所以我所要做的就是在我的超级项目中使用git add include/foo。这会将更新后的 gitlink 添加到我的索引中,因此当我运行 git commit 时,我会记录 new gitlink 以及我的其他更改。

    这是一个新的提交,我现在可以推送我的提交,如果还有其他地方我也保存我的超级项目(在 GitHub 或其他地方)。

    【讨论】:

    • 感谢您的回答和充实的解释。但是我害怕在其他人的存储库中提交,因为我认为将来再次更新子模块时可能会导致合并冲突。如果我提交,合并冲突会发生吗?如果可以,会自动解决吗? (我一开始应该问的)
    • 我完全不清楚您是否在任何子存储库中进行了任何提交。 (git submodule update --remote 不会,它只是更改您选择了哪个提交。)但是,所有 Git 存储库都是本地的定义并且所有存储库都是您自己的。这包括您的子模块存储库:它们是您的。您当时可能是从其他人那里复制的,但他们现在是您的了。只有git push,如果您这样做,会影响其他人的存储库(并且只有在他们允许的情况下)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 2013-01-03
    相关资源
    最近更新 更多