如何使用--commit-filter在一个git filter-branch pass中排除20提交?

时间:2016-11-28 16:56:18

标签: git bash git-filter-branch

我需要从裸存储库中的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完成它的工作时,我如何获得将旧哈希映射到新哈希的日志文件?

3 个答案:

答案 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)脚本;
  • filter-branch脚本使用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)

要尝试的三件事 - 我自己没有遇到这种情况,所以没有测试过任何一种情况。

  1. 子字符串应为${GIT_COMMIT:0:7}而不是${GIT_COMMIT0:7}(变量名后的冒号)

  2. 使用--tag-name-filter cat -- --all代替HEADman page给出了相关的示例:

      

    删除由" Darl McBribe撰写的提交"来自历史:

    git filter-branch --commit-filter '
           if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
           then
                   skip_commit "$@";
           else
                   git commit-tree "$@";
           fi' HEAD
    
                 ^^^^
    

    请注意,在该示例中指定HEAD足以清理存储库。

  3. 使用bash测试代替test(1)(应该更快,更强大):

    if [[ ${GIT_COMMIT0:7} = e687d59  ||  ${GIT_COMMIT0:7} = 58daf29 || ... ]]; then