Nested git repositories without remotes (a.k.a. git submodule without remotes)
Asked Answered
T

4

52

I have a project of which I am interested in breaking out portions as open-source. I've set up nested git repositories main, one, two and three:

main/
├── one
├── three
└── two

I thought that by going into "main" and doing

git add one
git add two
git add three

(note the lack of trailing slashes), I'd set up submodules with the sub-repositories and be good to go.

However, as noted in How to track untracked content?, this only creates gitlinks and not real submodules.

Unfortunately, that answer doesn't help, as it assumes that there is a "master" repository somewhere else for "main/one", "main/two", and "main/three". I'd like these sub-repo's to be the master repositories. I'm considering fake submodules (as per Git fake submodules), but that's not a particularly ideal situation for cloning.

Any other suggestions out there?

Transcontinental answered 23/5, 2011 at 17:55 Comment(0)
Q
36

You can do what you want, but your one, two, and three would need to be accessible to whoever will need to clone them—this is not usually the case for “random” development repositories.

If you do set this up, you will need to be very careful not to delete “your” repository (or make it otherwise inaccessible) since it is not just “yours”: it will be origin in your collaborator’s clones and it will serve as the “central”/“upstream” repository (as specified in .gitmodules).


If all your collaborators are local (and can read from the repositories), you can add your existing sub-repositories as submodules by giving their local paths as URLs:

git rm --cached one two three
git submodule add `pwd`/one
git submodule add `pwd`/two
git submodule add `pwd`/three

If not all your collaborators will be working on the same machine, then that will probably not work correctly (since it will store a local path in .gitmodules; non-local collaborators would have to adjust the URLs after git submodule init).

If your one, two, and three are remotely Git-accessible, then you can specify their effecive URLs instead:

git rm --cached one two three
git -c protocol.file.allow=always submodule add server:/path/to/your/main/one
git -c protocol.file.allow=always submodule add server:/path/to/your/main/two
git -c protocol.file.allow=always submodule add server:/path/to/your/main/three

In both cases, since you already have a sub-repository in place, git submodule add will use that instead of trying to clone from the specified path/URL.

Queenqueena answered 24/5, 2011 at 6:23 Comment(7)
Hey, that's great! Thank you! I'd tried git submodule add ./one, but got some error (I think complaining about a lack of remote). Your solutions work wonderfully.Transcontinental
Out of curiosity, in the worst case, would collaborators be able to edit .gitmodules and .git/config manually to 'fix' broken links?Transcontinental
All that said, I understand your warning, too. Fortunately, we're a (very) small team, so even if I have to rip out the submodules and replace them with ones with origin at github or the like, it won't be a big deal. Thanks again!Transcontinental
@David: 1) Adding a submodule with a relative path means something special to git submodule add: resolve it as relative to the containing repository’s origin remote. That is why I use pwd to get an absolute path in my example. 2) Yes, your collaborators can always edit .git/config after initializing the submodules. If you establish a widely usable URL for your sub-repositories (or decide to put bare clones in a widely accessible location), then .gitmodules should be updated so future collaborators that clone your main repository will not have to adjust the URLs manually.Queenqueena
TLDR: Not possible without remotes unless all collaborators share a machine.Fable
Note that for more recent versions of git (v2.38.1 for me) when trying to add a local submodule path, the "file" protocol is blocked by default and using the above submodule command will get you an error something to the effect of Cloning into '/tmp/repo1/sub'... fatal: transport 'file' not allowed fatal: clone of '/tmp/repo2' into submodule path '/tmp/repo1/sub' failed. To avoid this, it is necessary to use the -c option to override the protocol.file.allow config property, e.g. git -c protocol.file.allow=always submodule add --name subrepo /tmp/repo2 path-under-parent-repoFenelia
@Fenelia I edited this into the answer. Here is a reference for this change in gitDiscontinuous
G
6

Chris's answer don't assume for a "master" repo (master being the default name of the main branch in Git, not a repo).

It declares submodules in a "parent" repo, which in your case would be "main".

So you need three independent repo "one" "two" and "three" setup elsewhere, and then clone and add them to your "main" repo as submodules:

# first remove the one directory previously added
git rm --cached one
# then declare the external one repo as a submodule in "main" repo)
git submodule add /path/to/one.git one
Gun answered 24/5, 2011 at 4:19 Comment(1)
Yes, that's one way to handle it—but the repos setup elsewhere is precisely what I was trying to avoid, if possible. (I didn't see any reason to have extra repo's lying around.) Thank you for your input, though!Transcontinental
C
1

I just came up with the idea to place the repository of the submodules exactly as a subdirectory of the superproject. That way, the project as a whole is only dependent on the one repository/ location that you set up (based on the answer from Chris).

E.g. Submodule one would have as its main repository the location server:/path/to/your/main/one (via git remote -v in that dir).

That way the submodule functionality (e.g. git submodule update --recursive) is pointed to the right location as well since the URL of that module/repository points to ./one (.gitmodules).

Christinchristina answered 19/3, 2016 at 16:49 Comment(1)
I believe what you're describing is known as a "monorepo".Schedule
N
0

In my case, I needed to specify both the submodule address and the location where it should be cloned, and both were the same:

$ git submodule add ./path/to/submodule path/to/submodule
Adding existing repo at 'path/to/submodule' to the index

More detail on my use case:
I wanted to start tracking an existing folder with git, and this folder already contained repos. I wanted to keep everything local: I am not collaborating with anyone on these repos, and the folders are already otherwise saved in the cloud.

Noranorah answered 3/11, 2023 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.