如何将现有的嵌套repo(已在子目录中检出)添加到父Git仓库作为子模块?

时间:2015-02-09 14:59:58

标签: git git-submodules git-add git-init

如果我从我的工作(父)目录创建初始提交会发生什么,但是有子库有独立签出的git repos?

我只是做了git add .但是当带有嵌套Git repos的子目录没有被注册为父仓库的子模块时,这让我陷入了一种奇怪的境地。

所以:如何在最初的“git add”之后继续。在一个父工作目录中,哪里有子库与独立检出的嵌套git回购(为了获得正确的子模块)?

一个例子:

[imz@z super-existing-sub]$ ls 
c  sub
[imz@z super-existing-sub]$ ls -a sub/
.  ..  a  .git
[imz@z super-existing-sub]$ 

因此,super-existing-sub/sub内已存在预先存在的super-existing-sub git repo。

我跑进super-existing-sub后:

$ git init
$ git add .

如何正确注册预先存在的Git仓库作为子模块?

现在,Git以某种方式跟踪了它:

$ git status 
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   c
    new file:   sub

$ 

但是git submodule有一些问题:

$ git submodule status 
No submodule mapping found in .gitmodules for path 'sub'
$ 

如何将其转换为正确的子模块?


我试着按照答案中提出的方式(由Victor和我组成)进行,即git submodule add URL subdir,但不幸的是,这打破了:

$ git submodule status
No submodule mapping found in .gitmodules for path 'wp-content/themes/liquorice'
$ git submodule add git@github.com:/nudgeme/Liquorice.git ./wp-content/themes/liquorice
'wp-content/themes/liquorice' already exists in the index
/sshx:kosmoplus:/home/kosmoplus/kosmoplus.ru.old $ git submodule status
No submodule mapping found in .gitmodules for path 'wp-content/themes/liquorice'
$ 

3 个答案:

答案 0 :(得分:3)

(我总是使用git submodule init让git识别它们,然后git submodule update将子模块实际克隆到工作目录中。但这不是被问到的情况。)< / p>

要从父目录创建新的git仓库,您需要在父目录上运行git init,然后git submodule add ./path/to/submodule/

注意:子模块的路径必须是绝对路径,因此您应该在路径前加上./

或者,如果您想要一个好的外部URL作为子模块的URL,您应该首先在./path/to/submodule/.git/config中查找原始URL,然后您应该能够

git submodule add URL ./path/to/submodule/

在实践中还没有尝试过,但是git-submodule的联机帮助页说:

  

如果<path>确实存在并且已经是有效的Git存储库,则会将其添加到变更集而不进行克隆。提供第二个表单是为了便于从头开始创建一个新的子模块,并假设用户稍后将子模块推送到给定的URL。

答案 1 :(得分:3)

在维克多·约翰逊的回答的基础上,这里有一个bash oneliner,可以同时添加一整个子模块。

find . -name config | grep git/config | grep -v ProjectToExclude | grep -v AnotherProjectToExclude | xargs -n 1 -I % sh -c 'cat % | grep -m 1 url | sed "s/url = //g"; echo % | sed "s/.git\/config//g";' | xargs -n 2 echo git submodule add

详细说明

假设您有一个包含许多git repos的文件夹,并且您希望父repo将它们全部作为子模块:

path/to/one_repo
path/to/one_repo/.git/config
path/to/another_repo
path/to/another_repo/.git/config
(etc.)

你想为每一个都运行git submodule add ./path/to/submodule/

<强> 1。此oneliner为每个可能的子模块打印该命令。以干运行方式运行它以查看哪些文件夹包含.git/configurl =文件。请注意,它假定第一次出现的url是远程的 - 确保您理智地检查结果。

oneliner再次解释说:

find . -name config |                            # find all config files
    grep git/config |                            # include only those that have "git/config" in their path
    grep -v ProjectToExclude |                   # exclude config files with ProjectToExclude in their path
    grep -v AnotherProjectToExclude |            # ditto
    xargs -n 1 -I % sh -c '                      # one line at a time, execute the following commands, substituting the path for `%`
        cat % |                                  # print the config file contents
            grep -m 1 url |                      # take the first line that contains `url`
            sed "s/url = //g";                   # remove the "url = " part
        echo % |                                 # print the path to the config file
            sed "s/.git\/config//g";             # remove '.git/config' to keep only the project path
    ' |                                          # summary: print the remote url on every 2nd line; the path on every 2nd line 
    xargs -n 2 echo git submodule add            # take two lines at a time, print them with the command

请注意,您可以向管道添加任意数量的grep -v ProjectToExclude以排除这些文件夹 - 再次运行oneliner以查看要执行的新命令列表,并注意ProjectToExclude不再存在

这将打印出来:

git submodule add https://github.com/username/one_repo.git path/to/one_repo
git submodule add git@otherdomain.com:another_repo.git path/to/another_repo
(etc.)

<强> 2。然后,执行它以实现:删除命令末尾的echo,以便最后一部分从

更改
xargs -n 2 echo git submodule add

xargs -n 2 git submodule add

(而不是回显命令,我们实际上将执行它。)

第3。将其添加到git。您现在可以运行git status来查看您刚刚完成的工作。

答案 2 :(得分:1)

参见TL;最后的DR。

让我们仔细阅读git submodule <URL> <path>的手册页,并注意以下说法:

  

如果<path>确实存在并且已经是有效的Git存储库,则会将其添加到变更集而不进行克隆。提供第二个表单是为了便于从头开始创建一个新的子模块,并假设用户稍后将子模块推送到给定的URL。

让我们尝试在像我们这样的情况下使用它(在将父目录递归地添加到新的父存储库之后,而已经存在嵌套的Git存储库)。

首先,想法是在./path/to/submodule/.git/config中查找原始网址,以获得有关子模块的元信息的真实外部URL,然后调用git submodule <URL> <path>(希望如此)根据人工页面做我们想要的。

试试吧:

$ git submodule status
No submodule mapping found in .gitmodules for path 'wp-content/themes/liquorice'
$ git submodule add git@github.com:/nudgeme/Liquorice.git ./wp-content/themes/liquorice
'wp-content/themes/liquorice' already exists in the index
/sshx:kosmoplus:/home/kosmoplus/kosmoplus.ru.old $ git submodule status
No submodule mapping found in .gitmodules for path 'wp-content/themes/liquorice'
$ 

不幸的是,它破了。

好吧,让我们思考如何解决索引中已经存在的问题&#34;并不是我们想要的......

...我们可以简单地从索引中删除它!这很成功:

$ git submodule status
No submodule mapping found in .gitmodules for path 'wp-content/themes/liquorice'
$ git rm --cached ./wp-content/themes/liquorice
rm 'wp-content/themes/liquorice'
$ git submodule add git@github.com:/nudgeme/Liquorice.git ./wp-content/themes/liquorice
Adding existing repo at 'wp-content/themes/liquorice' to the index
$ git submodule status
 9733c0ab3e4207352e3f51d612f2a1c9c4a0b63a wp-content/themes/liquorice (liquorice2.1-1-g9733c0a)
$ 

TL; DR

  • 在subdir中查找原始网址;
  • git rm --cached subdir
  • git submodule add URL subdir

这甚至可以成为一个简单的脚本来自动执行将现有嵌套repo作为子模块添加到父级中的任务,但我没有看到增加事物的重点。在这个级别,只需学习基本的Git命令,并使用和组合它们!