How to replay Git repository history into subdirectory?

First, rewrite bee's history to move all files into the subdirectory:

cd /path/to/bee
git filter-branch --force --prune-empty --tree-filter '
dir="my fancy/target directory"
if [ ! -e "${dir}" ]
then
    mkdir --parents "${dir}"
    git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files "${dir}"
fi'

git log --stat should show every file appearing under my fancy/target directory. Now you can merge the history into aye with ease:

cd /path/to/aye
git remote add -f bee /path/to/bee
git checkout -b bee-master bee/master
git rebase master
git checkout master
git rebase bee-master

Recreate the submodule in aye:

git submodule add git://my-submodule 'my fancy/target directory/my-submodule'

Finally you can clean up aye:

git rm 'my fancy/target directory/.gitmodules'
git branch --delete --force bee-master
git remote remove bee

You may also have to fix any absolute paths in your repository (for example in .gitignore)


Much faster version (hat tip to this answer):

git filter-branch --index-filter 'git ls-files -s | sed "s-\t\"*-&newsubdir/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'

Replace newsubdir with any directory or nested directory you like. On macOS, you may have to use gsed instead of sed (install with brew install gnu-sed).

Tags:

Git