【问题标题】:How to change the author name filtered by the commit message?如何更改提交消息过滤的作者姓名?
【发布时间】:2017-05-07 17:19:12
【问题描述】:

设置是这样的。我们对存储库进行了多次推送,提交消息如下所示:

[System] Updated the logs
[System] CSV file updated
etc.

现在我希望将这些提交绑定到特定的 git 帐户,以便我可以将更改与我的提交区分开来。 “系统”一直在提交作者姓名和电子邮件,就像我的一样。

现在我想搜索提交消息,并且对于消息中包含 [System] 的每个提交,我想将名称更新为 System.我该怎么做?

我希望它采用控制台命令的形式(我可以在其中运行命令,无需使用-interactive选项手动更改它)(使用 git 的 bash 或python,不管有什么解决方案)

有一些命令可以提供帮助,例如:

git show :/[System] - 显示匹配字符串的最后一条 git 消息

git-filter-branch

还有其他一些,但我不确定如何以类似脚本(或任何)的形式做到这一点。

【问题讨论】:

标签: git bash github


【解决方案1】:

您可以使用 git commit --amend 将作者更改为提交

在变基时使用

edit

然后使用命令:

git commit --amend --author="Author Name <email@address.com>"

然后使用:

git rebase --continue

你可以在 rebase 中指定提交号来修改特定的提交

【讨论】:

  • 你有指定 git 提交的例子吗?另外,我不关注关于使用edit 的第一条评论。我在哪里使用编辑?
  • 这里是完整的步骤:git rebase origin/master -i. 它会打开一个编辑器,列出你所有的提交。将edit 放置在您要编辑的提交之前,而不是选择。现在变基将停止,然后您输入以下命令来编辑该提交。 git commit --amend --author="Author Name &lt;email@address.com&gt;". 然后执行 git rebase --continue git rebase --continue. 确保您首先尝试在 fork 上进行 rebase,因为 rebase 会重写历史。
  • 感谢您的详细解释,但我想在没有 -i (interactive) 标志的情况下执行此操作。我想知道在这种情况下是否有解决方案。我将编辑问题以进一步指出这一点。
【解决方案2】:

答案与duplicatesajib khan noted 相同,注意事项相同。您只需更改测试。查看那里接受的答案,其中包含以下部分:

git filter-branch --env-filter '
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]

请注意,这第一步测试原始提交的“提交者电子邮件”字符串。您希望测试原始提交的提交消息,可能与原始提交的作者和/或提交者一起。

if <some-test>

棘手的部分是测试本身,因为原始提交的消息不是环境的一部分。

如果你的测试通过了,你想同时改变作者提交者,所以这不太对:

then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi

但您可以简单地删除第二个测试并覆盖作者和提交者:

then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi

最后,命令的最后一位将保持不变,例如:

' --tag-name-filter cat -- --branches --tags

因此,问题归结为&lt;test&gt;。在这里你必须做出一些决定:

  • 您想更改(副本)任何包含文字字符串[System] 的提交吗?或者,您是否只想更改 [System] 开头的提交?

  • 您是否希望在原始提交的作者和/或提交者姓名和/或电子邮件与您自己匹配时更改这些副本?还是您想更改它们而不管原始作者和/或提交者如何?如果作者匹配你的名字但提交者不匹配,或者提交者匹配你的名字但作者不匹配怎么办?

  • 您是想在过滤器中“即时”计算匹配度,还是希望预先计算所有提交哈希 ID,然后将更改应用于这些特定提交?

在考虑您的答案时,请记住 git filter-branch 的运作方式是复制您将其定向到的每个提交--branches 表示“可从分支名称访问的每个提交”) .当它复制每个此类提交时,它会应用您的每个过滤器。有许多; see the git filter-branch documentation for the list.

实际上,过滤器分支代码提取原始提交,通过以适当的顺序应用每个过滤器来进行任何请求的更改,然后从结果中进行新的提交。如果新提交(包括新提交的父哈希 ID)与原始提交逐位相同,则新提交原始提交。但是,只要链中某处的一个提交以任何方式被修改,新的提交就会获得一个新的、不同的哈希 ID。这会强制所有后续提交至少有一件事不同,即它们的父提交哈希,因此一旦发生至少一个更改,更改就会“影响”剩余的提交。

结果是一个新的存储库不再与原始存储库兼容。原始版本的所有克隆都必须被丢弃,并用新存储库的新克隆替换,并使用其新的哈希 ID。

