假设我要重写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正确地执行了替换。
我在这里缺少什么?
答案 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
}