【问题标题】:How to convert a Git repo to a submodule, which is nested in another (parent) Git repo?如何将 Git 存储库转换为嵌套在另一个(父)Git 存储库中的子模块?
【发布时间】:2015-04-03 02:43:11
【问题描述】:

我有一个 Git 存储库,其中包含作为 Git 子存储库的子文件夹。

+ main (local GIT repo)
  + subdirectory1
     + plugin1 (created as local GIT repo)
     + plugin2 (created as local GIT repo)
  + subdirectory2
    + subdirectory2a
      + plugin3 (created as local GIT repo)
  + subdirectory3

plugin1、plugin2、plugin3 是主 Git repo 的子文件夹(subrepos)。 此外,plugin1、plugin2、plugin3 作为本地 Git 存储库启动,并添加了内容和历史记录。

我想将插件 1、插件 2、插件 3 从 Git 子存储库转换为 Git 主存储库中的子模块。

我想在插件的 Git 存储库中单独进行开发,但仍将它们保留为子文件夹。它们还应该在主 Git 存储库中显示为链接。

我使用 Git Extensions 作为开发版本控制 GUI。

【问题讨论】:

    标签: git version-control repository git-submodules git-extensions


    【解决方案1】:

    切换到ma​​in目录,签出master分支,执行以下Git命令为plugin1新建一个子模块:

    git submodule add (url_to_plugin1_repository) subdirectory1/plugin1sm
    

    这里的“url_to_plugin1_repository”指向您当前的 plugin1 的 Git 存储库。将创建一个名为 subdirectory1/plugin1sm 的新目录,该目录将跟踪您的远程存储库。我给它起了一个不同的名字,以区别于不是子模块的 plugin1 目录。请注意,Git 将从远程 url 克隆 plugin1sm 目录的数据,而不仅仅是从本地复制。话虽如此,如果您在本地 plugin1 存储库中有任何未提交的更改,您应该在执行上述步骤之前提交并推送它们。

    此时,从 ma​​in 目录执行 git status 应显示类似于以下内容:

    $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD ..." to unstage)
    #
    #   new file:   .gitmodules
    #   new file:   subdirectory1/plugin1sm
    

    由于您位于 ma​​in 目录中,因此新的子模块在变更集中显示为“文件”。您可以使用以下命令提交此更改:

    $ git add subdirectory1/plugin1sm
    $ git commit -m "Created submodule for plugin1"
    $ git push origin master
    

    您可能会想到的下一个问题是如何将新的子模块与您的主 Git 存储库一起使用。让我们先来看看当您处理 plugin1sm 目录中的文件时会发生什么。当您在 plugin1sm 目录中工作时,Git 将跟踪更改并表现得好像它不知道该目录之外的任何内容。当需要提交和推送您的更改时,您可以使用以下预期命令:

    $ cd subdirectory1/plugin1sm
    $ git add <yourfile>
    $ git commit -m "modified my file"
    $ git push
    

    但是主存储库呢?这是事情变得有点有趣的地方。由于您修改了 plugin1sm 子模块,它将在主存储库的变更集中显示为修改后的“文件”。要继续,您可以添加子模块并使用以下命令推送它:

    $ cd ../../
    $ git add subdirectory1/plugin1sm
    $ git commit -m "updated my submodule"
    $ git push origin master
    

    总而言之,您在子模块中的基本 Git 工作流程将照常进行,并且在您的 存储库中,您需要记住整个子模块将显示为一个文件。事情变得比我们在这里考虑的简单用例更复杂,但希望这能让您走上正确的道路。

    您可以对 plugin2plugin3 目录重复此过程。当你创建完子模块后,你应该可以删除原来的插件目录了。

    【讨论】:

    • 感谢您的回答。我的问题是,我想保留 plugin1 目录是唯一的。我不想为子模块创建 plugin1sm 目录。
    • 我做了一个丑陋的 hack 来解决我在 Git Extensions 中的子模块问题。也许不是真的有效,但目前有效。由于它的长度,我将我的 hack 添加为单独的答案。不知道有没有缺点。
    • 在将 plugin1sm 目录添加为子模块后,您可以随时将目录重命名为您想要的任何名称。
    【解决方案2】:

    我的答案有两个部分,条件和解决方案。

    第一部分:条件

    我有同样的问题,但我已经有一个类似的存储库具有相同的结构, 说

    Project1 (not a repo)
       |___ Repo1
       |___ Repo2
    

    和:

    Project2 (a repo)
       |___ Submodule1 (same repo as Repo1)
       |___ Submodule2 (same repo as Repo2)
    

    我想将 Repo1 和 Repo2 转换为 Project1 的子模块,它与 Project2 基本相同。 明确地说,克隆 Project2 并不能解决问题,因为 Project1 和 Project2 中有更多的文件不一样,但为了简单起见..

    所以我的 Project1 的 .git/config 看起来像这样

    [core]
    repositoryformatversion = 0
    filemode = false
    bare = false
    logallrefupdates = true
    symlinks = false
    ignorecase = true
    

    我的 Project2 的 .git/config 是这样的:

    [core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
    [submodule]
        active = .
    [remote "origin"]
        url = ######
        fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
        remote = origin
        merge = refs/heads/master
    [submodule "Submodule2"]
        url = ######
    [submodule "Subodule2"]
        url = ######
    

    在 Project2 中,有一个名为 .gitmodules 的文件:

    我有同样的问题,但我已经有一个类似的存储库具有相同的结构, 说

    Project1 (not a repo)
       |___ Repo1
       |___ Repo2
    

    和:

    Project2 (a repo)
       |___ Submodule1 (same repo as Repo1)
       |___ Submodule2 (same repo as Repo2)
    

    我想将 Repo1 和 Repo2 转换为 Project1 的子模块,它与 Project2 基本相同。 明确地说,克隆 Project2 并不能解决问题,因为 Project1 和 Project2 中有更多的文件不一样,但为了简单起见..

    所以我的 Project1 的 .git/config 看起来像这样:

    [core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
    

    我的 Project2 的 .git/config 是这样的:

    [core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
    [submodule]
        active = .
    [remote "origin"]
        url = URL/TO/Project2
        fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
        remote = origin
        merge = refs/heads/master
    [submodule "Path/To/Submodule2"]
        url = ######
    [submodule "Path/To/Subodule2"]
        url = ######
    

    在 Project2 中,有一个名为 .gitmodules 的文件:

    [submodule "Path/To/Submodule1"]
        path = Path/To/Submodule1
        url = ######
        branch = master
    [submodule "Path/To/Submodule2"]
        path = Path/To/Submodule2
        url = ######
        branch = master
    

    那该怎么办:

    第二部分:解决方案

    1. 确保子模块具有相同的文件夹名称

    Project1 (not a repo) |___ Submodule1 |___ Submodule2

    1. 然后将Project2/.gitmodules复制到Project1/

    2. 然后将Projec2的.git/conif的内容子模块部分复制到Project1的.git/config,它基本上看起来像Project2,但没有覆盖[remote "origin"]:

    我的 Project1 的 .git/config 是这样的:

    [core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
    [submodule]
        active = .
    [remote "origin"]
        *url = URL/TO/Project1*
        fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
        remote = origin
        merge = refs/heads/master
    [submodule "Path/To/Submodule2"]
        url = ######
    [submodule "Path/To/Subodule2"]
        url = ######
    

    【讨论】:

    • 感谢分享您的经验!
    【解决方案3】:

    这是对我来说最终似乎可以正常工作的解决方案(在 Windows 下,使用 Git 扩展作为用户界面):

    以下操作在命令行中完成:

    cd c:\!GIT\main     # main
    git branch
    git checkout dev-main
    
    mkdir subdirectory1\plugin1
    cd subdirectory1/plugin1
    git init        # init git
    git status      # show status
    git add .       # stage
    git commit -m "Initial commit"      # initial commit
    git checkout -b "dev"       # create dev branch
    git remote add origin ./subdirectory1/plugin1    # add remote path
    
    # create submodule in main
    cd ../..
    git submodule add ./subdirectory1/plugin1 subdirectory1/plugin1  # create submodule
    git submodule   # show submodules
    git status
    git add .       # stage submodule
    git status
    git commit -m "Submodule subdirectory1/plugin1"
    git status
    git config submodule.subdirectory1/plugin1.url ./subdirectory1/plugin1   # add relative path to config
    git submodule   # show submodules
    

    【讨论】:

      【解决方案4】:

      我做了一个丑陋的黑客来解决我在 Git 扩展中的子模块问题。
      也许不是真的有效,但目前有效。

      cd main/subdirectory1/plugin2
      git init
      git status
      git add .
      git commit -m "Initial commit of Submodule."
      git checkout -b dev     # create branch dev
      
      git submodule add ./subdirectory1/plugin2 subdirectory1/plugin2
      
      Add the following config text to w:/path/to/main/.git/config:
      [submodule "subdirectory1/plugin2"]
          url = w:/path/to/main/subdirectory1/plugin2
      
      Add the following config text to w:/path/to/main/.gitmodules (supporting Git Extensions to see submodule):
      [submodule "subdirectory1/plugin2"]
          path = subdirectory1/plugin2
          url = w:/path/to/main/subdirectory1/plugin2
          branch = dev
      

      【讨论】:

      • 为什么要发布两个不同的答案?为什么不将两个答案合二为一呢?
      猜你喜欢
      • 1970-01-01
      • 2018-04-05
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 2016-07-14
      • 1970-01-01
      • 2015-04-09
      • 1970-01-01
      相关资源
      最近更新 更多