【问题标题】:git edit authors name in commit range, scriptgit 编辑提交范围内的作者姓名,脚本
【发布时间】:2013-10-14 02:54:53
【问题描述】:

我想创建一个 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 之间)尚未被询问。如果我错了,很抱歉浪费你的时间。感谢那些试图回答这个问题的人!

【问题讨论】:

  • 我不认为if [ git rev-list ... ] 是对的。你期望它做什么?也许应该是if [ $(git rev-list ...) ] 或者只是if git rev-list ......
  • @twalberg 哦。只需删除git rev-list 行中的括号即可。
  • 仅删除括号无济于事:git rev-list 如果具有有效参数,则退出零(成功),无论正在重写什么 rev。
  • 抱歉,第一次回答时错过了git rev-list 的问题。更新了我的答案以解决该问题。您不想在提交过滤器中进行rev-list 测试;只需直接在git filter-branch 命令中限制您要重写的版本即可。
  • 这不是重复的。这个问题只是问如何重写作者;这个问题询问如何将这种重写应用于有限的提交范围。请大家不要在不考虑假设的重复项是否实际上在问完全相同的问题的情况下投票关闭。

标签: git bash shell


【解决方案1】:

如果你想为脚本使用参数,只需这样做

#!/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_EMAILGIT_AUTHOR_EMAIL。见this answer

【讨论】:

  • 我稍微编辑了这个问题。我仍然收到错误消息:'Rewrite $SHA1-Number git commit-tree: line 48: [: too many arguments'
【解决方案2】:

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

与其试图限制过滤器脚本中的修订,不如将修订传递给git filter-branch,这样它就只会对这些提交做任何事情。 git filter-branch 在命令末尾采用与 git rev-list 相同的参数(尽管您必须用 -- 将它们分隔,以便将 --boundary 解释为 rev-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 的问题。

【讨论】:

  • 事实证明,git filter-branch 不允许您按 ID 指定提交(我在写答案之前尝试过,我认为同样的事情会起作用)。
【解决方案3】:

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

if [ git-rev-list ... ]

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

[ git-rev-list ... ]

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

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

过滤器的应用顺序如下所示。 始终使用 eval 在 shell 上下文中评估参数 命令(除了提交过滤器的显着例外,用于技术 原因)。在此之前,$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 或在拓扑上位于“之前”)。第二个排除了较低版本 ($A) 之前的提交,使用帽子后缀来避免排除 $A 本身。

这是使用这种技术的Brian Campbell's script 的变体(好吧,我也更改了引号扩展技术)。

#! /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 \"\$@\""

【讨论】:

  • 就是这样!感谢您的解决方案和解释!
  • 顺便说一句,使用--env-filter 可能更有效(但那个是eval-ed 所以可能也需要一些语法调整)。
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 2018-05-27
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多