Rewrite history git filter-branch create / split into submodules / subprojects
git, git-filter-branch, git-submodules, subproject, url-rewriting
Solution
I resolved my own question, here is the solution:
`git-submodule-split library another_library`
Script `git-submodule-split`:
#!/bin/bash
set -eu
if [ $# -eq 0 ]
then
echo "Usage: $0 submodules-to-split"
fi
export _tmp=$(mktemp -d)
export _libs="$@"
for i in $_libs
do
mkdir -p $_tmp/$i
done
git filter-branch --commit-filter '
function gitCommit()
{
git add -A
if [ -n "$(git diff --cached --name-only)" ]
then
git commit -F $_msg
fi
} >/dev/null
# from git-filter-branch
git checkout-index -f -u -a || die "Could not checkout the index"
# files that $commit removed are now still in the working tree;
# remove them, else they would be added again
git clean -d -q -f -x
_git_dir=$GIT_DIR
_git_work_tree=$GIT_WORK_TREE
_git_index_file=$GIT_INDEX_FILE
unset GIT_DIR
unset GIT_WORK_TREE
unset GIT_INDEX_FILE
_msg=$(tempfile)
cat /dev/stdin > $_msg
for i in $_libs
do
if [ -d "$i" ]
then
unset GIT_DIR
unset GIT_WORK_TREE
unset GIT_INDEX_FILE
cd $i
if [ -d ".git" ]
then
gitCommit
else
git init >/dev/null
gitCommit
fi
cd ..
rsync -a -rtu $i/.git/ $_tmp/$i/.git/
export GIT_DIR=$_git_dir
export GIT_WORK_TREE=$_git_work_tree
export GIT_INDEX_FILE=$_git_index_file
git rm -q -r --cached $i
git submodule add ./$i >/dev/null
git add $i
fi
done
rm $_msg
export GIT_DIR=$_git_dir
export GIT_WORK_TREE=$_git_work_tree
export GIT_INDEX_FILE=$_git_index_file
if [ -f ".gitmodules" ]
then
git add .gitmodules
fi
_new_rev=$(git write-tree)
shift
git commit-tree "$_new_rev" "$@";
' --tag-name-filter cat -- --all
for i in $_libs
do
if [ -d "$_tmp/$i/.git" ]
then
rsync -a -i -rtu $_tmp/$i/.git/ $i/.git/
cd $i
git reset --hard
cd ..
fi
done
rm -r $_tmp
git for-each-ref refs/original --format="%(refname)" | while read i; do git update-ref -d $i; done
git reflog expire --expire=now --all
git gc --aggressive --prune=now
Problem
I am currently importing a cvs project into git. After importing, i want to rewrite the history to move an existing directory into a seperate submodule. Suppose i have a structure like this: ` file1 file2 file3 dir1 dir2 library ` Now i want to rewrite the history so that the directory `library` is always a git submodule. Say, split out specified directories into their own submodules / subprojects This is my currently code: File rewrite-submodule (which is called) ``` cd project git filter-branch --tree-filter $PWD/../$0-tree-filter --tag-name-filter cat -- --all ``` File rewrite-submodule-tree-filter ``` #!/bin/bash function gitCommit() { unset GIT_DIR unset GIT_WORK_TREE git add -A if [ -n "$(git diff --cached --name-only)" ] then # something to commit git commit -F $_msg fi } _git_dir=$GIT_DIR _git_work_tree=$GIT_WORK_TREE unset GIT_DIR unset GIT_WORK_TREE _dir=$PWD if [ -d "library" ] then _msg=$(tempfile) git log ${GIT_COMMIT}^! --format="%B" > $_msg git rm -r --cached lib cd library if [ -d ".git" ] then gitCommit else git init gitCommit fi cd .. export GIT_DIR=$_git_dir export GIT_WORK_TREE=$_git_work_tree git submodule add -f ./lib fi GIT_DIR=$_git_dir GIT_WORK_TREE=$_git_work_tree ``` This code creates the .gitmodules file, but not the submodule commit entry (the line `Subproject commit <sha1-hash>`, output by `git diff`) in the main repository and the files in directory `library` are still versioned in the main repository and not in the subproject repository. Thanks in advance for any hint The .gitmodules look like this: ``` [submodule "library"] path = library url = ./library ```