git filter-branch:使用--index-filter移动文件夹不起作用

时间:2017-02-20 22:50:33

标签: git git-filter-branch

假设我要重写Git历史记录,将所有过去提交的/foo/bar的所有内容移至/baz/quux;在Windows上运行。

我在/foo/bar中进行了两次提交的样本回购,仅此而已:

git clone https://github.com/jakub-g/filter-branch-test

让我们把一个文件夹下面的脚本从我的Git repo中放到一个文件夹中并运行它(类似的东西在很多地方提到SO,包括https://stackoverflow.com/a/13590229)。

#!/bin/bash
PATH_TO_GIT_REPO='./filter-branch-test'
REWRITE_FROM='foo/bar/'
REWRITE_TO='baz/quux/'

cd ${PATH_TO_GIT_REPO} &&
git filter-branch -f --index-filter \
 'git ls-files -s | sed "s-\t${REWRITE_FROM}-\t${REWRITE_TO}-" \
  | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info \
  && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' &&
cd -

当我运行它时:

bash ./runFilterBranch.sh

输出结果为:

...
WARNING: Ref 'refs/heads/master' is unchanged

什么都没发生,我还有旧路。

当我在master中运行git ls-files -s | sed "s-\t${REWRITE_FROM}-\t${REWRITE_TO}-"时,我发现sed正确地执行了替换。

我在这里缺少什么?

2 个答案:

答案 0 :(得分:5)

顺便说一句,有一种更简单的方法:

git filter-branch --index-filter "
        git read-tree --prefix='$REWRITE_TO'/ \$GIT_COMMIT:'$REWRITE_FROM'
        git rm -r --cached '$REWRITE_FROM'
"

答案 1 :(得分:0)

正如@torek所提到的,问题是一个基本问题,变量扩展不在单引号内发生。

只是为了记录,这里是我如何更新我的脚本以便可重用并且能够从外部传递变量(变量扩展和转义是棘手的)

事实上,我为2个不同的用例创建了两个bash函数,第二个对于某些场景来说更快。

PATH_TO_GIT_REPO='test-folder'
REWRITE_FROM='foo/bar/'
REWRITE_TO='baz/quux/'

# Rewrite just one folder and keep all the other folder intact.
# Note this will rewrite ALL the commits in the git repo's history
# so it will be slow for big repos.
rewriteFolder(){
    SED_COMMAND='s-\t\"*'${REWRITE_FROM}'-\t'${REWRITE_TO}'-'

    cd ${PATH_TO_GIT_REPO} &&
    git branch -f FILTER_BRANCH_BACKUP &&
    git filter-branch -f --index-filter \
     "git ls-files -s | sed \"$SED_COMMAND\" |
      GIT_INDEX_FILE=\$GIT_INDEX_FILE.new git update-index --index-info &&
      mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" HEAD
}

# Rewrite just one folder and isolate it (remove all the other folders).
# If you have a big number of commits, and only some of them touch ${REWRITE_FROM},
# this will rewrite only this small subset of commits, and discard all the other commits,
# hence it will be much faster than `rewriteFolder`.
isolateAndRewriteFolder(){
    SED_COMMAND='s-\t\"*-\t'${REWRITE_TO}'-'

    cd ${PATH_TO_GIT_REPO} &&
    git branch -f FILTER_BRANCH_BACKUP &&
    echo 'Step 1/2...' &&
    git filter-branch -f --prune-empty --subdirectory-filter ${REWRITE_FROM} &&
    echo 'Step 2/2...' &&
    git filter-branch -f --index-filter \
     "git ls-files -s | sed \"$SED_COMMAND\" |
      GIT_INDEX_FILE=\$GIT_INDEX_FILE.new git update-index --index-info &&
      mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" HEAD    
}