从.gitmodules还原git子模块

Restore git submodules from .gitmodules

我有一个文件夹,是Git回购。它包含一些文件和.gitmodules文件。现在,当我执行git initgit submodule init时,后者的命令输出是零。如何帮助Git查看在.gitmodules文件中定义的子模块,而不需要再次手动运行git submodule add

更新:这是我的.gitmodules文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[submodule"vim-pathogen"]
    path = vim-pathogen
    url = git://github.com/tpope/vim-pathogen.git
[submodule"bundle/python-mode"]
    path = bundle/python-mode
    url = git://github.com/klen/python-mode.git
[submodule"bundle/vim-fugitive"]
    path = bundle/vim-fugitive
    url = git://github.com/tpope/vim-fugitive.git
[submodule"bundle/ctrlp.vim"]
    path = bundle/ctrlp.vim
    url = git://github.com/kien/ctrlp.vim.git
[submodule"bundle/vim-tomorrow-theme"]
    path = bundle/vim-tomorrow-theme
    url = git://github.com/chriskempson/vim-tomorrow-theme.git

下面是这个目录的列表:

1
2
3
4
5
6
drwxr-xr-x  4 evgeniuz 100 4096 июня  29 12:06 .
drwx------ 60 evgeniuz 100 4096 июня  29 11:43 ..
drwxr-xr-x  2 evgeniuz 100 4096 июня  29 10:03 autoload
drwxr-xr-x  7 evgeniuz 100 4096 июня  29 12:13 .git
-rw-r--r--  1 evgeniuz 100  542 июня  29 11:45 .gitmodules
-rw-r--r--  1 evgeniuz 100  243 июня  29 11:18 .vimrc

所以,当然,这是在顶级水平。Git目录没有更改,只完成git init


git submodule init只考虑索引中已经存在的用于初始化的子模块(即"分阶段")。我会写一个简短的脚本来解析.gitmodules,对于每个urlpath对运行:

1
git submodule add <url> <path>

例如,可以使用以下脚本:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

set -e

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/')
        url=$(git config -f .gitmodules --get"$url_key")
        git submodule add $url $path
    done

这是基于git-submodule.sh脚本本身如何解析.gitmodules文件。


在@mark longair的答案基础上,我编写了一个bash脚本来自动执行以下过程的步骤2和3:

  • 克隆"样板"报告以开始新项目
  • 删除.git文件夹并重新初始化为新的repo
  • 重新初始化子模块,删除文件夹前提示输入
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #!/bin/bash

    set -e
    rm -rf .git
    git init

    git config -f .gitmodules --get-regexp '^submodule\..*\.path$' > tempfile

    while read -u 3 path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/')
        url=$(git config -f .gitmodules --get"$url_key")

        read -p"Are you sure you want to delete $path and re-initialize as a new submodule?" yn
        case $yn in
            [Yy]* ) rm -rf $path; git submodule add $url $path; echo"$path has been initialized";;
            [Nn]* ) exit;;
            * ) echo"Please answer yes or no.";;
        esac

    done 3<tempfile

    rm tempfile

    注意:子模块将在其主分支的顶部签出,而不是与样板文件repo相同的提交,因此您需要手动执行该操作。

    通过管道将输出从git config传输到read循环会导致输入提示出现问题,因此它将输出到临时文件。我的第一个bash脚本的任何改进都将非常受欢迎:)

    感谢Mark,https://stackoverflow.com/a/226724/193494,bash:嵌套的交互式读取循环中也使用了read,[email protected]帮助我找到这个解决方案!


    扩展优秀@mark longair的答案,添加有关分支和回购名称的子模块。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/bin/sh

    set -e

    git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
        while read path_key path
        do
            name=$(echo $path_key | sed 's/\submodule\.\(.*\)\.path/\1/')
            url_key=$(echo $path_key | sed 's/\.path/.url/')
            branch_key=$(echo $path_key | sed 's/\.path/.branch/')
            url=$(git config -f .gitmodules --get"$url_key")
            branch=$(git config -f .gitmodules --get"$branch_key" || echo"master")
            git submodule add -b $branch --name $name $url $path || continue
        done

    我也有类似的问题。git submodule init正在悄无声息地失败。

    当我这样做的时候:

    git submodule add

    我得到:

    The following path is ignored by one of your .gitignore files: ...

    我在想,GitIgnore(d)路径可能是原因。


    我知道已经有一段时间了,但是我想分享这个版本,它只调用一次git config,不需要脚本,也可以处理分支:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    git config -f .gitmodules --get-regexp '^submodule\.' | perl -lane'
    $conf{$F[0]} = $F[1]}{
    @mods = map {s,\.path$,,; $_} grep {/\.path$/} keys(%conf);
    sub expand{$i = shift; map {$conf{$i . $_}} qw(.path .url .branch)}
    for $i (@mods){
        ($path, $url, $branch) = expand($i);
        print(qq{rm -rf $path});
        print(qq{git submodule add -b $branch $url $path});
    }
    '

    唯一的副作用是命令的输出,不会执行任何操作,因此您可以在提交之前进行审计。

    这可以在控制台上使用简单的复制和粘贴,但是放入shell脚本应该很简单。

    实例输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    rm -rf third-party/dht
    git submodule add -b post-0.25-transmission https://github.com/transmission/dht third-party/dht
    rm -rf third-party/libutp
    git submodule add -b post-3.3-transmission https://github.com/transmission/libutp third-party/libutp
    rm -rf third-party/libb64
    git submodule add -b post-1.2.1-transmission https://github.com/transmission/libb64 third-party/libb64
    rm -rf third-party/libnatpmp
    git submodule add -b post-20151025-transmission https://github.com/transmission/libnatpmp third-party/libnatpmp
    rm -rf third-party/miniupnpc
    git submodule add -b post-2.0.20170509-transmission https://github.com/transmission/miniupnpc third-party/miniupnpc
    rm -rf third-party/libevent
    git submodule add -b post-2.0.22-transmission https://github.com/transmission/libevent third-party/libevent