如何在git存储库中创建现有目录git子模块

时间:2016-04-03 14:29:01

标签: git version-control git-submodules

我对git-submodules非常困惑。

基本上我的问题是我不能让git明白~/main-project/submodule是一个子模块。

我对git子模块有很好的经验:
在我的dotfiles repository中,我在~/dotfiles-repo中创建了.gitmodules文件,并添加了路径和网址。从那时起,如果我对子模块中的文件进行更改并运行git status,我会得到类似的内容:.vim/bundle/auto-complete (new commits) # in red

我在.gitmodules中创建了~/main-project文件但是:

  • 如果我对~/main-project/submodule进行了更改,甚至推动了更改,那么在<submodule> (new commits) # in red中运行git status时,我就不会得到类似~/main-project的响应。 我只是获得了在这些目录中所做的更改
  • 当我点击文件夹时这些目录的链接位于github,它并没有将我引导到存储库本身,而是保留在同一个存储库中。

    1. 也许我错过了重点。子模块的主要特征是什么?
    2. 为什么git理解the dotfiles repo但不是in my other repo中的子模块?
    3. 是不是因为我已经告诉git将~/main-project/submodule内的文件添加到索引中?

我已阅读this question,这导致我this answer但我不确定是否需要git-subtree。我不想做那些可能难以改变的事情。

  

修改:This suggested duplicate-solution也没有用,我收到Updates were rejected because the remote contains work that you do not have locally的错误。似乎@GabLeRoux实际告诉我将<repo-A>推送到<repo-B>的网址。

4 个答案:

答案 0 :(得分:25)

解决方案非常简单。它是从here中提取的。

  1. git rm submodule-dir
    这将删除git在submodule-dir
  2. 之后跟踪的所有文件
  3. rm -rf submoduledir
    这将删除submodule-dir中可能遗留的所有其他文件,因为git忽略了它们。
  4. 现在,我们必须提交才能从索引中删除文件:
    git commit
    在提交之后,我们清除了git遵循的文件,并且没有在submodul-dir中跟踪。 现在是时候了:
  5. git submodule add <remote-path-to-submodule>
    这将重新添加子模块,但作为一个真正的子模块。
  6. 此时检查.gitmodules并查看子模块是否已成功添加可能是个好主意。在我的情况下,我已经有一个.gitmodules文件,所以我不得不修改它。
  7. 修改

    v2.12.0-rc0以来this commit之后,我们收到了git submodule absorbgitdirs,这正是我在发布此问题时所需要的。

    这是此命令执行的docs状态:

      

    如果子模块的git目录在子模块中,   将子模块的git目录移动到其超级项目中   $GIT_DIR/modules路径,然后连接git目录和   它的工作目录是设置core.worktree并添加   一个.git文件,指向嵌入在中的git目录   superprojects git目录。

    所以不要像@DomQ和我之前的答案中所建议的那样重新开始,而是可以添加运行以下内容:

    1. 在不从索引中删除子模块的情况下,将子模块的URL添加到.gitmodules并添加到.git/config git submodule add <url> <path>
    2. 将子模块的$GIT_DIR目录(常规存储库中的.git)移动到.git/modules/<path> git submodule absorbgitdirs <path>

答案 1 :(得分:3)

基本上没有比假装重新开始更好的方式

  1. 确保所有内容都在任何地方提交
  2. 将您的子存储库移开
  3. git submodule add来自子存储库的远程
  4. cd mysubmodule
  5. git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
  6. git merge FETCH_HEAD
  7. 为了解释为什么会出现这种情况,在我看来,除了可以从git-submodule(1)手册页(或者甚至是relevant chapter from the Git book)。我在this blog post找到了一些更深入的解释,但由于这篇文章有点冗长,我在这里总结一下。

    在较低级别,git子模块由以下元素组成,

    • 子模块树顶部的commit object
    • (在最近的Git版本中).git/modules中的一个子目录,用于托管子模块的Git对象,
    • .gitmodules配置文件中的条目。

    在父树对象中包含(或更确切地说,由SHA1引用)提交对象。这是不寻常的,因为事件usually反过来发生了,但这解释了为什么在子模块中执行提交后,您会看到主存储库git status中出现一个目录。您还可以使用git ls-tree使some experiments更详细地观察此提交对象。

    .git/modules中的子目录代表子模块中的.git子目录;实际上,子模块中有一个.git 文件,它使用gitdir:行指向前者。这是默认行为since version 1.7.8 of Git。如果你只是继续使用一个单独的.git目录,不确定为什么一切都不会正常工作,除非在发行说明中注明,在具有子模块的分支和另一个分支之间切换时可能会遇到麻烦那不是。

    .gitmodules文件提供git submodule update --remote和朋友应该从中提取的网址;这显然不同于主存储库的一组遥控器。另请注意,.gitmodules.git/config命令以及在幕后调用它的其他命令部分复制到git submodule sync

    尽管对.gitmodules + .git/config以及.git/modules + mysubmodule/.git进行必要的更改非常容易(事实上,甚至还有对于后者,git submodule absorbgitdirs实际上并不是仅仅创建树内提交对象的瓷器。因此,通过上述移动+重做更改提出了解决方案。

答案 2 :(得分:2)

这些解决方案似乎都不适合我,所以我想出了自己的方法:

  1. 确保已存在一个新的git repo来保存内容 例如,我们将使用“ git@github.com:/ newemptyrepo

  2. 导航到您要调制的目录:

cd myproject/submodule-dir
  1. 从父级的索引中删除将要创建的子模块:
git rm -r --cached .
  1. 在待子模块中初始化一个新的git repo:
git init
  1. 设置待创建子模块的来源并进行首次提交:
git remote add origin git@github.com:/newemptyrepo
git add . && git commit && git push --set-upstream origin master
  1. 现在,您必须导航到父存储库的顶级路径:
cd .. && cd `git rev-parse --show-toplevel`
  1. 最后,像往常一样添加子模块:
git submodule add git@github.com:/newemptyrepo ./myproject/submodule-dir
  1. 现在提交并推送上述命令所做的更改,您已经完成设置!

答案 3 :(得分:1)

按顺序回答您的问题:

  1. 根据GitHub的purpose个子模块。功能方面,它被设计为概念化一个子存储库(几乎可以像任何其他文件一样对待),它是由父存储库控制的版本,其中父级跟踪子模块的当前提交ID(子级)存储库)而不是它的内容
  2. 这很可能是因为您已经将文件添加到存储库的索引中。在这种情况下,解决方案是git rm --cached submodule-name/。然后创建一个中间提交,然后添加文件夹作为存储库git add submodule-name(注意在子模块名称后面有没有尾部斜杠子模块的情况)。
  3. 是:)
  4. 您提到的answer也可以更正您提交的历史记录:

    1. 优点
    2. 该文件夹将被视为所有提交历史记录中的子模块,而不仅仅是所有未来的提交。如果您签出以前版本,它被视为文件夹,这可以避免任何复杂情况。这是一个复杂的问题,因为当您返回到分支的提示时,您可能还必须输入您的子模块并签出到最新的提交以恢复所有文件(可能从您的工作目录中删除)。这可以通过对您的最新提交进行某种递归检查来避免。

      1. 缺点
      2. 如果修改了提交历史记录,那么所有其他贡献者也必须重新克隆项目,因为它们会发生合并冲突或更糟;重新引入问题会提交回项目。