2

我想创建一个 git 脚本,在指定的提交范围(abcd..dcba)中将作者“A”替换为作者“B”。我怎样才能做到这一点?这是我到目前为止所拥有的:

#!/bin/sh
#
# git-myCommand
#
#
git filter-branch --commit-filter '
    if  [ git rev-list --boundary 02e60c8..dc4c65f ]; then
        if [ "$GIT_AUTHOR_NAME" = "A" ];then
            GIT_AUTHOR_NAME="B";
        fi;
    fi;
git commit-tree "$@"'

问题是git说

Rewrite $SHA1-Number git commit-tree: line 48: [: too many arguments

git rev-list --boundary 命令在 if 语句中是否合法?如果我删除 if [git rev-list ... ] 语句,它将起作用。

理想的情况是我可以添加输入变量。所以命令看起来像

git myCommand $AuthorExpression $AuthorReplace $CommitA..$CommitB

编辑:有些人认为这个问题已经被问过了。对于那些请再次阅读上面的问题并将其与之前提出的问题进行比较。AFAIK 这个问题(测试提交是否在提交 A 和提交 B 之间)尚未被询问。如果我错了,很抱歉浪费你的时间。感谢那些试图回答这个问题的人!

4

3 回答 3

3

如果要为脚本使用参数,只需执行

#!/bin/sh
#
# git-myCommand
#
#
AuthorExpression=$1
AuthorReplace=$2
CommitA=$3
CommitB=$4
git filter-branch --commit-filter "
    if git rev-list --boundary '$CommitA'..'$CommitB'; then
        if [ \"\$GIT_AUTHOR_NAME\" = '$AuthorExpression' ];then
            GIT_AUTHOR_NAME='$AuthorReplace';
        fi;
    fi;
git commit-tree \"\$@\""

但是,请注意,您可能还想编辑GIT_COMMITTER_NAMEGIT_COMMITTER_EMAIL以及GIT_AUTHOR_EMAIL。看到这个答案

于 2013-10-07T13:53:54.230 回答
2

您可以将 shell 脚本中的变量替换为您传入的脚本git filter-branch。您只需要注意正确引用即可。由于是单引号,所以不能直接替换变量,但是可以结束单引号,打开一个双引号字符串进行替换,然后关闭双引号字符串,重新打开单引号字符串;字符串将在扩展后附加。在单引号字符串中,您应该在变量的扩展字符串周围加上引号,以防它包含空格或其他字符。

与其试图限制过滤器脚本中的修订,不如只将修订传递给它,git filter-branch以便它只会对那些提交做任何事情。采用与命令末尾git filter-branch相同的参数(尽管您必须用 a 分隔它们才能将其解释为参数)。git rev-list----boundaryrev-list

#!/bin/sh
#
# git-myCommand
#
#
AuthorExpression=$1
AuthorReplace=$2
CommitA=$3
CommitB=$4
git filter-branch --commit-filter '
    if [ "$GIT_AUTHOR_NAME" = "'"$AuthorExpression"'" ];then
        GIT_AUTHOR_NAME="'"$AuthorReplace"'";
    fi;
git commit-tree "$@"' -- --boundary "$CommitA".."$CommitB"

编辑git rev-list:第一次回答时错过了问题。

于 2013-10-07T13:57:18.260 回答
2

其他人已经解决了参数引用问题。剩下的大问题是测试:

if [ git-rev-list ... ]

提交过滤器只是一个 shell 脚本片段,所以它告诉 shell 运行命令:

[ git-rev-list ... ]

并测试该命令的退出状态是零(真)还是非(假)。该[命令也称为test,没有任何git内置命令。

您似乎想要的是判断被过滤的原始提交是否是A..B范围的成员。让我们首先从 filter-branch 文档中注意到这一点:

过滤器按下列顺序应用。<command> 参数始终在 shell 上下文中使用 eval 命令进行评估(由于技术原因,提交过滤器除外)。在此之前,$GIT_COMMIT环境变量将被设置为包含被重写的提交的 id。

因此,您可以编写如下内容:

A=$(git rev-parse $3) || exit 1
B=$(git rev-parse $4) || exit 1
git filter-branch --commit-filter "
    if git merge-base --is-ancestor \$GIT_COMMIT $B &&
       ! git merge-base --is-ancestor \$GIT_COMMIT $A^; then

第一个merge-base测试是否$GIT_COMMIT是更高转速的祖先(在拓扑上等于$B或“在”它之前)。第二个排除了较低 rev ( $A) 之前的提交,使用帽子后缀来避免排除$A自身。

这是使用这种技术的Brian Campbell 脚本的一个变体(好吧,我也更改了引用扩展技术)。

#! /bin/sh
case $# in
4) ;;
*) echo "usage: $0 oldauthor newauthor firstrev lastrev" >&2; exit 1;;
esac

AuthorExpression=$1
AuthorReplace=$2
A=$(git rev-parse --verify $3^{commit}) || exit 1
B=$(git rev-parse --verify $4^{commit}) || exit 1

git filter-branch --commit-filter "
    if git merge-base --is-ancestor \$GIT_COMMIT $B &&
       ! git merge-base --is-ancestor \$GIT_COMMIT $A^; then
       if [ \"\$GIT_AUTHOR_NAME\" = '$AuthorExpression' ]; then
       GIT_AUTHOR_NAME='$AuthorReplace'
       fi
    fi
git commit-tree \"\$@\""
于 2013-10-07T16:27:25.863 回答