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 ```

Original source

Related problems