如何在 Git 中更改多次提交的作者和提交者名称以及电子邮件?

我当时在学校计算机上编写一个简单的脚本,然后将更改提交到 Git(在笔驱动器中的一个存储库中,该存储库是从家里的计算机克隆的)。经过几次提交后,我意识到我正在以 root 用户身份提交东西。

有什么办法可以将这些提交的作者更改为我的名字?

答案

注意:此答案会更改 SHA1,因此请小心在已推送的分支上使用它。如果您只想修正名称的拼写或更新旧电子邮件,则 git 允许您执行此操作而无需使用.mailmap重写历史记录。看到我的其他答案

使用交互式基础

你可以做

git rebase -i -p <some HEAD before all of your bad commits>

然后,将所有错误提交标记为 rebase 文件中的 “edit”。如果您还想更改您的第一次提交,则必须手动将其作为重新提交添加到 rebase 文件的第一行中(遵循其他行的格式)。然后,当 git 要求您修改每次提交时,请执行

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

编辑或仅关闭打开的编辑器,然后执行

git rebase --continue

继续进行基地调整。

您可以通过添加--no-edit来跳过此处完全打开编辑器的操作,这样命令将是:

git commit --amend --author "New Author Name <email@address.com>" --no-edit && \
git rebase --continue

单次提交

正如一些评论者指出的那样,如果您只想更改最近的提交,则不需要 rebase 命令。做就是了

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

这会将作者更改为指定的名称,但是将在git config user.namegit config user.email中将提交者设置为您配置的用户。如果要将提交者设置为指定的内容,则会同时设置作者和提交者:

git -c user.name="New Author Name" -c user.email=email@address.com commit --amend --reset-author

关于合并提交的注意事项

我的原始回复有轻微缺陷。如果当前HEAD和您的<some HEAD before all your bad commits>之间有任何合并提交,然后<some HEAD before all your bad commits> ,那么git rebase将使它们git rebase平(顺便说一句,如果您使用 GitHub pull request,将有大量的合并提交您的历史记录)。这通常会导致非常不同的历史记录(因为重复的更改可能会被 “重新基准化”),并且在最坏的情况下,它可能导致git rebase要求您解决困难的合并冲突(可能已经在合并提交中解决了) )。解决方案是使用-p标志来git rebase ,这将保留历史记录的合并结构。 git rebase的联机帮助页警告说,使用-p-i可能会导致问题,但是在BUGS部分中,它说 “编辑提交并改写其提交消息应该可以正常工作。”

我在上面的命令中添加了-p 。对于仅更改最新提交的情况,这不是问题。

更改作者(或提交者)将需要重写所有历史记录。如果您对此表示满意,并认为值得这样做,则应查看git filter-branch 。手册页包含一些示例,可以帮助您入门。还要注意,您可以使用环境变量来更改作者,提交者,日期等的名称。请参见git 手册页的 “环境变量” 部分。

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

#!/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

您也可以这样做:

git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

注意,如果您在 Windows 命令提示符中使用此命令,则需要使用"代替'

git filter-branch --commit-filter "
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi" HEAD

一个班轮,但是如果您有多用户存储库,请小心 - 这会将所有提交更改为具有相同(新)的作者和提交者。

git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='new@email'; GIT_COMMITTER_NAME='Newname'; GIT_COMMITTER_EMAIL='new@email';" HEAD

在字符串中使用换行符(可以在 bash 中使用):

git filter-branch -f --env-filter "
    GIT_AUTHOR_NAME='Newname'
    GIT_AUTHOR_EMAIL='new@email'
    GIT_COMMITTER_NAME='Newname'
    GIT_COMMITTER_EMAIL='new@email'
  " HEAD

当您没有初始化 $ HOME / .gitconfig 时,就会发生这种情况。您可以将其修复为:

git config --global user.name "you name"
git config --global user.email you@domain.com
git commit --amend --reset-author

用 git 版本 1.7.5.4 测试

对于一次提交:

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

(摘自 asmeurer 的回答)

如果只有少数几个提交具有错误的作者,则可以使用exec命令和--amend提交在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.com>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD

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

此解决方案的键入时间可能比其他解决方案长,但它是高度可控的 - 我确切知道它会击中什么提交。

感谢 @asmeurer 的启发。

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" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "your@email.to.match" ]
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"
'

正如 docgnome 所述,重写历史记录很危险,并且会破坏其他人的存储库。

但是,如果您确实想这样做,并且您处于 bash 环境中(在 Linux 中,在 Windows 上没有问题,则可以使用 git bash,这是 git 安装随附的),请使用git filter-branch

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL'

为了加快速度,您可以指定要重写的修订版本范围:

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL' HEAD~20..HEAD

当接管另一位作者的未合并提交时,有一种简单的方法来处理此问题。

git commit --amend --reset-author