How to `git submodule add` Existing sub Repository?

ilyaigpetrov picture ilyaigpetrov · Sep 25, 2015 · Viewed 9.4k times · Source

The Question

How to add existing sub repository as a submodule in git?

The Why

I have a private codespace supermodule with submodules scattered randomly:

codespace (git repo, private)
├── Archived_projects (git repos)
└── Projects
    ├── project-foo (git repo)
    └── project-bar (git repo)

Sometimes submodules have commits not ready to be pushed. But I want them to be saved while pushing supermodule codespace.
codespace is a repo cloned to c9.io workspace or other places.

What I Do

linus@machine /cygdrive/f/__Storage__/Workspace
$ git clone https://github.com/octocat/Spoon-Knife.git
Cloning into 'Spoon-Knife'...
$ cd Spoon-Knife/
$ git clone https://github.com/octocat/Spoon-Knife.git ./foo/bar
Cloning into './foo/bar'...
$ git add .

From cmd.exe

> git submodule add https://github.com/octocat/Spoon-Knife.git ./foo/bar
'foo/bar' already exists in the index
> cat .gitmodules
cat: .gitmodules: No such file or directory

From cygwin.exe (bash)

$ git submodule add https://github.com/octocat/Spoon-Knife.git ./foo/bar
': not a valid identifier/Git/mingw64/bin/gettext.sh: line 89: export: `sm_path
'' already exists in the index
$ cat .gitmodules
cat: .gitmodules: No such file or directory

Reference

git submodule [--quiet] add [-b <branch>] [-f|--force] [--name <name>]
              [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]

<repository> is the URL of the new submodule’s origin repository.

<path> is the relative location for the cloned submodule to exist in the superproject. If <path> does not exist, then the
submodule is created by cloning from the named URL. If <path> does exist and is already a valid Git repository, then this is
added to the changeset without cloning. This second form is provided to ease creating a new submodule from scratch, and
presumes the user will later push the submodule to the given URL.

In either case, the given URL is recorded into .gitmodules for use by subsequent users cloning the superproject. If the URL
is given relative to the superproject’s repository, the presumption is the superproject and submodule repositories will be
kept together in the same relative location, and only the superproject’s URL needs to be provided: git-submodule will
correctly locate the submodule using the relative URL in .gitmodules.

If <path> does exist and is already a valid Git repository, then this is added to the changeset without cloning.

Why this doesn't work in my case?

Answer

Carlo Wood picture Carlo Wood · Jan 3, 2020

Where you went wrong is doing the

$ git add .

That adds everything, so also foo/bar, to the index of the current repository (ready to be committed thus).

If you just don't do that and continue with

$ git submodule add https://github.com/CarloWood/XYZ.git foo/bar

then that should work; this would detect that foo/bar is an already cloned repository and add it to the current repository as a submodule.

Note that it is not needed to clone first. You explicitly say you already have done that, but for clarity for other readers I'd like to point out that if you omit the clone right before the git add . too (so there isn't a foo/bar at all now) then the above git submodule add ... would see there isn't anything yet and then simply clone it for you.

Note that there is a minor difference between methods. If you start with cloning then foo/.git will be a directory, while if you use git submodule add to do the cloning then this .git repository is put in .git/modules/foo of the parent project and foo/.git is a file containing the path to that. There is no real difference however as using a file for the .git to point anywhere else is generic and could be used anywhere; you can not conclude anything from .git being a file or directory.