【问题标题】:How to change the author and committer name and e-mail of multiple commits in Git?如何在 Git 中更改多个提交的作者和提交者姓名和电子邮件?
【发布时间】:2018-11-21 15:55:36
【问题描述】:

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

有没有办法将这些提交的作者更改为我的名字?

【问题讨论】:

  • 问题:使用 git filter-branch 会保留以前标签、版本和对象的 SHA1 吗?或者更改作者姓名是否会强制更改相关的 SHA1?
  • 哈希会改变是
  • 切线地,我创建了一个小脚本,最终为我解决了根本原因。 gist.github.com/tripleee/16767aa4137706fd896c
  • @impinball 问题的年龄几乎不相关。创建一个新的重复问题是不可能的。我想我可以创建一个问题来寻求这个特定的答案,但我并不完全相信它会获得如此多的知名度。并不是说这里缺少 Git 问题……很高兴我能帮上忙。
  • @TimurBernikovich 提到的 github 脚本很棒并且对我有用。但是那个 github url 已经改变了:docs.github.com/en/enterprise/2.17/user/github/using-git/…

标签: git version-control git-filter-branch git-rewrite-history


【解决方案1】:

将所有提交(包括第一次提交)重置为当前用户和当前时间戳:

git rebase --root --exec "git commit --amend --no-edit --date 'now' --reset-author"

【讨论】:

  • 这仅适用于当前分支。
【解决方案2】:

这个答案使用git-filter-branch,the docs 现在给出这个警告:

git filter-branch 有很多陷阱,可能会对预期的历史重写产生不明显的破坏(并且由于它的性能如此糟糕,因此您几乎没有时间调查此类问题)。这些安全和性能问题不能向后兼容修复,因此不建议使用它。请使用替代的历史过滤工具,例如git filter-repo。如果您仍然需要使用 git filter-branch,请仔细阅读SAFETY(和PERFORMANCE)了解 filter-branch 的地雷,然后尽可能合理地避免其中列出的许多危害。

更改作者(或提交者)将需要重写所有历史记录。如果您对此感到满意并认为值得,那么您应该查看git filter-branch。手册页包含几个帮助您入门的示例。另请注意,您可以使用环境变量来更改作者姓名、提交者、日期等。请参阅git man page 的“环境变量”部分。

