如何将一个 git 子模块(其远程是本地文件系统中的一个文件夹)转换为 git 子树,最好能保留子模块的提交历史记录?
如何将一个 git 子模块(其远程是本地文件系统中的一个文件夹)转换为 git 子树,最好能保留子模块的提交历史记录?
subtree add
而不是read-tree
。它将从.gitmodule
中获取子模块列表,并提取模块的前缀、名称和url。然后删除每个子模块,并将它们重新添加为子树到相同的位置。它还将每个子模块的远程添加为远程,因此您可以稍后通过提供其名称而不是URL来更新子树(例如:git subtree pull -P Foo Foo master --squash
,而不是git subtree pull -P Foo https://example.com/foo.git master --squash
)。--squash
参数。使用--squash
,将只将子树的头导入到存储库中。这可能是大多数人想要的。#!/bin/bash -x
# extract the list of submodules from .gitmodule
cat .gitmodules |while read i
do
if [[ $i == \[submodule* ]]; then
echo converting $i
# extract the module's prefix
mpath=$(echo $i | cut -d\" -f2)
# skip two lines
read i; read i;
# extract the url of the submodule
murl=$(echo $i|cut -d\= -f2|xargs)
# extract the module name
mname=$(basename $mpath)
# deinit the module
git submodule deinit $mpath
# remove the module from git
git rm -r --cached $mpath
# remove the module from the filesystem
rm -rf $mpath
# commit the change
git commit -m "Removed $mpath submodule"
# add the remote
git remote add -f $mname $murl
# add the subtree
git subtree add --prefix $mpath $mname master --squash
# fetch the files
git fetch $murl master
fi
done
git rm .gitmodules
亚历山大·米哈伊利安的脚本由@GaspardP修改后并不能满足我的需求。
我进行了修改并作出了改进。现在,新的子模块将指向与旧的子模块相同的提交。之前,该脚本只是从目标仓库中下载最新的提交,可能会导致兼容性问题。
https://gist.github.com/Nikita240/0c98cea8f53a15e69699cd8bc40657c4
#!/bin/bash -x
# This script will convert all your git submodules into git subtrees.
# This script ensures that your new subtrees point to the same commits as the
# old submodules did, unlike most other scripts that do this.
# THIS SCRIPT MUST BE PLACED OUTSIDE OF YOUR REPOSITORY!!!!!!!!!!
# Otherwise, the script will interfere with the git commits.
# Save the script in your home directory as `~/subtrees.sh`
# `cd` into your repository
# Run `~/subtrees.sh`
# Enjoy!
# extract the list of submodules from .gitmodule
cat .gitmodules |while read i
do
if [[ $i == \[submodule* ]]; then
echo converting $i
read i
# extract the module's prefix
mpath=$(echo $i | grep -E "(\S+)$" -o)
echo path: $mpath
read i
# extract the url of the submodule
murl=$(echo $i|cut -d\= -f2|xargs)
echo url: $murl
# extract the module name
mname=$(basename $mpath)
echo name: $mname
# extract the referenced commit
mcommit=$(git submodule status $mpath | grep -E "\S+" -o | head -1)
echo commit: $mcommit
# deinit the module
git submodule deinit $mpath
# remove the module from git
git rm -r --cached $mpath
# remove the module from the filesystem
rm -rf $mpath
# commit the change
git commit -m "Removed $mpath submodule at commit $mcommit"
# add the remote
git remote add -f $mname $murl
# add the subtree
git subtree add --prefix $mpath $mcommit --squash
# commit any left over uncommited changes
git commit -a -m "$mname cleaned up"
# fetch the files
git fetch $murl master
echo
fi
done
git rm .gitmodules
git commit -a -m "Removed .gitmodules"
git submodule status
返回的提交名称前面有一个连字符(-
)。我不得不在该行末尾添加 cut -d"-" -f2
来将其切掉。 - Jason Rkeybase://
远程更改为本地远程后才有效。不太可能其他人会遇到这个问题。 - Nathan Musoke
#!/bin/bash -x
作为shebang,而不是回显所有命令。 - Bjoern Dahlgren