如何更改一系列提交的作者?


当前回答

GitHub最初有一个很好的解决方案(断开链接),它是以下shell脚本:

#!/bin/sh

git filter-branch --env-filter '

an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "your@email.to.match.example" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "your@email.to.match.example" ]
then
    an="Your New Author Name"
    am="Your New Author Email"
fi

export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'

其他回答

运行git-rebase-i<sha1或起点的ref>使用edit(或e)标记要更改的所有提交循环执行以下两个命令,直到处理完所有提交:gitcommit--modify--reuse message=HEAD--author=“新作者<new@author.email>";git rebase—继续

这将保留所有其他提交信息(包括日期)。--reuse message=HEAD选项阻止消息编辑器启动。

通过Amend更改提交作者姓名和电子邮件,然后用新提交替换旧提交:$git checkout<commit hash>#签出到需要修改的提交$gitcommit--modify--author“name”<author@email.com>“#更改作者姓名和电子邮件$git replace<旧提交哈希><新提交哈希>#用新提交替换旧提交$gitfilter分支--all#基于替换重写所有未来提交$git replace-d<old commit hash>#删除干净替换$git push-f origin HEAD#force push另一种方式回扣:$git rebase-i<good commit hash>#返回上一次提交#编辑器将打开,在提交更改作者之前将“pick”替换为“edit”$gitcommit--modify--author=“作者名称<author@email.com>“#更改作者姓名和电子邮件#保存更改并退出编辑器$git rebase--continue#完成rebase

对于单个提交:

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

(摘自阿斯梅勒的回答)

如果您是该存储库的唯一用户,则可以使用gitfilter分支(如svick所写)、git快速导出/git快速导入加上过滤脚本(如docgnome answer中引用的文章所述)或交互式rebase重写历史。但其中任何一项都会从最初更改的承诺开始更改修订;这对任何基于分支预重写的更改的人来说都意味着麻烦。

回收,回收

若其他开发人员的工作并没有基于预重写版本,最简单的解决方案就是重新克隆(再次克隆)。

或者,他们可以尝试gitrebase--pull,如果他们的存储库中没有任何更改,这将加快速度,或者在重新编写的提交之上重新设置分支的基础(我们希望避免合并,因为这将永远保留预重写的commit)。所有这一切都假设他们没有未经许可的工作;否则,使用gitstash来隐藏更改。

如果其他开发人员使用功能分支,和/或git pull--rebase不起作用,例如,因为上游未设置,他们必须在重写后提交的基础上重新启动工作。例如,在获取新的更改(gitfetch)之后,对于基于/fforked-from origin/master的主分支,需要运行

$ git rebase --onto origin/master origin/master@{1} master

这里origin/master@{1}是预重写状态(在获取之前),请参阅gitrevisions。


另一种解决方案是使用refs/replace/mechanism,从1.6.5版开始,Git中就提供了这种机制。在该解决方案中,您可以替换电子邮件错误的提交;那么,任何获取“replace”ref的人(比如fetch=+refs/replace/*:refs/replace/*refspec位于其.git/config中的适当位置)都将透明地获取替换,而那些不获取这些ref的人将看到旧的提交。

程序大致如下:

查找包含错误电子邮件的所有提交,例如使用$git日志--作者=user@wrong.email--全部对于每个错误的提交,创建一个替换提交,并将其添加到对象数据库$git cat文件-p<错误提交的ID>|sed-e的/user@wrong\.电子邮件/user@example.com/g'>tmp.txt$git哈希对象-t提交-w tmp.txt<已更正提交的ID>既然您已经纠正了对象数据库中的提交,您必须告诉git使用git replace命令自动透明地用纠正的提交替换错误的提交:$git替换<错误提交的ID><更正提交的ID最后,列出所有替代品,以检查此过程是否成功$git替换-l并检查是否进行了更换$git日志--作者=user@wrong.email--全部

您当然可以自动执行此过程。。。好吧,除了使用gitreplace,它还没有批处理模式,所以您必须使用shell循环,或者手动替换。

未测试!YMMV。

请注意,在使用refs/replace/mechanism时可能会遇到一些粗糙的角落:它是新的,但尚未经过很好的测试。

这是@Brian版本的更详细版本:

要更改作者和提交人,可以执行以下操作(在bash中可以使用换行符):

git filter-branch --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

您可能会遇到以下错误之一:

临时目录已存在以Refs/original开头的引用已存在(这意味着先前在存储库上运行了另一个过滤器分支,然后在refs/original处备份原始分支引用)

如果要在出现这些错误的情况下强制运行,请添加--force标志:

git filter-branch --force --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

可能需要对--all选项做一点解释:它使过滤器分支可以处理所有引用(包括所有分支)的所有修订。例如,这意味着标记也被重写,并且在重写的分支上可见。

一个常见的“错误”是使用HEAD,这意味着只过滤当前分支上的所有修订。然后,重写的分支中不存在标记(或其他引用)。