如何将 Git 存储库转换为嵌套在另一个(父)Git 存储库中的子模块?
How to convert a Git repo to a submodule, which is nested in another (parent) Git repo?
我有一个 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 存储库的子文件夹(子存储库)。
此外,plugin1、plugin2、plugin3 作为本地 Git 回购启动,并添加了内容和历史记录。
我想将 plugin1、plugin2、plugin3 从 Git 子库转换为主 Git 库中的子模块。
我想在插件的 Git 存储库中单独进行开发,但仍将它们保留为子文件夹。它们也应该仍显示为主要 Git 存储库中的链接。
我使用 Git 扩展作为开发版本控制 GUI。
切换到 main 目录,签出 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 存储库中有任何未提交的更改,您应该在执行上述步骤之前提交并推送它们。
此时,从 main 目录执行 git 状态应该显示类似于以下内容:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD ..." to unstage)
#
# new file: .gitmodules
# new file: subdirectory1/plugin1sm
由于您在 main 目录中,新的子模块在变更集中显示为 "file"。您可以使用以下命令提交此更改:
$ 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 子模块,它将在主存储库的变更集中显示为修改后的 "file"。要继续,您可以添加子模块并使用以下命令推送它:
$ cd ../../
$ git add subdirectory1/plugin1sm
$ git commit -m "updated my submodule"
$ git push origin master
总而言之,您在子模块中的基本 Git 工作流程将照常进行,而在您的 main 存储库中,您需要牢记整个子模块将显示为一个文件。事情变得比我们在这里考虑的简单用例更复杂,但希望这能让您走上正确的道路。
您可以对 plugin2 和 plugin3 目录重复此过程。当你创建完子模块后,你应该可以删除原来的插件目录。
我做了一个丑陋的 hack 来解决我在 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
这是最终对我来说似乎工作正常的解决方案(在 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
我的回答分为条件和解决方案两部分。
第一部分:条件
我遇到了同样的问题,但我已经有一个结构相同的类似存储库,
说
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
那么怎么办:
第二部分:解决方案
- 确保子模块具有相同的文件夹名称
Project1 (not a repo)
|___ Submodule1
|___ Submodule2
然后复制Project2/.gitmodules
到Project1/
然后将Projec2的.git/conif
的content submodule部分复制到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 = ######
我有一个 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 存储库的子文件夹(子存储库)。 此外,plugin1、plugin2、plugin3 作为本地 Git 回购启动,并添加了内容和历史记录。
我想将 plugin1、plugin2、plugin3 从 Git 子库转换为主 Git 库中的子模块。
我想在插件的 Git 存储库中单独进行开发,但仍将它们保留为子文件夹。它们也应该仍显示为主要 Git 存储库中的链接。
我使用 Git 扩展作为开发版本控制 GUI。
切换到 main 目录,签出 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 存储库中有任何未提交的更改,您应该在执行上述步骤之前提交并推送它们。
此时,从 main 目录执行 git 状态应该显示类似于以下内容:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD ..." to unstage)
#
# new file: .gitmodules
# new file: subdirectory1/plugin1sm
由于您在 main 目录中,新的子模块在变更集中显示为 "file"。您可以使用以下命令提交此更改:
$ 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 子模块,它将在主存储库的变更集中显示为修改后的 "file"。要继续,您可以添加子模块并使用以下命令推送它:
$ cd ../../
$ git add subdirectory1/plugin1sm
$ git commit -m "updated my submodule"
$ git push origin master
总而言之,您在子模块中的基本 Git 工作流程将照常进行,而在您的 main 存储库中,您需要牢记整个子模块将显示为一个文件。事情变得比我们在这里考虑的简单用例更复杂,但希望这能让您走上正确的道路。
您可以对 plugin2 和 plugin3 目录重复此过程。当你创建完子模块后,你应该可以删除原来的插件目录。
我做了一个丑陋的 hack 来解决我在 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
这是最终对我来说似乎工作正常的解决方案(在 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
我的回答分为条件和解决方案两部分。
第一部分:条件
我遇到了同样的问题,但我已经有一个结构相同的类似存储库, 说
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
那么怎么办:
第二部分:解决方案
- 确保子模块具有相同的文件夹名称
Project1 (not a repo)
|___ Submodule1
|___ Submodule2
然后复制
Project2/.gitmodules
到Project1/
然后将Projec2的
.git/conif
的content submodule部分复制到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 = ######