从.gitmodules恢复git子模块

evg*_*iuz 66 git git-submodules

我有一个文件夹,这是一个git repo.它包含一些文件和.gitmodules文件.现在,当我这样做git init,然后git submodule init,后者命令的输出是什么.我如何帮助git查看.gitmodules文件中定义的子模块,而无需git submodule add再次手动运行?

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

[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
Run Code Online (Sandbox Code Playgroud)

这是这个目录的清单:

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
Run Code Online (Sandbox Code Playgroud)

所以,绝对是最高级别的.git目录没有改变,只是git init完成了

Mar*_*air 91

git submodule init只考虑已经在索引中的子模块(即"暂存")进行初始化.我会编写一个解析的短脚本.gitmodules,并为每个urlpath一对运行:

git submodule add <url> <path>
Run Code Online (Sandbox Code Playgroud)

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

#!/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
Run Code Online (Sandbox Code Playgroud)

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

  • 你的意思是`git submodule update --init`?所有这些命令都以静默方式失败。看起来 git 没有看到仅在 `.gitmodules` 中定义的模块 (2认同)

Kev*_* C. 15

扩展@Mark Longair的答案,我编写了一个bash脚本来自动执行以下过程的第2步和第3步:

  1. 克隆'样板'回购以开始一个新项目
  2. 删除.git文件夹并重新初始化为新的repo
  3. 重新初始化子模块,在删除文件夹之前提示输入

#!/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
Run Code Online (Sandbox Code Playgroud)

注意:子模块将在其主分支的顶端检出,而不是与样板回购相同的提交,因此您需要手动执行.

将git config的输出管道输入到读取循环中会导致输入提示出现问题,因此会将其输出到临时文件中.我的第一个bash脚本的任何改进都将非常受欢迎:)


非常感谢马克,/sf/answers/15870711/,bash下一个循环中的嵌套交互读取目前正使用的读取也和tnettenba @ chat.freenode.net帮助我在这个解决办法!


mau*_*n85 7

扩展优秀的@Mark Longair 的答案,以添加尊重分支和回购名称的子模块。

#!/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
Run Code Online (Sandbox Code Playgroud)


bok*_*kov 5

@mark-longair 的脚本更新版本。它还支持分支,处理某些子模块已存在于 中的情况.git/config,并在必要时备份与子模块路径同名的现有目录。

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/');
        branch_key=$(echo $path_key | sed 's/\.path/.branch/');
        # If the url_key doesn't yet exist then backup up the existing
        # directory if necessary and add the submodule
        if [ ! $(git config --get "$url_key") ]; then
            if [ -d "$path" ] && [ ! $(git config --get "$url_key") ]; then
                mv "$path" "$path""_backup_""$(date +'%Y%m%d%H%M%S')";
            fi;
            url=$(git config -f .gitmodules --get "$url_key");
            # If a branch is specified then use that one, otherwise
            # default to master
            branch=$(git config -f .gitmodules --get "$branch_key");
            if [ ! "$branch" ]; then branch="master"; fi;
            git submodule add -f -b "$branch" "$url" "$path";
        fi;
    done;

# In case the submodule exists in .git/config but the url is out of date

git submodule sync;

# Now actually pull all the modules. I used to use this...
#
# git submodule update --init --remote --force --recursive
# ...but the submodules would check out in detached HEAD state and I 
# didn't like that, so now I do this...

git submodule foreach --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)';
Run Code Online (Sandbox Code Playgroud)