Как `git submodule add` Существующий суб-репозиторий?

Вопрос

Как добавить существующий суб-репозиторий как субмодуль в git?

Почему

У меня есть личное codespace супермодуль с подмодулями, разбросанными случайным образом:

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

Иногда субмодули имеют коммиты, не готовые к тому, чтобы их подталкивали Но я хочу, чтобы они были сохранены при нажатии на супермодуль codespace,
codespace репозиторий, клонированный в рабочую область c9.io или другие места

Что я делаю

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 .

Из 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

Из 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

Ссылка

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.

Если <path> существует и уже является допустимым Git-репозиторием, затем он добавляется в набор изменений без клонирования.

Почему это не работает в моем случае?

8 ответов

Где вы ошиблись, так это

$ git add .

Это добавляет все, поэтому также foo/bar, в индекс текущего репозитория (готов к фиксации таким образом).

Если вы просто не сделаете этого и продолжите

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

тогда это должно сработать; это обнаружит, что foo/bar является уже клонированным репозиторием, и добавит его в текущий репозиторий как подмодуль.

Обратите внимание, что сначала клонировать не нужно. Вы прямо говорите, что уже сделали это, но для ясности другим читателям я хотел бы указать, что если вы опустите клон прямо передgit add . тоже (так что сейчас вообще нет foo/bar), то указанное выше git submoduleadd ... увидит, что еще ничего нет, а затем просто клонирует это для вас.

Обратите внимание, что между методами есть небольшая разница. Если вы начнете с клонирования, тогдаfoo/.git будет каталогом, а если вы используете git submoduleadd сделать клонирование тогда это .git репозиторий помещен в .git/modules/foo родительского проекта и foo/.git- это файл, содержащий путь к нему. Однако нет реальной разницы, поскольку использование файла для.gitуказывать где-нибудь еще является общим и может использоваться где угодно; вы не можете сделать вывод из.git являясь файлом или каталогом.

Один из способов сделать это вручную создать .gitmodule файл

Формат ниже

[submodule "path/to/submodule1"]
    path = path/to/submodule/1
    url = git@github.com:user/submodule1
[submodule "path/to/submodule2"]
    path = path/to/submodule/2
    url = git@github.com:user/submodule2

git submodule add обнаруживает, существует ли путь, указанный для субмосулы, и содержит ли он инициализированный репозиторий git, поэтому не нужно беспокоиться об этом. Я столкнулся с подобной проблемой, поэтому я написал (хакерский) скрипт для решения этой проблемы.

#!/bin/bash
# save super directory
currentDir=`pwd`
# get all the git repos inside (except .) and format them 
# the way git does
gitDirs=`find -type d -name ".git" | sed -e 's|.git$||' -e 's|./||' -e 's|/$||' | grep -v "^$"`

for i in ${gitDirs[@]}
do
        echo "dealing with $i now"

        cd $i 
        # get the remote url for each submodule
        fetchUrl=`git remote -v | awk '/fetch/ {print $2}'`
        # for my purposes repos without remotes are useless
        # but you may have a different use case
        if [[ -z $fetchUrl ]]
        then
                echo "fetch url not found for this directory"
                continue
        else                                                      
                echo "got a fetch url of $fetchUrl for git repo $i"                                                                 
        fi                                                        

        cd $currentDir
        # make sure it isn't tracked as a submodule already                                                         
        existing=`grep -A5  $i ./.gitmodules | grep $fetchUrl`    

        if [[ -z $existing ]]                                     
        then                                                      
                echo "does not exist in .gitmodules yet, will create now"
                # if it doesn't exist yet then create it
                git submodule add $fetchUrl $i
        else
                echo "$i is already present as a submodule with fetch url: $fetchUrl"
                echo "The command we would have used is: git submodule add $fetchUrl $i"
        fi
done

Не добавляйте подмодуль, используя git add, использовать git submodule add.

Если вы уже клонировали репозиторий, просто запустите

      git submodule add ./sub/

NB: предыдущий ./subили нужен абсолютный путь

Чтобы дополнить ответ Карлоса для существующего репо. Он уже содержит свой URL. Вы можете просто

       git submodule add $(cat repodir/.git/config  | grep url | cut -d '=' -f 2) reponame
  1. удалить файлы из индекса foo/bar: git rm -f --cached foo/bar
  2. git submodule add https://github.com/octocat/Spoon-Knife.git ./foo/bar

По крайней мере, если (будущие) подмодули не имеют рекурсивных других каталогов repositories/.git, то следующее просто добавляет их все. (Я не уверен, почему мне пришлось указать каталог как путь и «репозиторий» для команды, но что угодно...)

      for d in $(dirname $(find -mindepth 2 -name .git)) ; do git submodule add -- ./$d/ ./$d/ ; done

Вам не нужно сначала клонировать вручную. После запуска git submodule add [url] [path] бежать git submodule update, который будет клонировать / тянуть все подмодули для вас.

Другие вопросы по тегам