How can I convert a git submodule (with a folder in the local file system as a remote) to a git subtree, preferably preserving the commit history of the submodule?
Alexander Mikhailian's script modified by @GaspardP did not work for me.
I modified it, and made an improvement. Now, the new subtrees will point to the same commit as the old submodules did. Previously, the script would simply download the latest commit from the target repositories, potentially causing compatibility issues.
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"