How to convert a GIT repo to a submodule, which is

2019-01-15 11:40发布

问题:

I have a GIT repo which has subfolders as GIT subrepositories.

+ 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

The plugin1, plugin2, plugin3 are subfolders (subrepos) of main GIT repo. Also plugin1, plugin2, plugin3 were initiated as local GIT repos and has content & history added.

I would like to convert plugin1, plugin2, plugin3 GIT subrepos to submodules or main GIT repo.

I would like to do development separately in the plugins GIT repos, but still keep as subfolders, also still show up as a link in main GIT repo. I use GIT Extensions as development version control GUI.

回答1:

Change to the main directory, checkout the master branch, and do the following Git command to create a new submodule for plugin1:

git submodule add (url_to_plugin1_repository) subdirectory1/plugin1sm

Here the "url_to_plugin1_repository" points to your current Git repository for plugin1. A new directory will be created call subdirectory1/plugin1sm, which will track your remote repository. I have given it a different name to distinguish it from the plugin1 directory which is not a submodule. Take note that Git will be cloning the data for the plugin1sm directory from the remote url, rather than just copying from your local. That being said, if you have any uncommited changes in your local plugin1 repository, you should commit and push them before doing the above step.

At this point, doing a git status from the main directory should show something similar to the following:

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

Since you are in the main directory, the new submodule shows up as a "file" in the changeset. You can commit this change with the following commands:

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

The next question which will probably come to your mind is how do you go about using the new submodule along with your main Git repository. Let's start by looking into what happens when you work on files inside the plugin1sm directory. When you work inside the plugin1sm directory, Git will track changes and behave as if it doesn't know about anything outside of that directory. When the time comes to commit and push your changes, you use the following expected commands:

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

But what about the main repository? Here is where things get a little interesting. Since you modified your plugin1sm submodule, it will show up as a modified "file" in the changeset of the main repository. To continue, you can add the submodule and push it with the following commands:

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

So to summarize, your basic Git workflow within a submodule will be business as usual, and within your main repository, you will need to keep in mind that the entire submodule will appear as a file. Things get more complex than the simple use case we considered here, but hopefully this sets you on the right path.

You can repeat this procedure for the plugin2 and plugin3 directories. And when you have finished creating the submodules, you should be able to delete the original plugin directories.



回答2:

This is the solution which finally seems to work fine for me (under Windows, using Git Extensions as user interface):

The following actions are done in command line:

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


回答3:

My answer has two parts, Conditions, and Solution.

Part I: Conditions

I had the same problem, but I had already a similar repository with the same structure, say

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

and:

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

And I wanted to convert Repo1 and Repo2 to a submodule of Project1 that it is basically the same as Project2. To state clear, cloning Project2 would not do the trick because there were a lot more files in Project1 and Project2 that were not the same, but to keep things simple..

So my Project1's .git/config looked like this

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

And my Project2's .git/config like this:

[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 = ######

and in Project2, there was a file called .gitmodules:

I had the same problem, but I had already a similar repository with the same structure, say

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

and:

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

And I wanted to convert Repo1 and Repo2 to a submodule of Project1 that it is basically the same as Project2. To state clear, cloning Project2 would not do the trick because there were a lot more files in Project1 and Project2 that were not the same, but to keep things simple..

So my Project1's .git/config looked like this:

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

And my Project2's .git/config like this:

[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 = ######

and in Project2, there was a file called .gitmodules:

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

So what to do:

Part II: Solution

  1. Ensure that submodules have the same folder name

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

  1. Then copy Project2/.gitmodules to Project1/

  2. Then copy the content submodule part of Projec2's .git/conif to Project1's .git/config that it basically look like Project2, but not overriding [remote "origin"]:

And my Project1's .git/config like this:

[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 = ######


回答4:

I made an ugly hack to solve my submodule problem in Git Extensions.
Maybe not really valid, but currently works.

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