I found 使用 Git,子树合并具有子模块的外部项目的最佳方法是什么? https://stackoverflow.com/questions/645019/using-git-whats-the-best-way-to-subtree-merge-an-external-project-that-has-subm但虽然相关,但它并没有回答我的问题。
假设我有我的父项目和子项目,其中包含子模块。如何将子项目子树合并到父项目的子目录中并保持对子模块的引用有效?
我尝试过类似的事情:
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/ http://help.github.com/subtree-merge/使用子模块,但无济于事。
我知道我可以通过手动修改 .gitmodules 文件以引用正确的路径,或者在没有子模块的情况下合并到子项目中,然后将它们重新添加到父项目中来实现此目的,但我认为这两种解决方案都是黑客。我正在寻找可以运行的实际命令,以使其自动工作,而无需手动编辑任何内容。
您可以更改 .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
我确信有一种更好的方法可以做到这一点,但它给出了要做什么的想法
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)