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


当前回答

如果您是此回购协议的唯一用户,或者您不关心其他用户是否可能破坏回购协议,那么可以。如果你已经推送了这些提交,并且它们存在于其他地方可以访问它们,那么就不会,除非你不在乎破坏他人的转发。问题是通过更改这些提交,您将生成新的SHA,这将导致它们被视为不同的提交。当其他人试图加入这些更改的提交时,历史是不同的,令人兴奋。

本页http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.html描述了如何做到这一点。(我还没有尝试过,所以YMMV)

其他回答

我应该指出,如果唯一的问题是作者/电子邮件与您平时的不同,这不是问题。正确的修复方法是在目录底部创建一个名为.mailmap的文件,行如下

Name you want <email you want> Name you don't want <email you don't want>

从那时起,像git shortlog这样的命令会认为这两个名称是相同的(除非你明确告诉他们不要这样做)。看见https://schacon.github.io/git/git-shortlog.html了解更多信息。

这与这里所有其他解决方案的优势在于,您不必重写历史,如果您有上游,这可能会导致问题,并且总是意外丢失数据的好方法。

当然,如果你以自己的身份提交了某件事,而它真的应该是其他人,而此时你不介意改写历史,出于归因的目的,更改提交作者可能是一个好主意(在这种情况下,我会在这里告诉你我的另一个答案)。

这个答案使用gitfilter分支,文档现在给出了这个警告:gitfilter分支有太多的缺陷,可能会对预期的历史重写造成不明显的影响(而且由于它的性能非常糟糕,因此几乎没有时间调查这些问题)。这些安全和性能问题不能向后兼容地解决,因此不建议使用。请使用其他历史筛选工具,如git filter repo。如果您仍然需要使用git过滤器分支,请仔细阅读安全(和性能)以了解过滤器分支的地雷,然后尽可能小心地避免列出的危险。

更改作者(或提交人)需要重写所有历史。如果您对此感到满意,并认为这是值得的,那么您应该查看gitfilter分支。手册页面包括几个示例,可帮助您入门。还要注意,您可以使用环境变量来更改作者、提交人、日期等的名称——请参阅git手册页面的“环境变量”部分。

具体来说,您可以使用以下命令修复所有分支和标记的所有错误作者名称和电子邮件(来源:GitHub帮助):

#!/bin/sh

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" ]
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
' --tag-name-filter cat -- --branches --tags

对于使用替代历史过滤工具gitfilter repo,您可以首先安装它并根据gitmailmap的格式构造gitmailmap。

Proper Name <proper@email.xx> Commit Name <commit@email.xx>

然后使用创建的mailmap运行过滤器repo:

git filter-repo --mailmap git-mailmap

我们今天遇到了一个问题,作者名中的UTF8字符在构建服务器上造成了麻烦,因此我们必须重写历史记录来纠正这个问题。所采取的步骤包括:

步骤1:按照此处的说明,更改所有未来提交的git用户名:https://help.github.com/articles/setting-your-username-in-git/

步骤2:运行以下bash脚本:

#!/bin/sh

REPO_URL=ssh://path/to/your.git
REPO_DIR=rewrite.tmp

# Clone the repository
git clone ${REPO_URL} ${REPO_DIR}

# Change to the cloned repository
cd ${REPO_DIR}

# Checkout all the remote branches as local tracking branches
git branch --list -r origin/* | cut -c10- | xargs -n1 git checkout

# Rewrite the history, use a system that will preseve the eol (or lack of in commit messages) - preferably Linux not OSX
git filter-branch --env-filter '
OLD_EMAIL="me@something.com"
CORRECT_NAME="New Me"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
fi
' --tag-name-filter cat -- --branches --tags

# Force push the rewritten branches + tags to the remote
git push -f

# Remove all knowledge that we did something
rm -rf ${REPO_DIR}

# Tell your colleagues to `git pull --rebase` on all their local remote tracking branches

快速概述:将存储库签出到临时文件,签出所有远程分支,运行将重写历史记录的脚本,强制推送新状态,并告诉所有同事重新启动数据库以获取更改。

我们在OS X上运行它时遇到了问题,因为它在提交消息中以某种方式打乱了行结尾,所以我们不得不在Linux机器上重新运行它。

如果您是该存储库的唯一用户,则可以使用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时可能会遇到一些粗糙的角落:它是新的,但尚未经过很好的测试。

如果您要修复的提交是最新的,并且只有几个,您可以使用git reset和git stash的组合,在配置正确的名称和电子邮件后再次提交。

顺序如下(对于2个错误的提交,没有挂起的更改):

git config user.name <good name>
git config user.email <good email>
git reset HEAD^
git stash
git reset HEAD^
git commit -a
git stash pop
git commit -a