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


当前回答

正如docgnome所提到的,重写历史是危险的,会破坏其他人的知识库。

但是,如果您真的想这样做,并且您处于bash环境中(在Linux和Windows中没有问题,您可以使用git bash,这是安装git时提供的),请使用gitfilter分支:

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

其他回答

注意:这个答案会改变SHA1,所以在已经推送的分支上使用它时要小心。如果你只想修复一个名字的拼写或更新一封旧邮件,Git可以让你不用使用.mailmap重写历史。

使用回扣

首先,如果您还没有这样做,您可能需要在git-config中修复您的名称:

git config --global user.name "New Author Name"
git config --global user.email "<email@address.example>"

这是可选的,但它也将确保重置提交者名称,假设这是您所需要的。

要使用rebase重写一系列提交的元数据,请执行

git rebase -r <some commit before all of your bad commits> \
    --exec 'git commit --amend --no-edit --reset-author'

--exec将在每次提交被重写后运行gitcommit步骤(就像您运行gitcommit&&gitrebase一样——重复继续)。

如果您还想更改第一次提交(也称为“root”提交),则必须在rebase调用中添加--root。

这将把提交人和作者都更改为user.name/user.email配置。如果不想更改该配置,可以使用--author“New author Name”<email@address.example>“而不是--reset-author。请注意,这样做不会更新提交者,只更新作者。

单次提交

如果您只想更改最近的提交,则无需重新设置基准。只需修改承诺:

 git commit --amend --no-edit --reset-author

整个项目历史

git rebase -r --root --exec "git commit --amend --no-edit --reset-author"

对于较旧的Git客户端(2020年7月之前)

-r、 --您可能不存在重基合并。作为替换,可以使用-p。请注意,-p存在严重问题,现已弃用。

这是@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 change-commits GIT_AUTHOR_NAME "old name" "new name"

或最近10次提交:

git change-commits GIT_AUTHOR_EMAIL "old@email.com" "new@email.com" HEAD~10..HEAD

添加到~/.gitconfig:

[alias]
    change-commits = "!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch --env-filter \"if [[ \\\"$`echo $VAR`\\\" = '$OLD' ]]; then export $VAR='$NEW'; fi\" $@; }; f "

资料来源:https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig

希望它有用。

我已经尝试了上面的脚本,但它不适合我,这解决了我的问题:

使用Git的“filter branch”命令。它允许您使用脚本批量处理(可能大量)提交。您可以在存储库中运行以下示例脚本(填写新旧电子邮件和名称的真实值):

git filter-branch --env-filter '
WRONG_EMAIL="wrong@example.com"
NEW_NAME="New Name Value"
NEW_EMAIL="correct@example.com"

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

在此处查看更多详细信息

我发现所提供的版本非常激进,特别是如果你从其他开发人员那里提交补丁,这将从本质上窃取他们的代码。

下面的版本确实适用于所有分支机构,并分别更改作者和发件人以防止这种情况发生。

感谢leif81的所有选择。

#!/bin/bash

git filter-branch --env-filter '
if [ "$GIT_AUTHOR_NAME" = "<old author>" ];
then
    GIT_AUTHOR_NAME="<new author>";
    GIT_AUTHOR_EMAIL="<youmail@somehost.ext>";
fi
if [ "$GIT_COMMITTER_NAME" = "<old committer>" ];
then
    GIT_COMMITTER_NAME="<new commiter>";
    GIT_COMMITTER_EMAIL="<youmail@somehost.ext>";
fi
' -- --all