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

Flá*_*iro 2282 git version-control git-filter-branch git-rewrite-history

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

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

asm*_*rer 1539

使用Interactive Rebase

你可以做到

git rebase -i -p <some HEAD before all of your bad commits>
Run Code Online (Sandbox Code Playgroud)

然后将所有错误提交标记为rebase文件中的"edit".如果您还想更改第一次提交,则必须手动将其添加为rebase文件中的第一行(遵循其他行的格式).然后,当git要求你修改每个提交时,做

 git commit --amend --author "New Author Name <email@address.com>" 
Run Code Online (Sandbox Code Playgroud)

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

git rebase --continue
Run Code Online (Sandbox Code Playgroud)

继续坚持.

你可以通过追加跳过这里完全打开编辑器,.mailmap 这样命令将是:

git commit --amend --author "New Author Name <email@address.com>" --no-edit && \
git rebase --continue
Run Code Online (Sandbox Code Playgroud)

单一提交

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

 git commit --amend --author "New Author Name <email@address.com>"
Run Code Online (Sandbox Code Playgroud)

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

 git -c user.name="New Author Name" -c user.email=email@address.com commit --amend --reset-author
Run Code Online (Sandbox Code Playgroud)

关于合并提交的注意事项

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

我已添加BUGS到上面的命令中.对于刚刚更改最新提交的情况,这不是问题.

  • 一旦`user.name`和`user.email`配置正确,`git commit --amend --reset-author`也可以工作. (50认同)
  • +1提及典型的一次错误修复的用例:git commit --amend --author = username (32认同)
  • 非常适合奇怪的提交 - 如果您配对并忘记更改作者,则非常有用 (27认同)
  • 这是完美的,我最常见的用法是我坐在另一台计算机上忘记设置作者,因此通常需要<5次提交才能修复. (11认同)
  • 在`<commit>`之后使用`user.name`和`〜/ .gitconfig`中的`user.email`重写所有提交的作者信息:运行`git rebase -i <commit> --exec'git commit --amend --reset-author --no-edit'`,save,quit.无需编辑! (10认同)
  • 要包含第一个提交,您可以使用`git rebase -i --root` (3认同)
  • @qwr我找到了上面评论的解决方案:首先使用 `git config` 设置新作者,然后 `git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="%cD" GIT_AUTHOR_DATE="%aD" git commit -- amend --no-edit --reset-author' rebase --committer-date-is-author-date -r --root HEAD` 这会重置作者并保留所有提交(包括第一次提交)的时间戳。从 reddit 帖子中得到提示 https://www.reddit.com/r/git/comments/jp59k5/rebase_without_changing_commit_timestamps/ (3认同)
  • 如果你甚至只有一百个提交可以通过,那将需要*永远*. (2认同)
  • 我需要使用 git push -f 才能将其推送到我的存储库主机(git push -f -u origin master) (2认同)
  • 两种解决方案都创建新的提交,但是github的解决方案(请参见接受的答案)使其余的元数据(例如提交日期)保持不变。 (2认同)
  • 请注意,这将重置提交日期 (2认同)
  • 要再次重申nandilugio和Jorjon所说的话:__这将覆盖所有提交的时间戳。__如果您不想破坏元数据,请使用接受的答案中的`filter-branch`脚本。 (2认同)
  • 请注意,“--author”不会更改提交日期,而“--reset-author”则会更改提交日期。 (2认同)
  • 小心这也会改变提交日期!这不是我想要的。我用上面的解决方案毁了我所有的提交历史 (2认同)
  • @transang `--author` 保留作者日期,但不保留提交日期(默认情况下在 github 上显示)。请参阅/sf/ask/1997588631/ (2认同)

Pat*_*otz 1099

