7

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

我只是这样做了git add .,但是当具有嵌套 Git 存储库的子目录未注册为父存储库的子模块时,这给我带来了一个奇怪的情况。

所以:如何在初始“git add”之后继续。在父工作目录中,有子目录具有独立签出的嵌套 git repos(为了获得正确的子模块)?

一个例子:

[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/subgit repo super-existing-sub

我跑进去后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'
$ 

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


我试图按照答案中建议的方式进行(由维克多和我组成),即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'
$ 
4

3 回答 3

7

基于 Victor Johnson 的回答,这里有一个 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/config包含包含url =. 请注意,它假定第一次出现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看看你刚刚做了什么。

于 2016-10-12T02:00:59.457 回答
3

(我一直习惯于git submodule init让 git 识别它们,然后git submodule update将子模块实际克隆到工作目录中。但这不是被询问的情况。)

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

注意:子模块的路径必须是绝对路径,所以你应该在路径前加上 ./

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

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

在实践中还没有尝试过,但是 git-submodule 的手册页说:

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

于 2015-02-09T15:33:04.023 回答
2

见 TL;最后的 DR。

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

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

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

这个想法是,首先,查找原始 URL,./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'
$ 

不幸的是,它坏了。

好吧,让我们想想我们如何解决“已经存在于索引中”而不是我们想要的东西的问题......

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

$ 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;博士

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

这甚至可以制作一个简单的脚本来自动执行将现有嵌套存储库作为子模块添加到父级的任务,但我看不出增加东西的意义。在这个级别,只需学习基本的 Git 命令,并使用和组合它们!

于 2015-02-24T21:05:09.557 回答