具体来说,您可以使用此命令修复所有分支和标签的所有错误作者姓名和电子邮件(来源: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-repo,可以先安装它并按照gitmailmap的格式构造一个git-mailmap。

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

然后使用创建的邮件映射运行 filter-repo:

git filter-repo --mailmap git-mailmap

【讨论】:

  • 执行脚本后,您可以通过执行“git update-ref -d refs/original/refs/heads/master”删除备份分支。
  • @rodowi,它复制了我所有的提交。
  • @RafaelBarros 作者信息(就像历史上的其他任何内容一样)是提交的 sha 密钥的一部分。对历史的任何更改都是重写导致所有提交的新 id。所以不要重写共享仓库或确保所有用户都知道它......
  • 使用git push --force --tags origin HEAD:master解决
  • 重要!!! 在执行脚本之前,请正确设置您的 user.name 和 user.email git config 参数!执行脚本后,您将拥有一些称为“原始”的重复备份历史!通过git update-ref -d refs/original/refs/heads/master 删除它,然后检查.git/refs/original 文件夹结构是否为空,然后使用rm -rf .git/refs/original 将其删除。最后,您可以通过git log --pretty=format:"[%h] %cd - Committer: %cn (%ce), Author: %an (%ae)" 验证新的重写日志!还有一件事:.git/logs 有一些日志文件仍然使用您的旧名称!
【解决方案3】:

git docs here 建议的 filter-repo 工具是 git 的 filter-branch 更安全的替代品。

git filter-repo --commit-callback '
  old_email = b"your-old-email@example.com"
  correct_name = b"Your Correct Name"
  correct_email = b"your-correct-email@example.com"
  
  if commit.committer_email == old_email :
    commit.committer_name = correct_name
    commit.committer_email = correct_email

  if commit.author_email == old_email : 
    commit.author_name = correct_name
    commit.author_email = correct_email
  '

上述命令反映了this脚本中使用的逻辑,但使用filter-repo而不是filter-branch。

commit-callback 选项之后的代码主体基本上是用于处理提交的 python 代码。你可以在这里用 python 编写你自己的逻辑。详细了解commit 对象及其属性here。

由于 filter-repo 工具没有与 git 捆绑,您需要单独安装它。

见Prerequisties和Installation Guide

如果你有一个python env >= 3.5,你可以使用pip来安装它。

pip3 install git-filter-repo

注意:强烈建议在新克隆上尝试filter-repo 工具。操作完成后,遥控器也会被移除。阅读更多关于为什么删除遥控器here。另请阅读INTERNALS 部分下此工具的限制。

【讨论】:

  • 这似乎是新来的孩子,我像黄金一样珍惜这个答案。请记住字段必须是二进制的,然后删除 == 行,并且您可以在推送之前无条件地更改所有内容。我说过我喜欢这个答案吗?它应该是被接受的。
【解决方案4】:

我试过上面的脚本对我不起作用,这解决了我的问题:

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

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

查看更多详情here

【讨论】:

    【解决方案5】:

    当您没有初始化 $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 测试。

    请注意,这只修复了最后一次提交。

    【讨论】:

    • 在最后一次提交时效果很好。很好很简单。 必须是全局更改,使用 --local 也可以
    • 这个是我的大赢家!如果您使用错误的作者信息创建提交,然后通过git config 在事后设置正确的作者,git commit --amend --reset-author --no-edit 命令特别有用。刚刚在我必须更新电子邮件时节省了我的 a$$。
    • 答案可能有点矫枉过正。首先检查这是否满足您的用例 - stackoverflow.com/a/67363253/8293309
    【解决方案6】:

    单个命令更改最后 N 次提交的作者:

    git rebase -i HEAD~N -x "git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit"
    

    注意事项

    • 用引用替换HEAD~N,直到你想重写你的提交。这可以是哈希、HEAD~4、分支名称、...
    • --no-edit 标志确保git commit --amend 不要求额外确认
    • 当您使用git rebase -i时,您可以手动选择更改作者的提交,

    您编辑的文件将如下所示:

    pick 897fe9e simplify code a little
    exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
    pick abb60f9 add new feature
    exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
    pick dc18f70 bugfix
    exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
    

    然后您仍然可以修改一些行以查看要更改作者的位置。这为您在自动化和控制之间提供了一个很好的中间地带:您会看到将要运行的步骤,并且一旦您保存所有内容就会立即应用。

    注意,如果你已经用git config user.name &lt;your_name&gt;和git config user.email &lt;your_email&gt;修复了作者信息,你也可以使用这个命令:

    git rebase -i HEAD~N -x "git commit --amend --reset-author --no-edit"
    

    【讨论】:

    • 我使用了 HEAD~8,它显示的次数比最后 8 次提交要多。
    • @BryanBryce 如果涉及合并提交,事情会变得复杂:)
    • 您使用--root 而不是HEAD~N 来编辑整个历史记录(包括初始提交),并使用--reset-author 来获取当前提交者而不是--author ...
    • 我的用例是我必须更改一些私人存储库中所有过去的提交,因为我的推送使用不同的用户名,没有附加电子邮件。第一个位允许我更改前 N 次提交的作者和电子邮件,但它没有保留提交时间戳,这些时间戳随之更新。我解决了这个by using this script。它既漂亮又干净,允许我将整个提交历史更改为单个用户名和电子邮件,同时保留提交时间戳。
    • @PedroHenrique:您需要将HEAD~4 替换为引用,直到您要重写提交的位置......我会尝试在我的回答中更清楚地说明这一点。正如我之前提到的:当心合并提交,你会遇到复杂的事情
    【解决方案7】:

    对于所有提交,我的解决方案:

    git rebase -i --root -x "git commit --amend --author 'bedorlan <bedorlan@gmail.com>' --no-edit"
    

    【讨论】:

      【解决方案8】:

      注意:此答案会更改 SHA1,因此在已推送的分支上使用它时要小心。如果您只想修复名称的拼写或更新旧电子邮件,git 允许您这样做,而无需使用 .mailmap 重写历史记录。见my other answer。

      使用交互式变基

      你可以的

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

      然后在 rebase 文件中将所有错误提交标记为“编辑”。如果您还想更改第一次提交,则必须手动将其添加为 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.name 和git config user.email 中配置的用户。如果您想将提交者设置为您指定的内容,这将同时设置作者和提交者:

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

      关于合并提交的注意事项

      我原来的回复有一点小瑕疵。如果当前的HEAD 和你的&lt;some HEAD before all your bad commits&gt; 之间有任何合并提交,那么git rebase 会将它们展平(顺便说一下,如果你使用 GitHub 拉取请求,你的历史)。这通常会导致非常不同的历史记录(因为重复的更改可能会“重新定位”),并且在最坏的情况下,它可能会导致git rebase 要求您解决困难的合并冲突(可能已经在合并提交)。解决方案是对git rebase 使用-p 标志,这将保留您历史记录的合并结构。 git rebase 的联机帮助页警告说,使用 -p 和 -i 可能会导致问题,但在 BUGS 部分它说“编辑提交并重新编写提交消息应该可以正常工作。”

      我已将-p 添加到上述命令中。对于您只是更改最近提交的情况,这不是问题。

      现代 git 客户端更新(2020 年 7 月)

      使用--rebase-merges 代替-p(-p 已被弃用并且存在严重问题)。

      【讨论】:

      • 非常适合奇怪的提交 - 如果您正在配对并且忘记更改作者,则很有用
      • +1 用于提及典型的错误修复的用例: git commit --amend --author=username
      • 这很完美,我最常见的用例是我坐在另一台电脑前忘记设置作者,因此通常有
      • git commit --amend --reset-author 在 user.name 和 user.email 配置正确后也可以工作。
      • 在&lt;commit&gt; 之后使用user.name 和user.email 从~/.gitconfig 重写所有提交的作者信息:运行git rebase -i &lt;commit&gt; --exec 'git commit --amend --reset-author --no-edit',保存,退出。无需编辑!
      【解决方案9】:

      我应该指出,如果唯一的问题是作者/电子邮件与您平时不同,这不是问题。正确的解决方法是在目录的底部创建一个名为 .mailmap 的文件,其中包含类似

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

      从那时起,git shortlog 之类的命令将认为这两个名称相同(除非您明确告诉它们不要这样做)。请参阅http://schacon.github.com/git/git-shortlog.html 了解更多信息。

      这具有此处所有其他解决方案的优势,因为您不必重写历史记录,如果您有上游可能会导致问题,并且始终是意外丢失数据的好方法。

      当然,如果您以自己的身份提交了某些内容,并且确实应该是其他人,并且此时您不介意重写历史记录,那么更改提交作者可能是出于归因目的的好主意(在这种情况下,我指示你给我的另一个答案here)。

      【讨论】:

      • 其实这是一个非常有趣的答案。就我而言,我在家里做了一些提交,这可能会让额外的作者感到困惑,所以这就是我所需要的。
      • 另外,请注意这不适用于 Gitea 的 web 端。
      • @iuliu.net 我不确定。这个问题stackoverflow.com/questions/53629125/… 似乎表明确实如此,但我尚未确认。当然,如果他们不这样做,那么他们应该这样做,因为它是 git 的标准部分。
      【解决方案10】:

      如果您想(轻松)更改当前分支的作者,我会使用如下内容:

      # update author for everything since origin/master
      git rebase \
        -i origin/master \
        --exec 'git commit --amend --no-edit --author="Author Name <author.name@email.co.uk>"'
      

      【讨论】:

        【解决方案11】:

        我想为@Rognon 答案的修改做出贡献。如果所选答案或其他答案对您不起作用(在我的特定问题中就是这种情况),此答案只是另一种选择:

        目标:您将在所有历史记录中使用正确的作者修复一个或多个作者,并且您将获得一个没有重复的干净历史记录。此方法通过用“干净”分支替换“主”分支来工作(它不使用合并/变基)

        注意:任何使用“主”存储库的人可能需要在推送之前再次检出它(在执行这些步骤之后),因为合并可能会失败。

        我们将使用一个名为“clean”的新分支来执行操作(假设您要修复“master”):

        git checkout -b clean

        (确保您在“干净”分支中:git branch)

        修改以下脚本(替换电子邮件地址和姓名)。请注意,此脚本需要两个错误的电子邮件/作者(例如),因此如果您只需要修复单个作者,您可以删除条件的第二部分或保持原样(因为它将被忽略,因为它不会t 匹配)。

        执行脚本。

        #/bin/bash
        
        git filter-branch --force --commit-filter '
                if [ "$GIT_COMMITTER_EMAIL" = "wrong1@example.com" -o "$GIT_COMMITTER_EMAIL" = "wrong2@example.com" ];
                then
                        export GIT_COMMITTER_NAME="John Doe";
                        export GIT_AUTHOR_NAME="John Doe";
                        export GIT_COMMITTER_EMAIL="correct@example.com";
                        export GIT_AUTHOR_EMAIL="correct@example.com";
                fi;
                git commit-tree "$@"
        ' --tag-name-filter cat -- --all
        

        它必须报告:Ref 'refs/heads/clean' was rewritten。如果它报告“未更改”,则可能是脚本中输入的电子邮件错误。

        确认历史记录已更正:git log

        如果您使用的是 github/gitlab(推荐 = 安全):

        1. 在远程创建“干净”分支:

        git push --set-upstream origin clean

        1. 将“干净”分支设置为默认分支
        2. 删除“master”(在执行此操作之前确保一切都符合预期)。
        3. 基于“干净”分支创建一个新分支“master”。
        4. 确认一切正常后,您现在可以删除“干净”分支(或者您可以重命名它)。

        如果不使用 github/gitlab 或者您更喜欢通过命令来完成:

        1. 从本地删除master分支:

        git branch -d master

        1. 重命名分支:

        git branch -m clean master

        1. 推送它(确保您的“主人”不受保护)

        git push --force origin master

        【讨论】:

          【解决方案12】:

          windows下也可以使用git-rocket-filter工具。

          来自the documentation:

          更改提交作者姓名和电子邮件:

          git-rocket-filter --branch TestBranch --commit-filter '
              if (commit.AuthorName.Contains("Jim")) {   
                  commit.AuthorName = "Paul"; 
                  commit.AuthorEmail = "paul@company.com"; 
              }
          

          【讨论】:

            【解决方案13】:

            以上所有答案都重写了存储库的历史。 只要多个作者没有使用要更改的名称,特别是如果存储库已共享并且提交是旧的,我更愿意使用.mailmap,记录在https://git-scm.com/docs/git-shortlog。 它允许将不正确的名称/电子邮件映射到正确的名称/电子邮件,而无需修改回购历史记录。您可以使用以下行:

            Proper Name <proper@email.xx> <root@localhost>
            

            【讨论】:

              【解决方案14】:

              您可以将其用作别名,以便您可以:

              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: 'change-commits' 不是 git 命令。参见 'git --help'。"
              • 在此命令和与 master 同步之后,历史记录中的所有提交都被复制了!甚至其他用户:(
              • @Vladimir 是意料中事,请研究一下 git 中的历史变化
              • 对我来说它似乎在 /bin/sh 中运行,所以我不得不用 sh 兼容测试 [ ](单括号)替换特定于 bash 的测试 [[ ]]。除此之外,它工作得很好,谢谢!
              • @Native_Mobile_Arch_Dev 你需要这个: git config --global alias.change-commits '!'"f() { VAR=\$1; OLD=\$2; NEW=\$3; shift 3; git filter-branch --env-filter \"if [[ \\\"\$`echo \$VAR`\\\" = '\$OLD' ]];然后导出 \$VAR='\$NEW'; fi\" \$@; }; f"
              【解决方案15】:

              最快、最简单的方法是使用 git rebase 的 --exec 参数:

              git rebase -i -p --exec 'git commit --amend --reset-author --no-edit'
              

              这将创建一个如下所示的待办事项列表:

              pick ef11092 Blah blah blah
              exec git commit --amend --reset-author --no-edit
              pick 52d6391 Blah bloh bloo
              exec git commit --amend --reset-author --no-edit
              pick 30ebbfe Blah bluh bleh
              exec git commit --amend --reset-author --no-edit
              ...
              

              这将自动工作,当您有数百次提交时,它会工作。

              【讨论】:

              • 您可以将-p 替换为--root 以更改历史记录中的所有 个提交(-p option 已弃用)。请注意,这仅在您通过 git config user.name &lt;yourname&gt; 和 git config user.email &lt;youremail&gt; 更正用户名和电子邮件后才有效。
              【解决方案16】:

              试试这个。它将执行与上述相同的操作,但以交互方式进行。

              bash <(curl -s  https://raw.githubusercontent.com/majdarbash/git-author-change-script/master/run.sh)
              

              参考:https://github.com/majdarbash/git-author-change-script

              【讨论】:

                【解决方案17】:

                我也想添加我的示例。 我想用给定的参数创建一个 bash_function。

                这适用于 mint-linux-17.3

                # $1 => email to change, $2 => new_name, $3 => new E-Mail
                
                function git_change_user_config_for_commit {
                
                 # defaults
                 WRONG_EMAIL=${1:-"you_wrong_mail@hello.world"}
                 NEW_NAME=${2:-"your name"}
                 NEW_EMAIL=${3:-"new_mail@hello.world"}
                
                 git filter-branch -f --env-filter "
                  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;
                }
                

                【讨论】:

                  【解决方案18】:

                  如果只有前几个提交的作者不好,您可以使用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 的启发。

                  【讨论】:

                  • 绝对很棒。你可以通过在 repo 的本地配置中设置 user.name 和 user.email 来缩短它,然后每一行是 onlyexec git commit --amend --reset-author -C HEAD 吗?
                  • 规范答案,使用过滤器分支,只是为我删除了 refs/heads/master。所以 +1 为您的可控、可编辑的解决方案。谢谢!
                  • 代替git rebase -i HEAD^^^^^^你也可以写git rebase -i HEAD~6
                  • 请注意,这会更改提交的时间戳。请参阅stackoverflow.com/a/11179245/1353267 以恢复到正确的时间戳
                  • 对于和我一样遇到同样问题的其他人,如果您尝试包含初始提交并且收到fatal: Needed a single revision,请尝试使用git rebase -i --root
                  【解决方案19】:
                  1. 将提交author name &amp; email 更改为Amend,然后替换old-commit with new-one:

                    $ git checkout <commit-hash>                            # checkout to the commit need to modify  
                    $ git commit --amend --author "name <author@email.com>" # change the author name and email
                    
                    $ git replace <old-commit-hash> <new-commit-hash>      # replace the old commit by new one
                    $ git filter-branch -- --all                           # rewrite all futures commits based on the replacement                   
                    
                    $ git replace -d <old-commit-hash>     # remove the replacement for cleanliness 
                    $ git push -f origin HEAD              # force push 
                    
                  2. 另一种方式Rebasing:

                    $ git rebase -i <good-commit-hash>      # back to last good commit
                    
                    # Editor would open, replace 'pick' with 'edit' before the commit want to change author
                    
                    $ git commit --amend --author="author name <author@email.com>"  # change the author name & email
                    
                    # Save changes and exit the editor
                    
                    $ git rebase --continue                # finish the rebase
                    

                  【讨论】:

                  • 非常好的答案。我喜欢从更新到清理 git 提交的更改
                  【解决方案20】:

                  这不是您的问题的答案,而是您可以用来在将来避免这种情况的脚本。它利用自Git version 2.9 以来可用的全局挂钩来根据您所在的目录检查您的电子邮件配置:

                  #!/bin/sh
                  PWD=`pwd`
                  if [[ $PWD == *"Ippon"* ]] # 1)
                  then
                    EMAIL=$(git config user.email)
                    if [[ $EMAIL == *"Work"* ]] # 2)
                    then
                      echo "";
                    else
                      echo "Email not configured to your Work email in the Work directory.";
                      git config user.email "youremail@youremail.com"
                      echo "Git email configuration has now been changed to \"$(git config user$
                      echo "\nPlease run your command again..."
                      echo ''
                      exit 1
                    fi;
                  elif [[ $PWD == *"Personal"* ]]
                  then
                    EMAIL=$(git config user.email)
                    if [[ $EMAIL == "youremail@youremail.com" ]]
                    then
                      echo "";
                    else
                      echo "Email is not configured to your personal account in the Personal di$
                      git config user.email "youremail@youremail.com"
                      echo "Git email configuration has now been changed to \"$(git config user$
                      echo "\nPlease run your command again..."
                      echo ''
                      exit 1;
                    fi;
                  fi; 
                  

                  它会检查您当前的工作目录,然后验证您的 git 是否配置为正确的电子邮件。如果没有,它会自动更改它。查看完整详情here。

                  【讨论】:

                    【解决方案21】:
                    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
                    

                    rebase 完成后按 ^C #(循环将不断更新最后一次提交)

                    【讨论】:

                      【解决方案22】:

                      当从其他作者那里接管一个未合并的提交时,有一种简单的方法来处理这个问题。

                      git commit --amend --reset-author

                      【讨论】:

                      • 对于一次提交,如果你想输入你的用户名,这是最简单的方法。
                      • 您可以添加--no-edit 以使这更容易,因为通常大多数人只想更新电子邮件地址而不是提交消息
                      • 你们能否分享一下 git 命令,以便用新的更新上次提交的电子邮件/用户名
                      • 你试过了吗?这应该是一个副作用,如果不是stackoverflow.com/a/2717477/654245 看起来像一条好路。
                      【解决方案23】:

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

                      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
                      

                      【讨论】:

                      • 如果在命令末尾指定HEAD,为什么会重写所有提交?
                      • 这不适用于我的 bitbucket 存储库,知道吗?我在建议的命令之后执行git push --force --tags origin 'refs/heads/*'
                      • 推送命令是:$git push --force --tags origin 'refs/heads/master'
                      • 整洁;这也保留了旧的时间戳。
                      • @HARSHNILESHPATHAK 请注意,对于最近创建的存储库,分支 master 已重命名为 main,因此命令变为 $git push --force --tags origin 'refs/heads/main'
                      【解决方案24】:

                      你的问题很常见。见“Using Mailmap to Fix Authors List in Git”

                      为了简单起见,我创建了一个脚本来简化这个过程:git-changemail

                      将该脚本放在您的路径上后,您可以发出如下命令:

                      • 更改当前分支上的作者匹配项

                        $ git changemail -a old@email.com -n newname -m new@email.com
                        
                      • 更改 和 上的作者和提交者匹配。将 -f 传递给 filter-branch 以允许重写备份

                        $ git changemail -b old@email.com -n newname -m new@email.com -- -f &lt;branch> &lt;branch2>
                        
                      • 在 repo 上显示现有用户

                        $ git changemail --show-both
                        

                      顺便说一句,在进行更改后,请使用以下命令从过滤器分支中清除备份:git-backup-clean

                      【讨论】:

                      • 当我运行你的命令时,它说“致命:无法执行'git-changemail':权限被拒绝”
                      • @Govind 需要设置脚本的执行权限chmod +x git-changemail
                      【解决方案25】:

                      我们今天遇到了一个问题,作者姓名中的 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
                      

                      快速概览:将存储库签出到临时文件,签出所有远程分支,运行将重写历史记录的脚本,强制推送新状态,并告诉所有同事执行 rebase pull 以获取变化。

                      我们在 OS X 上运行它时遇到了麻烦,因为它以某种方式弄乱了提交消息中的行尾,因此我们不得不在 Linux 机器上重新运行它。

                      【讨论】:

                        【解决方案26】:

                        正如 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
                        

                        【讨论】:

                        • 请注意,这将留下任何指向旧提交的标签。 --tag-name-filter cat 是“让它工作”选项。
                        • @romkyns 知道如何更改标签吗?
                        • @NickVolynkin 是的,您指定 --tag-name-filter cat。这确实应该是默认行为。
                        • 答案可能有点矫枉过正。首先检查这是否满足您的用例 - stackoverflow.com/a/67363253/8293309
                        【解决方案27】:

                        对于单个提交:

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

                        (摘自 asmeurer 的回答)

                        【讨论】:

                        • 但这只是最近的提交
                        • 根据git help commit,git commit --amend 更改“当前分支的尖端”(即 HEAD)处的提交。这通常是最近的提交,但您可以通过第一个 checking out 使用 git checkout &lt;branch-name&gt; 或 git checkout &lt;commit-SHA&gt; 提交任何您想要的提交。
                        • 但是如果你这样做,所有已经有该提交作为父提交的提交都将指向错误的提交。此时最好使用 filter-branch。
                        • @JohnGietzen:您可以将提交重新设置为已更改以解决该问题的提交。但是,如果您进行 >1 次提交,那么如前所述,filter-branch 可能会容易得多。
                        • 请注意,此更改仅提交 author 而不是 committer
                        【解决方案28】:

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

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

                        即示例author-conv-file

                        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
                        

                        【讨论】:

                        • 谢谢,我想知道为什么这不是核心 git(或 git-svn)功能。这可以通过 git svn clone 的标志来完成,但不能在 git filter-branch...
                        【解决方案29】:

                        我发现提供的版本过于激进,特别是如果您提交其他开发人员的补丁,这实际上会窃取他们的代码。

                        以下版本确实适用于所有分支,并分别更改作者和提交者以防止这种情况发生。

                        感谢 leif81 的 all 选项。

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

                        【讨论】:

                          【解决方案30】:

                          我使用以下内容来重写整个存储库的作者,包括标签和所有分支:

                          git filter-branch --tag-name-filter cat --env-filter "
                            export GIT_AUTHOR_NAME='New name';
                            export GIT_AUTHOR_EMAIL='New email'
                          " -- --all
                          

                          然后,如MAN page of filter-branch 中所述,删除所有由filter-branch 备份的原始引用(这是破坏性的,先备份):

                          git for-each-ref --format="%(refname)" refs/original/ | \
                          xargs -n 1 git update-ref -d
                          

                          【讨论】:

                          • 使用--tag-name-filter cat非常重要。否则,您的标签将保留在原始提交链上。其他答案没有提到这一点。
                          猜你喜欢
                          • 1970-01-01
                          • 2014-11-14
                          • 1970-01-01
                          • 2018-05-27
                          • 2021-02-08
                          • 2021-04-11
                          相关资源
                          最近更新 更多