更改作者(或提交者)将需要重写所有历史记录.如果您对此感到满意并认为它值得,那么您应该查看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
Run Code Online (Sandbox Code Playgroud)

  • Github有一个https://help.github.com/articles/changing-author-info的公共脚本,它很棒! (570认同)
  • 执行脚本后,您可以通过执行"git update-ref -d refs/original/refs/heads/master"来删除备份分支. (32认同)
  • 解决了使用`git push --force --tags origin HEAD:master` (17认同)
  • @rodowi,它复制了我的所有提交. (7认同)
  • @RafaelBarros作者信息(就像历史中的其他内容一样)是commit的sha键的一部分.对历史记录的任何更改都是重写,导致所有提交的新ID.所以不要重写共享仓库或确保所有用户都知道它... (6认同)
  • **重要!!!**在执行脚本之前,请正确设置user.name和user.email git config参数!执行脚本后,您将拥有一些名为"original"的重复备份历史记录!通过`git update-ref -d refs/original/refs/heads/master`删除它,然后检查`.git/refs/original`文件夹结构是否为空,然后用`rm -rf .git/refs删除它/ original`.最后,您可以通过以下方式验证新的重写日志:`git log --pretty = format:"[%h]%cd - 提交者:%cn(%ce),作者:%an(%ae)"`!还有一件事:`.git/logs`有一些日志文件仍然有你的旧名字! (5认同)
  • 我已经根据这个答案创建了一个交互式脚本 - 如果你有多个作者修改https://gist.github.com/yaronuliel/8157d7318de988f4399f561d466e12f3,可以避免重新编写脚本 (3认同)
  • 我想我已经找到了一种(看似安全的)方法来删除引用日志中的旧条目以及仍然包含旧作者详细信息的原始(现在是孤立的)提交。首先按照此答案中所述运行脚本,然后运行“git update-ref -d refs/original/refs/heads/master”,然后运行“git -c gc.reflogExpireUnreachable=now gc --prune=now”。这会删除对旧提交链的引用,使它们成为孤儿,然后第二个命令将清除引用日志中的所有引用并删除(修剪)实际提交 blob(使用 git show &lt;one of the old commit hashes 检查&gt;`) (3认同)
  • 顺便说一句:“.git/logs”是您的引用日志。它很重要,不能手动编辑。从那里摆脱你自己的名字的唯一方法是创建一个全新的空存储库,将现有的存储库设置为远程存储库,将旧存储库拉入分支,然后将该分支重新设置为新存储库。我只是为一个敏感项目这样做,但这对大多数人来说工作量太大了(我在这里使用了两个答案的变体:http://stackoverflow.com/questions/5340790/easiest-way-to-replay-commits- on-new-git-repository)。之后我还做了“git gc --aggressive”来清理它。祝你好运。 (2认同)

小智 585

你也可以这样做:

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
Run Code Online (Sandbox Code Playgroud)

注意,如果在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
Run Code Online (Sandbox Code Playgroud)

  • env-filter将更改所有提交.该解决方案允许有条件的. (28认同)
  • `"refs/original/Force中已存在先前的备份,用-f覆盖备份"对不起,但`-f` -flag将执行此脚本两次.实际上,在Brian的回答中,对于过滤器分支之后的干扰感到抱歉. (5认同)
  • 是不是使用env-filter更简单的解决方案?不知道为什么这会得到更多的选票. (4认同)
  • 然后链接被破坏了.我们如何将这些更改推送到另一个存储库? (3认同)
  • @ user208769 env-filter也允许有条件; 看看我的回答:-) (2认同)

Bri*_*aro 531

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

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
Run Code Online (Sandbox Code Playgroud)

