I needed to convert a subdirectory of a repo to a submodule and have the
histories of both repos linked together. I found that this was discussed
few years back [1], but the code seemed quite complicated and was not


Now, the situation is better, because git subtree can already do most of
the work. Below is a script that I used to split a submodule from my
repo. It basically consist of a call to 'git subtree split' followed by
'git filter-branch' to link the histories together.

I'd like to get some initial feedback on it before attempting to
integrate it with git sources (i.e. writing tests and doc). What do you



set -e

. git-sh-setup


test -d "$dir" || die "$dir is not a directory"

# Create subtree corresponding to the directory
subtree=$(git subtree split --prefix="$dir")

git tag $subtree_tag $subtree
export subtree subtree_tag superproject

# Replace the directory with submodule reference in the whole history
git filter-branch -f --index-filter "
    set -e
    # Check whether the $dir exists in this commit
    if git ls-files --error-unmatch '$dir' > /dev/null 2>&1; then

        # Find subtree commit corresponding to the commit in the
        # superproject (this could be made faster by not running git log
        # for every commit)
        subcommit=\$(git log --format='%T %H' $subtree |
            grep ^\$(git ls-tree \$GIT_COMMIT -- '$dir'|awk '{print \$3}') |
            awk '{print \$2}')

        # filter-branch runs the filter in an empty work-tree - create the
        # future submodule in it so that the 'git submodule add' below
        # does not try to clone it.
        if ! test -d '$dir'; then
            mkdir -p '$dir'
            ( cd '$dir' && clear_local_git_env && git init --quiet && git pull 
$superproject $subtree_tag )

        # Remove all files under $dir from index so that the 'git
        # submodule add' below does not complain.
        git ls-files '$dir'|git update-index --force-remove --stdin

        # Add the submodule - the goal here is to create/update .gitmodules
        git submodule add $url '$dir'

        # Update the submodule commit hash to the correct value
        echo \"160000 \$subcommit       $dir\"|git update-index --index-info

# Replace the directory in the working tree with the submodule
( cd "$dir" && find -mindepth 1 -delete && git init && git pull $superproject 
$subtree_tag )

# Clean up
git tag --delete $subtree_tag
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to