如果您选择用“是”回答第三个问题“您是否愿意预先计算哈希 ID 以进行更改”,这可以让您更加确定您的过滤器会做什么,并且不会触摸任何不需要的提交——如果您需要在之前的更改后再次更改内容,则必须重新计算预先计算的哈希 ID,因为每次进行任何更改时哈希 ID 都会更改。如果您选择“不,我将动态测试”,这将不再是一个问题,但是您的测试代码必须是正确的,否则您将修改您不打算修改的提交的副本。当然,您可以仔细检查新的、修改后的存储库以确保它是正确的。如果不是,不要放弃原件以支持副本,而是放弃副本并通过改进的测试重新开始过滤。

现在让我们考虑&lt;test&gt;。如果您已经准备好所有要更改的提交 ID 的完整列表,则测试将是:“要复制的提交的哈希是否是列表中的哈希之一?”要复制的提交的哈希可用,in all filter-branch filters,为$GIT_COMMIT

过滤器

过滤器的应用顺序如下所示。 始终使用 eval 在 shell 上下文中评估参数 命令(除了提交过滤器的显着例外,用于技术 原因)。在此之前,$GIT_COMMIT 环境变量将是 设置为包含被重写的提交的 id。还, GIT_AUTHOR_NAME,GIT_AUTHOR_EMAIL,GIT_AUTHOR_DATE,GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL 和 GIT_COMMITTER_DATE 取自当前 提交并导出到环境中,以影响作者 和由创建的替换提交的提交者身份 git-commit-tree(1) 过滤器运行后。

因此,如果您要影响的提交 ID 在文件中,每行一个,您可以使用 grep 来查看 $GIT_COMMIT 是否与这些行之一匹配:

if grep $GIT_COMMIT /tmp/list-of-commits

(作为副作用,如果 grep 匹配其中一个提交,则提交的哈希将打印在标准输出上,您将在过滤期间看到)。

如果您希望动态选择提交,那就有点困难了。您必须根据提交的哈希提取提交日志消息。你可以通过git log 做到这一点:

git log --no-walk --pretty=format:%B $GIT_COMMIT

获取整个消息,或者:

git log --no-walk --pretty=format:%s $GIT_COMMIT

只获取主题行。然后,您可以再次通过匹配程序(例如 grep)来确定消息是否包含字符串或以字符串开头。

由于grep 是正则表达式,而方括号是正则表达式字符,您可能想改用fgrep(固定字符串grep)。使用fgrep 意味着无法验证开放方括号是否出现在主题行的开头,但如果您愿意的话。

因此,在日志消息内部或开头检测[System] 的一些方法是:

if git log --no-walk --pretty=format:%B $GIT_COMMIT | fgrep "[System]"

或:

if git log --no-walk --pretty=format:%s $GIT_COMMIT | grep "^\[System]"

请记住,在 sh 和 bash 中,if ... 只是在单词 if 之后运行命令,然后查看其退出状态。退出状态为零表示“是”:测试成功。非零退出状态表示“否”:测试失败。测试:

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]

正在运行 [ 程序,带有参数:

$GIT_COMMITTER_EMAIL     (spaces retained as a single argument)
=
$OLD_EMAIL               (spaces likewise protected by double quote)
]

/bin/[ 程序,也称为/bin/test,查找关闭的] 作为最后一个参数,并将其删除。 (如果以test 调用,它不会寻找关闭的]。)然后它执行其余参数规定的测试。在这种情况下,参数是两个字符串,它们之间有一个=,所以test 测试两个字符串是否相等。

我们只需将测试替换为grep(查看$GIT_COMMIT 是否在提交ID 文件中)或git log ... | grep(查看git log 输出是否包含字符串)。 grep 的退出状态告诉我们是否找到了我们正在寻找的字符串。

如果您使用准备好的提交哈希文件,您可以尝试许多不同的方法来收集您想要更改的提交的哈希 ID,而不会带来很多痛苦,因为您将在一个更熟悉的(并且可能比eval-ed 过滤器git filter-branch 中可用的编程环境更丰富。

另一个警告

这可能应该在另一个问题的答案中注明,但是任何时候您要运行git filter-branch,最好在一个新的、全新的存储库克隆上运行它。这样,您可以仔细检查新提交,看看您的过滤器是否按照您的预期进行。如果没有,您可以扔掉过滤后的克隆并重试,因为您在它上面花费的只是克隆和过滤所需的时间和磁盘空间。

【讨论】:

  • +1 以获得如此详细的答案,它提供了许多有价值的信息。它可能不适合我的所有需求,但肯定会提供一些信息。评论没有那么大,无法评论您答案中的所有地方,但感谢您的回答。最后,我想我最终会创建一个 bash 脚本来操作/编辑提交,而不是使用多个单个命令
猜你喜欢
  • 2021-02-08
  • 2018-11-21
  • 2022-06-10
  • 2018-08-16
  • 2018-05-29
  • 2011-02-13
相关资源
最近更新 更多