2011-03-24 104 views
2

我发现Using Git, what's the best way to subtree merge an external project that has submodules?但虽然相关,它不回答我的问题。Git命令自动子树合并项目与子模块?

假设我有我的父项目和我的子项目,它包含子模块。如何将子项目子树合并到父项目的子目录中并保持对子模块的引用工作?

我已经试过了诸如:

git remote add -f child_remote git://github.com/me/child.git 
git checkout -b child_branch child_remote/master 
git submodule init 
git submodule update 
git checkout master 
git read-tree --prefix=child_directory/ -u child_branch 

但读树失去的子模块,并.gitmodules只出现在子目录中。当我尝试执行git子模块init和git子模块更新时,出现如下错误:“路径'child_directory/submodule_directory'中找不到在.gitmodules中找到的子模块映射”。

我也试着修改http://help.github.com/subtree-merge/上的说明以使用子模块,但无济于事。

我知道我可以通过手动修改.gitmodules文件来引用正确的路径,或者在没有子模块的情况下合并Child项目,然后将它们重新添加到Parent项目中,但我认为这两者解决方案是黑客。我正在寻找人们会运行的实际命令来自动运行,而无需手动编辑任何内容。

+0

子树合并的使用几乎让你越界“自动执行”。只需编辑路径。 – 2011-03-25 06:13:46

回答

0

您可以更改.gitmodules中的路径,然后执行git submodule init && git submodule update,也可以将子模块转换为子树。最后一个选项涉及某种脚本,因为没有自动执行此操作的方法。

当使用shell脚本,你可以使用这些函数来获得子模块和他们的名字(从混帐子模块源):

# This lists the unmerged submodules 
module_list() 
{ 
    git ls-files --error-unmatch --stage -- "[email protected]" | 
    perl -e ' 
    my %unmerged =(); 
    my ($null_sha1) = ("0" x 40); 
    while (<STDIN>) { 
     chomp; 
     my ($mode, $sha1, $stage, $path) = 
      /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/; 
     next unless $mode eq "160000"; 
     if ($stage ne "0") { 
      if (!$unmerged{$path}++) { 
       print "$mode $null_sha1 U\t$path\n"; 
      } 
      next; 
     } 
     print "$_\n"; 
    } 
    ' 
} 

# This gets the submodule's name from the .gitignore file in your webroot 
module_name() 
{ 
    # Do we have "submodule.<something>.path = $1" defined in .gitmodules file? 
    re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g') 
    name=$(git config -f $2/.gitmodules --get-regexp '^submodule\..*\.path$' | 
     sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p') 
    test -z "$name" && 
    die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")" 
    echo "$name" 
} 

然后,当你重复的结果,可以提取名称和url用于子树。

module_list | while read mode sha1 stage path 
do 
    #the path as your repo sees it 
    full_path=$path 

    #The path as .gitmodules in your child_directory sees it 
    fake_path=${path[*]/[child_directory]\//} 

    #Get the name of the submodule 
    stupid_name=$(module_name "$fake_path" "[child_directory]") 

    #Get the git URL from the .gitmodules file 
    git_url=$(git config -f [child_directory]/.gitmodules submodule."$stupid_name".url) 

    #Gets the clean name to use as remote name 
    new_remote=$(echo $git_url | cut -d. -f2 | cut -d/ -f2- | cut -d/ -f2) 

    #Remove the submodules folder 
    rm -rf $path 

    #Add the subtree 
    git remote add -f $new_remote $git_url 
    git merge -s ours --no-commit $new_remote/master 
    git read-tree --prefix=$full_path/ -u $new_remote/master 
    git commit -m "$new_remote merged in $full_path" 
done 

我敢肯定有一个更好的方式这样做的方式,但它给人的是什么做

0

为什么不能在项目中使用子模块的想法?您现在可以全面使用'git submodule update --recursive`。

此外还有git-slave可以帮助您跨子模块自动化分支。