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


我正在学校的计算机上写一个简单的脚本,并将更改提交给Git(在我的pendrive中的repo中,从我家里的计算机克隆)。经过几次提交,我意识到我是以root用户身份提交的东西。

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


2004
2018-04-15 03:09


起源


问题:使用git filter-branch是否保留了先前标签,版本和对象的SHA1?或者更改作者名称强制更改关联的SHA1也是如此? - AndyL
哈希会改变是的 - Not Available
切向地,我创建了一个小脚本,最终为我找到了根本原因。 gist.github.com/tripleee/16767aa4137706fd896c - tripleee
@impinball这个问题的年龄几乎没有关系。创建一个新的重复问题是不可能的。我想我可以创建一个问题来回答这个特定的答案,但我并不完全相信它会得到那么多的可见性。这不像是Git问题在这里缺乏......很高兴我能提供帮助。 - tripleee
GitHub有这个特殊的脚本: help.github.com/articles/changing-author-info - Timur Bernikowich


答案:


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

801
2018-04-15 03:16



Github有一个公共脚本 help.github.com/articles/changing-author-info 它很棒! - rodowi
执行脚本后,您可以通过执行“git update-ref -d refs / original / refs / heads / master”删除备份分支。 - D.R.
@rodowi,它复制了我的所有提交。 - Rafael Barros
@RafaelBarros作者信息(就像历史中的其他内容一样)是commit的sha键的一部分。对历史记录的任何更改都是重写,导致所有提交的新ID。因此,不要重写共享仓库或确保所有用户都知道它... - johannes
解决了使用 git push --force --tags origin HEAD:master - Matteo Contrini


使用Interactive Rebase

你可以做到

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.name 和 git 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>, 然后 git rebase 将它们弄平(顺便说一句,如果你使用GitHub拉取请求,你的历史将会有大量的合并提交)。这通常会导致非常不同的历史(因为重复的更改可能会“重新出现”),而在最坏的情况下,它可能导致 git rebase 要求您解决困难的合并冲突(可能已在合并提交中解决)。解决方案是使用 -p 国旗 git rebase,这将保留您的历史的合并结构。的联机帮助页 git rebase 警告说使用 -p 和 -i 可以导致问题,但在 BUGS 它说“编辑提交和重写他们的提交消息应该可以正常工作”。

我已经添加 -p 到上面的命令。对于刚刚更改最新提交的情况,这不是问题。


1417
2017-08-24 03:08



对于奇怪的提交非常有用 - 如果您正在配对而忘记更改作者则很有用 - mloughran
+1提及典型的一次错误修复的用例:git commit --amend --author = username - Nathan Kidd
这是完美的,我最常见的用法是我坐在另一台计算机上忘记设置作者,因此通常有<5提交左右修复。 - Zitrax
git commit --amend --reset-author 也工作一次 user.name 和 user.email 配置正确。 - pts
之后重写所有提交的作者信息 <commit> 运用 user.name 和 user.email 从 ~/.gitconfig: 跑 git rebase -i <commit> --exec 'git commit --amend --reset-author --no-edit',保存,退出。无需编辑! - ntc2


你也可以这样做:

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

566
2018-05-15 19:15



是不是使用env-filter更简单的解决方案?不知道为什么这会得到更多的选票。 - stigkj
然后链接被破坏了。我们如何将这些更改推送到另一个存储库? - Russell
env-filter将更改所有提交。该解决方案允许有条件的。 - user208769
"A previous backup already exists in refs/original/ Force overwriting the backup with -f" 对不起,但在哪里 -f -flag将执行此脚本两次。实际上这是在Brian的回答中,对于过滤器分支之后的干扰感到抱歉。 - hhh
@ user208769 env-filter也允许有条件;看看我的回答:-) - stigkj


一个班轮,但如果你有一个多用户存储库,要小心 - 这将改变 所有 承诺拥有相同的(新的)作者和提交者。

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

483
2018-04-15 03:22



