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


当前回答

我们今天遇到了一个问题,作者名中的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机器上重新运行它。

其他回答

我改编了这个解决方案,它通过摄取一个简单的author conv文件(格式与git cvsimport相同)来工作。它通过在所有分支中更改author conv文件中定义的所有用户来工作。

我们将其与cvs2git结合使用,将存储库从cvs迁移到git。

即示例作者conv文件

john=John Doe <john.doe@hotmail.com>
jill=Jill Doe <jill.doe@hotmail.com>

脚本:

 #!/bin/bash

 export $authors_file=author-conv-file

 git filter-branch -f --env-filter '

 get_name () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=\(.*\) <.*>$/\1/"
 }

 get_email () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=.* <\(.*\)>$/\1/"
 }

 GIT_AUTHOR_NAME=$(get_name $GIT_COMMITTER_NAME) &&
     GIT_AUTHOR_EMAIL=$(get_email $GIT_COMMITTER_NAME) &&
     GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME &&
     GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL &&
     export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
     export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
 ' -- --all

这是@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,这意味着只过滤当前分支上的所有修订。然后,重写的分支中不存在标记(或其他引用)。

git rebase -i YOUR_FIRTS_COMMIT_SHA^

while true; do git commit --amend --author="Name Surname <email@example.com>" --no-edit && git rebase --continue; done

在重基完成后按^C#(循环将继续更新上次提交)

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

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

如果只有前几次提交的作者不好,您可以使用exec命令和--modify commit在git rebase-i内部执行此操作,如下所示:

git rebase -i HEAD~6 # as required

它为您提供了可编辑的提交列表:

pick abcd Someone else's commit
pick defg my bad commit 1
pick 1234 my bad commit 2

然后添加exec--author=“…”在所有作者不好的行之后:

pick abcd Someone else's commit
pick defg my bad commit 1
exec git commit --amend --author="New Author Name <email@address.example>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <email@address.example>" -C HEAD

保存并退出编辑器(运行)。

这个解决方案可能比其他解决方案键入的时间更长,但它是高度可控的——我确切地知道它命中了什么提交。

感谢@asmeurer的灵感。