答案与duplicate 和sajib 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
因此,问题归结为<test>。在这里你必须做出一些决定:
您想更改(副本)任何包含文字字符串[System] 的提交吗?或者,您是否只想更改以 [System] 开头的提交?
您是否希望仅在原始提交的作者和/或提交者姓名和/或电子邮件与您自己匹配时更改这些副本?还是您想更改它们而不管原始作者和/或提交者如何?如果作者匹配你的名字但提交者不匹配,或者提交者匹配你的名字但作者不匹配怎么办?
您是想在过滤器中“即时”计算匹配度,还是希望预先计算所有提交哈希 ID,然后将更改应用于这些特定提交?
在考虑您的答案时,请记住 git filter-branch 的运作方式是复制您将其定向到的每个提交(--branches 表示“可从分支名称访问的每个提交”) .当它复制每个此类提交时,它会应用您的每个过滤器。有许多; see the git filter-branch documentation for the list.
实际上,过滤器分支代码提取原始提交,通过以适当的顺序应用每个过滤器来进行任何请求的更改,然后从结果中进行新的提交。如果新提交(包括新提交的父哈希 ID)与原始提交逐位相同,则新提交是原始提交。但是,只要链中某处的一个提交以任何方式被修改,新的提交就会获得一个新的、不同的哈希 ID。这会强制所有后续提交至少有一件事不同,即它们的父提交哈希,因此一旦发生至少一个更改,更改就会“影响”剩余的提交。
结果是一个新的存储库不再与原始存储库兼容。原始版本的所有克隆都必须被丢弃,并用新存储库的新克隆替换,并使用其新的哈希 ID。
如果您选择用“是”回答第三个问题“您是否愿意预先计算哈希 ID 以进行更改”,这可以让您更加确定您的过滤器会做什么,并且不会触摸任何不需要的提交——如果您需要在之前的更改后再次更改内容,则必须重新计算预先计算的哈希 ID,因为每次进行任何更改时哈希 ID 都会更改。如果您选择“不,我将动态测试”,这将不再是一个问题,但是您的测试代码必须是正确的,否则您将修改您不打算修改的提交的副本。当然,您可以仔细检查新的、修改后的存储库以确保它是正确的。如果不是,不要放弃原件以支持副本,而是放弃副本并通过改进的测试重新开始过滤。
现在让我们考虑<test>。如果您已经准备好所有要更改的提交 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,最好在一个新的、全新的存储库克隆上运行它。这样,您可以仔细检查新提交,看看您的过滤器是否按照您的预期进行。如果没有,您可以扔掉过滤后的克隆并重试,因为您在它上面花费的只是克隆和过滤所需的时间和磁盘空间。