是的,但不要忘记提交者的姓名/电子邮件。对我有用的是 git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; GIT_COMMITER_NAME='Newname'; GIT_COMMITTER_EMAIL='newemail';" HEAD 否则git将跟踪旧名称作为提交者! - Olivier Verdier
@Olivier您有关于GIT_COMMITER_NAME - > GIT_COMMITTER_NAME的拼写错误 - Filipe Correia
它适用于我的所有提交,包括最初的提交。 - Vincent
如果指定,为什么要重写所有提交 HEAD 在命令的最后? - Nick Volynkin
这对我的bitbucket存储库不起作用,任何想法?我做了 git push --force --tags origin 'refs/heads/*' 在建议的命令之后 - ujsgeyrr1f0d0d0r0h1h0j0j_juj


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


202
2018-02-16 09:46



这在上次提交时效果很好。很好,很简单。不 有 使用,成为全球变革 --local 也有效 - Ben
git commit --amend --reset-author --no-edit - mafrosis


对于单个提交:

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

(从asmeurer的答案中提取)


180
2018-04-26 22:50



但这只是在最近的提交中 - Richard
根据 git help commit, git commit --amend 更改“当前分支的尖端”(即HEAD)的提交。这通常是最近的提交,但您可以首先进行任何提交 退房 提交 git checkout <branch-name> 要么 git checkout <commit-SHA>。 - Rory O'Kane
但是如果你这样做,所有已经作为父提交的提交将指向错误的提交。最好在那时使用filter-branch。 - John Gietzen
@JohnGietzen:您可以将提交重新设置回更改为修复该提交的提交。但是,如果您正在进行> 1提交,那么如上所述,filter-branch可能会更容易。 - Thanatos
请注意,此更改仅提交 author 而不是 committer - Nick Volynkin


如果只有前几个提交有不好的作者,你可以在里面完成这一切 git rebase -i 使用 exec 命令和 --amend 提交,如下:

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的灵感。


152
2017-12-08 17:05



绝对棒极了。你可以通过在repo的本地配置中设置user.name和user.email来缩短它,然后每行只是exec git commit --amend --reset-author -C HEAD ? - Andrew
@Andrew --reset-author工作得很好。 - Boggin
规范的答案,使用filter-branch,只为我删除了refs / heads / master。因此,您可控制,可编辑的解决方案+1。谢谢! - jmtd
你为什么开始 Someone else's commit代替 my bad commit 1?我刚试过 HEAD^^ 修改最后2个提交,它工作得非常好。 - fredoverflow
代替 git rebase -i HEAD^^^^^^ 你也可以写 git rebase -i HEAD~6 - Patrick Schlüter


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"
'

108
2017-10-07 09:54



工作得很好。只是不得不 git reset --hard HEAD^ 在其他本地存储库上进行两次以使它们进入早期版本, git pull-ed修改后的版本,这里我没有包含任何行 unknown <stupid-windows-user@.StupidWindowsDomain.local> (得去爱git的默认)。 - Alan Plum
在此之后我无法推动。我必须使用“-f”吗? - fossilet
我做到了 git push -f。此外,本地回购必须在此之后重新开始。 - fossilet
如果需要在特定分支上运行shell脚本,可以将最后一行更改为:“'master..your-branch-name”(假设您已分支master)。 - Robert Kajic
脚本已更新,单击链接<nice solution> - mdn


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

79
2017-08-04 00:52



请注意,这将使任何标记指向旧提交。 --tag-name-filter cat 是“让它工作”的选择。 - Roman Starkov
@romkyns关于如何更改标签的任何想法? - Nick Volynkin
@NickVolynkin是的,你指定 --tag-name-filter cat。这应该是默认行为。 - Roman Starkov


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

git commit --amend --reset-author


46
2018-03-23 22:23



对于单个提交,如果您想要输入用户名,这是最简单的方法。 - Pedro Benevides
你可以加 --no-edit 为了使这更容易,因为通常大多数人只想更新电子邮件地址而不是更新提交消息 - PlagueHammer
你们可以分享一下git命令,只是为了更新最后一次提交的电子邮件/用户名 - adi
你试过这个吗?如果没有,这应该是这种副作用 stackoverflow.com/a/2717477/654245 看起来像一条好路。 - Ryanmt