我找到了Using Git, what's the best way to subtree merge an external project that has submodules?但是虽然相关,却没有回答我的问题。
假设我有我的父项目和我的子项目,其中包含子模块。如何将子项目子树合并到父项目的子目录中,并保持对子模块的引用有效?
我尝试过这样的事情:
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
但是read-tree丢失了子模块,而.gitmodules只出现在子目录中。当我尝试执行git submodule init和git submodule update时,我得到的错误如“在.gitmodules中没有找到子模块映射'对于路径'child_directory / submodule_directory'”。
我还尝试修改http://help.github.com/subtree-merge/处的说明以使用子模块,但无济于事。
我知道我可以通过手动修改.gitmodules文件来引用正确的路径,或者在没有子模块的Child项目中合并,然后将它们重新添加到Parent项目中来实现这一点,但我考虑这两种解决方案黑客攻击。我正在寻找可以自动运行的实际命令,而无需手动编辑任何内容。
答案 0 :(得分:0)
您可以更改.gitmodules中的路径,然后执行git submodule init && git submodule update
,也可以将子模块转换为子树。最后一个选项涉及某种脚本,因为没有自动的方法来执行此操作。
使用shell脚本时,您可以使用这些函数来获取子模块及其名称(来自git-submodules源代码):
# This lists the unmerged submodules
module_list()
{
git ls-files --error-unmatch --stage -- "$@" |
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
我确信有更好的方法可以做到这一点,但它可以让我知道要做什么
答案 1 :(得分:0)
为什么不在项目中使用子模块?你现在可以全面使用'git submodule update --recursive`。
还有git-slave可以帮助您跨子模块自动化分支。