我需要从裸存储库中的git历史记录中连续清理20个提交。 我尝试使用以下命令,(注意,我不想写全长哈希并尝试使用子字符串比较):
git filter-branch -d /dev/shm/scratch --commit-filter '
if [ ${GIT_COMMIT0:7} = e687d59 ] ||
[ ${GIT_COMMIT0:7} = 58daf29 ] ||
...
[ ${GIT_COMMIT0:7} = 682b2c2 ] ||
[ ${GIT_COMMIT0:7} = 947db9e ];
then
skip_commit "$@";
else
git commit-tree "$@";
fi' --tag-name-filter cat -- --all
但我立即收到消息:
重写414840693169a74d052548c7a7a1bc5b06d3b79c(1/10360)(0秒 通过,剩下0预测)git commit-tree:49:git commit-tree:错误的替换无法写入重写提交
OR条件或子字符串都有错误,我无法弄清楚。
我还有一个问题:当git filter-branch
完成它的工作时,我如何获得将旧哈希映射到新哈希的日志文件?
答案 0 :(得分:2)
基本问题是:
if [ ${GIT_COMMIT0:7} = e687d59 ] || [ ${GIT_COMMIT0:7} = 58daf29 ] || ... [ ${GIT_COMMIT0:7} = 682b2c2 ] || [ ${GIT_COMMIT0:7} = 947db9e ];
错了。
子字符串的bash语法为${name:offset:length}
,在这种情况下为${GIT_COMMIT:0:7}
,即您缺少冒号。
可是:
git filter-branch
是一个sh(非bash)脚本; eval
;和前两个意味着你不能在这里依赖特定于bash的语法。
第三种意味着没有真正的理由这样做。
一种选择是使用-o
(又名[
)计划的test
(或)运算符:
if [ $GIT_COMMIT = ... -o
$GIT_COMMIT = ... -o
...
$GIT_COMMIT = ... ]; then
但在我看来,这仍然太痛苦了。相反,为什么不使用grep
,例如:
if echo $GIT_COMMIT | grep -F -f /tmp/list >/dev/null; then
文件/tmp/list
包含您要跳过的ID?如果grep找到其中一个,则以零(成功)状态退出,否则以非零(失败)状态退出,如果测试成功,test
或[
程序退出0的方式相同,如果失败则为非零。
(如果你的grep有-q
,你可以使用它而不是重定向到/dev/null
。)
答案 1 :(得分:2)
我会把它写成
git filter-branch -d /dev/shm/scratch --commit-filter '
case $GIT_COMMIT in
e687d59*|58daf29*|682b2c2*|947db9e*)
skip_commit "$@"
;;
*)
git commit-tree "$@"
;;
esac' --tag-name-filter cat -- --all
它并不比你的陈述好很多(在你指出它之后修复它),但仍然少一点打字。
如果您在重写之前知道了提交,那么添加它可能会有所回报:
... --tag-name-filter cat -- --all --not that_commit
答案 2 :(得分:0)
要尝试的三件事 - 我自己没有遇到这种情况,所以没有测试过任何一种情况。
子字符串应为${GIT_COMMIT:0:7}
而不是${GIT_COMMIT0:7}
(变量名后的冒号)
使用--tag-name-filter cat -- --all
代替HEAD
。 man page给出了相关的示例:
删除由" Darl McBribe撰写的提交"来自历史:
git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then skip_commit "$@"; else git commit-tree "$@"; fi' HEAD
^^^^
请注意,在该示例中指定HEAD
足以清理存储库。
使用bash
测试代替test(1)
(应该更快,更强大):
if [[ ${GIT_COMMIT0:7} = e687d59 || ${GIT_COMMIT0:7} = 58daf29 || ... ]]; then