重写历史 git filter-branch 创建/拆分为子模块/子项目

Mar*_*inF 5 git url-rewriting subproject git-submodules git-filter-branch

我目前正在将 cvs 项目导入 git。
导入后,我想重写历史记录以将现有目录移动到单独的子模块中。

假设我有这样的结构:

file1
file2
file3
dir1
dir2
library

现在我想重写历史记录,以便该目录library始终是 git 子模块。比如说,将指定的目录拆分为它们自己的子模块/子项目

这是我当前的代码:

文件重写子模块(被调用)

cd project
git filter-branch --tree-filter $PWD/../$0-tree-filter --tag-name-filter cat -- --all
Run Code Online (Sandbox Code Playgroud)

文件重写子模块树过滤器

    #!/bin/bash

    函数 gitCommit()
    {
        取消设置 GIT_DIR
        取消设置 GIT_WORK_TREE
        git添加-A
        if [ -n "$(git diff --cached --name-only)" ]
        然后
            # 需要提交的东西
            git 提交 -F $_msg
        菲
    }

    _git_dir=$GIT_DIR
    _git_work_tree=$GIT_WORK_TREE
    取消设置 GIT_DIR
    取消设置 GIT_WORK_TREE
    _dir=$PWD

    如果[-d“库”]
    然后
        _msg=$(临时文件)
        git 日志 ${GIT_COMMIT}^! --format="%B" > $_msg
        git rm -r --缓存库
        光盘库
        如果[-d“.git”]
        然后
            git提交
        别的
            git初始化
            git提交
        菲
        光盘 ..
        导出 GIT_DIR=$_git_dir
        导出 GIT_WORK_TREE=$_git_work_tree
        git 子模块添加 -f ./lib
    菲

    GIT_DIR=$_git_dir
    GIT_WORK_TREE=$_git_work_tree
    

此代码创建 .gitmodules 文件,但不是主存储库中的子模块提交条目(行Subproject commit <sha1-hash>,由 输出git diff),并且目录中的文件library仍然在主存储库中进行版本控制,而不是在子项目存储库中进行版本控制。

预先感谢您的任何提示

.gitmodules 看起来像这样:

    [子模块“库”]
        路径=库
        网址=./库
    

Mar*_*inF 2

我解决了我自己的问题,这是解决方案:

git-submodule-split library another_library

脚本git-submodule-split

    #!/bin/bash

    设置-eu

    如果 [ $# -eq 0 ]
    然后
        echo "用法: $0 要分割的子模块"
    菲

    导出_tmp=$(mktemp -d)
    导出_libs =“$@”
    对于 $_libs 中的 i
    做
        mkdir -p $_tmp/$i
    完毕

    git 过滤器分支 --commit-filter '
    函数 gitCommit()
    {
        git添加-A
        if [ -n "$(git diff --cached --name-only)" ]
        然后
            git 提交 -F $_msg
        菲
    } >/dev/null

    # 来自 git-filter-branch
    git checkout-index -f -u -a || git checkout-index -f -u -a || die“无法签出索引”
    # $commit 删除的文件现在仍在工作树中;
    # 删除它们,否则它们会再次添加
    git clean -d -q -f -x

    _git_dir=$GIT_DIR
    _git_work_tree=$GIT_WORK_TREE
    _git_index_file=$GIT_INDEX_FILE
    取消设置 GIT_DIR
    取消设置 GIT_WORK_TREE
    取消设置 GIT_INDEX_FILE

    _msg=$(临时文件)
    猫 /dev/stdin > $_msg
    对于 $_libs 中的 i
    做
        如果[-d“$i”]
        然后
            取消设置 GIT_DIR
            取消设置 GIT_WORK_TREE
            取消设置 GIT_INDEX_FILE
            cd $i
            如果[-d“.git”]
            然后
                git提交
            别的
                git 初始化 >/dev/null
                git提交
            菲
            光盘 ..
            rsync -a -rtu $i/.git/ $_tmp/$i/.git/
            导出 GIT_DIR=$_git_dir
            导出 GIT_WORK_TREE=$_git_work_tree
            导出 GIT_INDEX_FILE=$_git_index_file
            git rm -q -r --cached $i
            git 子模块添加 ./$i >/dev/null
            git 添加 $i
        菲
    完毕
    rm$_msg
    导出 GIT_DIR=$_git_dir
    导出 GIT_WORK_TREE=$_git_work_tree
    导出 GIT_INDEX_FILE=$_git_index_file

    如果[-f“.gitmodules”]
    然后
        git 添加 .gitmodules
    菲

    _new_rev=$(git 写树)
    转移
    git 提交树“$_new_rev”“$@”;
    ' --标签名称-过滤猫 -- --all

    对于 $_libs 中的 i
    做
        如果[-d“$_tmp/$i/.git”]
        然后
            rsync -a -i -rtu $_tmp/$i/.git/ $i/.git/
            cd $i
            git重置——硬
            光盘 ..
        菲
    完毕
    rm -r $_tmp

    git for-each-ref refs/original --format="%(refname)" | git for-each-ref refs/original --format="%(refname)" | 当读我时;执行 git update-ref -d $i; 完毕

    git reflog expire --expire=now --all
    git gc --aggressive --prune=now