从 .gitmodules 恢复 git 子模块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11258737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 14:02:47  来源:igfitidea点击:

Restore git submodules from .gitmodules

gitgit-submodules

提问by evgeniuz

I have a folder, which was a git repo. It contains some files and .gitmodules file. Now, when I do git initand then git submodule init, the latter command output is nothing. How can I help git to see submodules, defined in .gitmodules file without running git submodule addby hand again?

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

Update: this is my .gitmodules file:

更新:这是我的 .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

and here is listing of this dir:

这是这个目录的列表:

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

so, definitely, it is in top level. the git directory is not changed, only git initis done

所以,当然,它是顶级的。git 目录没有改变,只是git init完成了

回答by Mark Longair

git submodule initonly considers submodules that already are in the index (i.e. "staged") for initialization. I would write a short script that parses .gitmodules, and for each urland pathpair runs:

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

git submodule add <url> <path>

For example, you could use the following script:

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

#!/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

This is based on how the git-submodule.shscriptitself parses the .gitmodulesfile.

这是基于git-submodule.sh脚本本身解析.gitmodules文件的方式。

回答by Kevin C.

Expanding on @Mark Longair's answer, I wrote a bash script to automate steps 2 & 3 of the following process:

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

  1. Clone a 'boilerplate' repo to begin a new project
  2. Remove the .git folder and re-initialize as a new repo
  3. Re-initialize the submodules, prompting for input before deleting folders
  1. 克隆“样板”存储库以开始新项目
  2. 删除 .git 文件夹并重新初始化为新的存储库
  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

Note: the submodules will be checked out at the tip of their master branch instead of the same commit as the boilerplate repo, so you'll need to do that manually.

注意:子模块将在其 master 分支的尖端被检出,而不是与样板 repo 相同的提交,因此您需要手动执行此操作。

Piping the output from git config into the read loop was causing problems with the prompt for input, so it outputs it to a temp file instead. Any improvements on my first bash script would be very welcome :)

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



Big thanks to Mark, https://stackoverflow.com/a/226724/193494, bash: nested interactive read within a loop that's also using read, and tnettenba @ chat.freenode.net for helping me arrive at this solution!

非常感谢 Mark, https://stackoverflow.com/a/226724/193494, bash: 循环中嵌套的交互式读取也使用 read和 tnettenba @ chat.freenode.net 帮助我找到这个解决方案!

回答by mauron85

Extending excellent @Mark Longair's answer to add submodule respecting branch and repo name.

扩展优秀的@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//')
        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

回答by Henry

I had a similar issue. git submodule initwas failing silently.

我有一个类似的问题。git submodule init默默地失败了。

When I did:

当我这样做时:

git submodule add <url> <path>

git submodule add <url> <path>

I got:

我有:

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

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

I'm thinking that .gitignore(d) paths might be the cause.

我认为 .gitignore(d) 路径可能是原因。

回答by alexgirao

I know its been a while, but I want to share this version that calls git configonly once, doesn't requires a script and also handles branches:

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

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});
}
'

The only side effect is the output of the commands, nothing gets executed, so you can audit before committing to them.

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

This works with a simple copy and paste at the console, but should be trivial to put in a shell script.

这适用于在控制台上进行简单的复制和粘贴,但放入 shell 脚本应该是微不足道的。

example output:

示例输出:

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

回答by bokov

An updated version of the script by @mark-longair . This one also supports branches, handles the case where some of the submodules already exist in .git/config, and when necessary backs up existing directories of the same name as the submodule paths.

@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)';