如何更改一系列提交的作者?
当前回答
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.example" ]
then
cn="Your New Committer Name"
cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "your@email.to.match.example" ]
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"
'
其他回答
如果您是该存储库的唯一用户,则可以使用gitfilter分支(如svick所写)、git快速导出/git快速导入加上过滤脚本(如docgnome answer中引用的文章所述)或交互式rebase重写历史。但其中任何一项都会从最初更改的承诺开始更改修订;这对任何基于分支预重写的更改的人来说都意味着麻烦。
回收,回收
若其他开发人员的工作并没有基于预重写版本,最简单的解决方案就是重新克隆(再次克隆)。
或者,他们可以尝试gitrebase--pull,如果他们的存储库中没有任何更改,这将加快速度,或者在重新编写的提交之上重新设置分支的基础(我们希望避免合并,因为这将永远保留预重写的commit)。所有这一切都假设他们没有未经许可的工作;否则,使用gitstash来隐藏更改。
如果其他开发人员使用功能分支,和/或git pull--rebase不起作用,例如,因为上游未设置,他们必须在重写后提交的基础上重新启动工作。例如,在获取新的更改(gitfetch)之后,对于基于/fforked-from origin/master的主分支,需要运行
$ git rebase --onto origin/master origin/master@{1} master
这里origin/master@{1}是预重写状态(在获取之前),请参阅gitrevisions。
另一种解决方案是使用refs/replace/mechanism,从1.6.5版开始,Git中就提供了这种机制。在该解决方案中,您可以替换电子邮件错误的提交;那么,任何获取“replace”ref的人(比如fetch=+refs/replace/*:refs/replace/*refspec位于其.git/config中的适当位置)都将透明地获取替换,而那些不获取这些ref的人将看到旧的提交。
程序大致如下:
查找包含错误电子邮件的所有提交,例如使用$git日志--作者=user@wrong.email--全部对于每个错误的提交,创建一个替换提交,并将其添加到对象数据库$git cat文件-p<错误提交的ID>|sed-e的/user@wrong\.电子邮件/user@example.com/g'>tmp.txt$git哈希对象-t提交-w tmp.txt<已更正提交的ID>既然您已经纠正了对象数据库中的提交,您必须告诉git使用git replace命令自动透明地用纠正的提交替换错误的提交:$git替换<错误提交的ID><更正提交的ID最后,列出所有替代品,以检查此过程是否成功$git替换-l并检查是否进行了更换$git日志--作者=user@wrong.email--全部
您当然可以自动执行此过程。。。好吧,除了使用gitreplace,它还没有批处理模式,所以您必须使用shell循环,或者手动替换。
未测试!YMMV。
请注意,在使用refs/replace/mechanism时可能会遇到一些粗糙的角落:它是新的,但尚未经过很好的测试。
使用交互式rebase,您可以在每次提交后放置一个修改命令。例如:
pick a07cb86 Project tile template with full details and styling
x git commit --amend --reset-author -Chead
注意:这个答案会改变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存在严重问题,现已弃用。
您还可以执行以下操作:
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
我应该指出,如果唯一的问题是作者/电子邮件与您平时的不同,这不是问题。正确的修复方法是在目录底部创建一个名为.mailmap的文件,行如下
Name you want <email you want> Name you don't want <email you don't want>
从那时起,像git shortlog这样的命令会认为这两个名称是相同的(除非你明确告诉他们不要这样做)。看见https://schacon.github.io/git/git-shortlog.html了解更多信息。
这与这里所有其他解决方案的优势在于,您不必重写历史,如果您有上游,这可能会导致问题,并且总是意外丢失数据的好方法。
当然,如果你以自己的身份提交了某件事,而它真的应该是其他人,而此时你不介意改写历史,出于归因的目的,更改提交作者可能是一个好主意(在这种情况下,我会在这里告诉你我的另一个答案)。
推荐文章
- 如何将git配置存储为存储库的一部分?
- 如何修改GitHub拉请求?
- 如何在Github和本地删除最后n次提交?
- 我如何调试git/git-shell相关的问题?
- 错误:无法使用rebase进行拉取:您有未分阶段的更改
- Git隐藏未缓存:如何把所有未分期的变化?
- 真实的恶魔
- 如何从另一个分支获得更改
- Git:权限被拒绝(publickey)致命-无法从远程存储库读取。克隆Git存储库时
- git reflog和log有什么区别?
- git推挂在Total line之后
- 重命名git子模块
- 结合Git存储库的前两次提交?
- Xcode 6 gitignore文件应该包括什么?
- 我如何从现有回购的分支创建一个新的GitHub回购?