使用字符串中的换行符(可以在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
Run Code Online (Sandbox Code Playgroud)

  • 是的,但不要忘记提交者的姓名/电子邮件.对我有用的是`git filter-branch -f --env-filter"GIT_AUTHOR_NAME ='Newname'; GIT_AUTHOR_EMAIL ='newemail'; GIT_COMMITER_NAME ='Newname'; GIT_COMMITTER_EMAIL ='newemail';" HEAD`否则git将跟踪旧名称作为提交者! (16认同)
  • 它适用于我的所有提交,包括最初的提交. (8认同)
  • 推送命令是:`$git push --force --tags origin 'refs/heads/master' ` (5认同)
  • @HARSHNILESHPATHAK 请注意,对于最近创建的存储库,分支 master 已重命名为 main,因此命令变为 `$git push --force --tags origin 'refs/heads/main'` (5认同)
  • 如果在命令末尾指定`HEAD`,为什么要重写所有提交? (4认同)
  • 这对我的 bitbucket 存储库不起作用,知道吗?我在建议的命令之后做了一个 `git push --force --tags origin 'refs/heads/*'` (3认同)
  • @Olivier您在GIT_COMMITER_NAME上输入了一个拼写错误 - > GIT_COMMITTER_NAME (2认同)
  • 整洁的; 这也保留了旧的时间戳。 (2认同)
  • 几年后回到这个问题,我对这个基于[警告]的答案感到害怕(https://git-scm.com/docs/git-filter-branch#_warning)。我最终制定了[我自己的答案](/sf/answers/5132002501/),它保留了旧作者和提交者时间戳。 (2认同)
  • 要推送,您需要强制使用:`git push --force` (2认同)

lrk*_*kwz 216

当您没有初始化$ HOME/.gitconfig时会发生这种情况.你可以解决这个问题:

git config --global user.name "you name"
git config --global user.email you@domain.com
git commit --amend --reset-author
Run Code Online (Sandbox Code Playgroud)

用git版本1.7.5.4测试

  • `git commit --amend --reset-author --no-edit` (53认同)
  • 这在最后一次提交时效果很好.很好,很简单.使用`--local`也不会*成为全局变化 (9认同)

blu*_*yed 183

对于单个提交:

git commit --amend --author="Author Name <email@address.com>"
Run Code Online (Sandbox Code Playgroud)

(摘自asmeurer的回答)

  • 但这只是它是最近的提交 (13认同)
  • 但是如果你这样做,所有已经作为父提交的提交将指向错误的提交.最好在那时使用filter-branch. (12认同)
  • 请注意,这只会改变提交`author`而不是`committer` (5认同)
  • 根据[`git help commit`](http://schacon.github.com/git/git-commit.html),`git commit --amend`更改了"当前分支的尖端"的提交(是HEAD).这通常是最近的提交,但你可以通过首先[check out](http://schacon.github.com/git/git-checkout.html)提交你想要的任何提交,使用`git checkout <branch -name>`或`git checkout <commit-SHA>`. (3认同)
  • @JohnGietzen:您可以将提交重新修改为更改为修复该提交的提交.但是,如果您正在进行> 1提交,那么如上所述,filter-branch可能会更容易. (3认同)

Ale*_*own 172

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

git rebase -i HEAD~6 # as required
Run Code Online (Sandbox Code Playgroud)

它为您提供了可编辑的提交列表:

pick abcd Someone else's commit
pick defg my bad commit 1
pick 1234 my bad commit 2
Run Code Online (Sandbox Code Playgroud)

然后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
Run Code Online (Sandbox Code Playgroud)

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

这个解决方案可能比其他解决方案更长,但它是高度可控的 - 我确切知道它所提交的提交内容.

感谢@asmeurer的灵感.

  • 绝对棒极了.你可以通过在repo的本地配置中设置user.name和user.email来缩短它,然后每行只有`exec git commit --amend --reset-author -C HEAD`? (25认同)
  • @Andrew --reset-author工作得很好. (4认同)
  • 代替`git rebase -i HEAD ^^^^^^`你也可以写`git rebase -i HEAD~6` (3认同)
  • 规范的答案是使用过滤器分支,只是为我删除了 refs/heads/master 。因此,为您的可控、可编辑的解决方案+1。谢谢! (2认同)
  • 请注意,这会更改提交的时间戳。请参阅 /sf/answers/782547181/ 以恢复到正确的时间戳 (2认同)
  • 对于与我遇到同样问题的其他人,如果您尝试包含初始提交并且收到“致命:需要单个修订”,请尝试使用“git rebase -i --root” (2认同)

Oli*_*ier 110

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"
'
Run Code Online (Sandbox Code Playgroud)

  • 我做了`git push -f`.此外,在此之后必须重新进行当地回购. (9认同)
  • 工作得很完美.只需要对其他本地存储库进行几次`git reset --hard HEAD ^`以使它们更早版本,`git pull`-ed修正版本,这里我没有任何包含`unknown <的行stupid-windows-user @ .StupidWindowsDomain.local>`(喜欢git的默认). (5认同)

svi*_*ick 80

正如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'
Run Code Online (Sandbox Code Playgroud)

为了加快速度,您可以指定要重写的一系列修订:

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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这将保留所有指向旧提交的标记。``--tag-name-filter cat``是“使其工作”选项。 (2认同)

Rya*_*nmt 48

当从另一位作者接管一个未合并的提交时,有一种简单的方法来处理它.

git commit --amend --reset-author

  • 您可以添加`--no-edit`以使其更容易,因为通常大多数人只想更新电子邮件地址而不是更新提交消息 (7认同)

bra*_*obo 46

您可以将其用作别名,以便执行以下操作:

git change-commits GIT_AUTHOR_NAME "old name" "new name"
Run Code Online (Sandbox Code Playgroud)

或者最近10次提交:

git change-commits GIT_AUTHOR_EMAIL "old@email.com" "new@email.com" HEAD~10..HEAD
Run Code Online (Sandbox Code Playgroud)

添加到〜/ .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 "
Run Code Online (Sandbox Code Playgroud)

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

希望它有用.

  • “git: 'change-commits' 不是 git 命令。请参阅 'git --help'。” (3认同)

sti*_*gkj 38

这是@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
Run Code Online (Sandbox Code Playgroud)

您可能会收到以下错误之一:

  1. 临时目录已存在
  2. refs/original开始的refs已经存在
    (这意味着先前已经在存储库上运行了另一个filter-branch,然后在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
Run Code Online (Sandbox Code Playgroud)

-- --all可能需要对该选项进行一些解释:它使filter-branch适用于所有refs(包括所有分支)的所有修订.这意味着,例如,标签也被重写并在重写的分支上可见.

一个常见的"错误"是使用HEAD,这意味着只过滤当前分支上的所有修订.然后在重写的分支中不存在标签(或其他引用).


小智 23

  1. git rebase -i <sha1 or ref of starting point>
  2. 标记要更改的所有提交edit(或e)
  3. 循环以下两个命令,直到您处理完所有提交:

    git commit --amend --reuse-message=HEAD --author="New Author <new@author.email>" ; git rebase --continue

这将保留所有其他提交信息(包括日期).该--reuse-message=HEAD选项阻止消息编辑器启动.


Ton*_*vel 22

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

git filter-branch --tag-name-filter cat --env-filter "
  export GIT_AUTHOR_NAME='New name';
  export GIT_AUTHOR_EMAIL='New email'
" -- --all
Run Code Online (Sandbox Code Playgroud)

然后,如过滤器分支MAN页面中所述,删除所有备份的原始引用filter-branch(这是破坏性的,先备份):

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

  • 使用`--tag-name-filter cat`非常重要.否则,您的标记将保留在原始提交链上.其他答案没有提到这一点. (2认同)

Lei*_*ldt 21

我改编了这个解决方案,通过摄取一个简单的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>
Run Code Online (Sandbox Code Playgroud)

剧本:

 #!/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
Run Code Online (Sandbox Code Playgroud)


Chr*_*aes 21

一个用于更改最后N次提交的作者的命令

git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit"
Run Code Online (Sandbox Code Playgroud)

笔记

  • --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
Run Code Online (Sandbox Code Playgroud)

然后,您仍然可以修改一些行,以查看要在哪里更改作者。这为您提供了介于自动化和控制之间的良好中间立场:您将看到将要运行的步骤,一旦保存,所有内容将立即应用。

  • 您使用“--root”而不是“HEAD~N”来编辑整个历史记录(包括初始提交),并使用“--reset-author”来获取当前提交者而不是“--author ...” (5认同)
  • @BryanBryce 如果涉及合并提交,事情就会变得复杂:) (2认同)
  • 我的用例是,我必须更改某些私人存储库中所有过去的提交,因为我的推送是在不同的用户名下进行的,没有附加电子邮件。第一点允许我更改前 N 次提交的作者和电子邮件,但它没有保留提交时间戳,这些时间戳会随之更新。我[通过使用这个脚本]解决了这个问题(https://gist.github.com/bgromov/a1905055a8b9cdbeb1d2a87e70920cc8)。它漂亮又干净,允许我将整个提交历史记录更改为单个用户名和电子邮件,同时保留提交时间戳。 (2认同)

dra*_*hnr 18

我发现所提供的版本是积极的,特别是如果你从其他开发人员提交补丁,这将基本上窃取他们的代码.

下面的版本适用于所有分支,并分别更改作者和comitter以防止这种情况.

感谢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
Run Code Online (Sandbox Code Playgroud)


Saj*_*han 18

  1. 更改承诺author name & emailAmend,然后替换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 
    
    Run Code Online (Sandbox Code Playgroud)
  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
    
    Run Code Online (Sandbox Code Playgroud)

  • 非常好的答案.我喜欢这些更改都是从更新中解决,甚至清理git提交 (2认同)

asm*_*rer 16

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

Name you want <email you want> Name you don't want <email you don't want>
Run Code Online (Sandbox Code Playgroud)

从那时起,命令git shortlog就会认为这两个名字是相同的(除非你明确告诉他们不要).有关更多信息,请参见http://schacon.github.com/git/git-shortlog.html.

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

当然,如果你做了自己的事情并且应该真的是其他人,并且你现在不介意重写历史记录,那么更改提交作者可能是一个好主意用于归因目的(在这种情况下我指导你到我的这里的其他答案).

  • 另外,请注意,这不适用于 Gitea 的 Web 端。 (2认同)

Sau*_*ari 14

一个更安全的 git 替代方法filter-branchfilter-repogit docs here建议的工具。

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
  '
Run Code Online (Sandbox Code Playgroud)

上述命令的反射镜中所用的逻辑这个脚本,但使用filter-repo代替filter-branch

commit-callback选项后的代码体基本上是用于处理提交的python代码。你可以在这里用python编写自己的逻辑。在此处查看有关commit对象及其属性的更多信息。

由于filter-repo工具未与 git 捆绑在一起,因此您需要单独安装它。

请参阅先决条件安装指南

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

pip3 install git-filter-repo
Run Code Online (Sandbox Code Playgroud)

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

  • 这似乎是新来的,我像金子一样珍惜这个答案。请记住,字段必须是二进制的,然后删除 == 行,并且您可以在推送之前无条件更改所有内容。我有说过我喜欢这个答案吗?应该是公认的。 (2认同)

Jak*_*ski 9

如果您是此存储库的唯一用户,则可以使用(如svick编写)或/ plus过滤脚本(如docgnome answer中引用的文章中所述)或交互式rebase 重写历史记录.但是其中任何一个都会改变第一次更改提交后的修订; 对于任何基于他/她的分支预先重写的更改的人来说,这意味着麻烦.git filter-branchgit fast-exportgit fast-import

复苏

如果其他开发人员没有将他们的工作基于预重写版本,那么最简单的解决方案就是重新克隆(再次克隆).

或者他们可以尝试git rebase --pull,如果他们的存储库中没有任何更改,它会快进,或者在重写提交之后重新绑定他们的分支(我们希望避免合并,因为它将永远保留预重写命令).所有这一切都假设他们没有做过工作; 使用git stash以其他方式离开藏匿的变化.

如果其他开发人员使用功能分支,和/或git pull --rebase不起作用例如,由于上游没有成立,他们必须重订其对-改写后提交顶工作.例如,在获取新的更改(git fetch)之后,对于master基于/ forked的分支origin/master,需要运行

$ git rebase --onto origin/master origin/master@{1} master
Run Code Online (Sandbox Code Playgroud)

origin/master@{1}是预重写状态(在获取之前),请参阅gitrevisions.


替代解决方案是使用refs/replace / mechanism,自1.6.5版本开始在Git中提供.在此解决方案中,您为具有错误电子邮件的提交提供替换; 然后任何提取'替换'引用的人(fetch = +refs/replace/*:refs/replace/*他们的 适当位置像refspec 一样.git/config)会透明地获得替换,而那些不获取这些引用的人会看到旧的提交.

程序如下:

  1. 查找所有提交错误电子邮件的提交,例如使用

    $ git log --author=user@wrong.email --all
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于每个错误的提交,创建替换提交,并将其添加到对象数据库

    $ git cat-file -p <ID of wrong commit> | 
      sed -e 's/user@wrong\.email/user@example.com/g' > tmp.txt
    $ git hash-object -t commit -w tmp.txt
    <ID of corrected commit>
    
    Run Code Online (Sandbox Code Playgroud)
  3. 现在您已经更正了对象数据库中的提交,您必须告诉git使用以下git replace命令自动并透明地替换错误的提交:

    $ git replace <ID of wrong commit> <ID of corrected commit>
    
    Run Code Online (Sandbox Code Playgroud)
  4. 最后,列出所有替换以检查此过程是否成功

    $ git replace -l
    
    Run Code Online (Sandbox Code Playgroud)

    并检查是否有替换

    $ git log --author=user@wrong.email --all
    
    Run Code Online (Sandbox Code Playgroud)

你当然可以自动执行这个程序......好吧,除了使用git replace哪个没有(还)批处理模式,所以你必须使用shell循环,或者"手工"替换.

没有测试!因人而异.

请注意,使用refs/replace/机制时可能会遇到一些粗糙的问题:它是新的,尚未经过很好的测试.


Lie*_*yan 9

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

git rebase -i -p --exec 'git commit --amend --reset-author --no-edit'
Run Code Online (Sandbox Code Playgroud)

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

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
...
Run Code Online (Sandbox Code Playgroud)

并且这将全部自动进行,当您有数百次提交时,该方法也将起作用。


Mix*_*OID 8

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

git rebase --root --exec "git commit --amend --no-edit --date 'now' --reset-author"
Run Code Online (Sandbox Code Playgroud)


djr*_*ero 6

如果您想要修复的提交是最新的,只有其中几个,您可以使用组合git resetgit stash在配置正确的名称和电子邮件后再次提交它们.

序列将是这样的(对于2个错误的提交,没有挂起的更改):

git config user.name <good name>
git config user.email <good email>
git reset HEAD^
git stash
git reset HEAD^
git commit -a
git stash pop
git commit -a
Run Code Online (Sandbox Code Playgroud)


Ami*_*adi 6

单行filter-repo

您可以使用(推荐的替代品)的回调功能来更改与所有提交关联的名称和电子邮件:git-filter-repofilter-branch

git filter-repo --name-callback 'return b"New Name"' --email-callback 'return b"newemail@gmail.com"'
Run Code Online (Sandbox Code Playgroud)

这比使用 的解决方案性能更高,并且可能更可靠filter-branch

请注意,上面的命令更改了所有提交的作者(和提交者),如果您想有效地“编辑”某个作者,并且只修改该特定作者的提交,请使用--commit-callback如下选项:

git filter-repo --commit-callback '
old_email = b"oldemail@gmail.com"
new_email = b"newemail@gmail.com"
new_name = b"New Author"

if commit.author_email == old_email:
    commit.author_email = new_email
    commit.author_name = new_name

if commit.committer_email == old_email:
    commit.committer_email = new_email
    commit.committer_name = new_name
'
Run Code Online (Sandbox Code Playgroud)

(只需将上面命令中的old_emailnew_email和变量更改为正确的值即可。)new_name


小智 5

如果您使用Eclipse与EGit,那么有一个非常简单的解决方案.
假设:您在本地分支"local_master_user_x"中提交,由于用户无效,无法将其推送到远程分支"master".

  1. 签出远程分支'master'
  2. 选择"local_master_user_x"包含更改的项目/文件夹/文件
  3. 右键单击 - 替换为 - 分支 - 'local_master_user_x'
  4. 再次提交这些更改,这次是正确的用户并进入本地分支'master'
  5. 推送到远程'主'


j16*_*16r 5

使用交互式rebase,您可以在每次要更改的提交后放置修改命令.例如:

pick a07cb86 Project tile template with full details and styling
x git commit --amend --reset-author -Chead
Run Code Online (Sandbox Code Playgroud)

  • 这个问题是其他提交元数据(例如日期和时间)也被修改.我刚刚发现了那种艰难的方式`;-)`. (3认同)

Sir*_*hos 5

请注意,git存储两个不同的电子邮件地址,一个用于提交者(提交更改的人),另一个用于作者(编写更改的人).

提交者信息不会在大多数地方显示,但您可以使用git log -1 --format=%cn,%ce(或使用show而不是log指定特定提交)来查看它.

虽然更改上次提交的作者非常简单git commit --amend --author "Author Name <email@example.com>",但是对于提交者信息没有单行或参数可以做同样的事情.

解决方案是(暂时或不临时)更改您的用户信息,然后修改提交,这将更新提交者到您当前的信息:

git config user.email my_other_email@example.com 
git commit --amend
Run Code Online (Sandbox Code Playgroud)


Mil*_*vić 5

我们今天遇到了一个问题,即作者姓名中的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
Run Code Online (Sandbox Code Playgroud)

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

我们在OS X上运行它时遇到了麻烦,因为它在某些方面搞砸了提交消息中的行结尾,所以我们不得不在之后的Linux机器上重新运行它.


alb*_*fan 5

你的问题很常见.请参阅" 使用Mailmap修复Git中的作者列表 "

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

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

顺便说一句,在进行更改后,使用以下命令从filter-branch清除备份:git-backup-clean


归档时间:

查看次数:

797318 次

最近记录:

5 年,9 月 前