我正在学校的计算机上编写一个简单的脚本,并将更改提交给Git(在我的pendrive中的repo中,从我家里的计算机克隆).几次提交后,我意识到我正在以root用户身份提交东西.
有没有办法将这些提交的作者改成我的名字?
你可以做到
git rebase -i -p
然后将所有错误提交标记为rebase文件中的"edit".如果您还想更改第一次提交,则必须手动将其添加为rebase文件中的第一行(遵循其他行的格式).然后,当git要求你修改每个提交时,做
git commit --amend --author "New Author Name "
编辑或只关闭打开的编辑器,然后执行
git rebase --continue
继续坚持.
你可以通过追加跳过这里完全打开编辑器,.mailmap
这样命令将是:
git commit --amend --author "New Author Name " --no-edit && \
git rebase --continue
正如一些评论者所指出的,如果您只想更改最近的提交,则不需要rebase命令.做就是了
git commit --amend --author "New Author Name "
这会将作者更改为指定的名称,但是提交者将在--no-edit
和中设置为您配置的用户git config user.name
.如果要将提交者设置为您指定的内容,则会设置作者和提交者:
git -c user.name="New Author Name" -c user.email=email@address.com commit --amend --reset-author
我原来的回答有一点点缺陷.如果在当前git config user.email
和你之间有任何合并提交HEAD
,那么
将展平它们(顺便说一句,如果你使用GitHub拉取请求,你的历史记录中将会有大量的合并提交).这通常会导致非常不同的历史记录(因为重复更改可能会"重新出现"),并且在最坏的情况下,它可能导致git rebase
要求您解决困难的合并冲突(可能已在合并提交中解决).解决方案是使用git rebase
标志来-p
保留历史记录的合并结构.该联机帮助页git rebase
警告说使用git rebase
并-p
可能导致问题,但在该-i
部分中它说"编辑提交和重写其提交消息应该可以正常工作".
我已添加BUGS
到上面的命令中.对于刚刚更改最新提交的情况,这不是问题.
更改作者(或提交者)将需要重写所有历史记录.如果您对此感到满意并认为它值得,那么您应该查看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
你也可以这样做:
git filter-branch --commit-filter '
if [ "$GIT_COMMITTER_NAME" = "" ];
then
GIT_COMMITTER_NAME="";
GIT_AUTHOR_NAME="";
GIT_COMMITTER_EMAIL="";
GIT_AUTHOR_EMAIL="";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
注意,如果在Windows命令提示符下使用此命令,则需要使用"
而不是'
:
git filter-branch --commit-filter "
if [ "$GIT_COMMITTER_NAME" = "" ];
then
GIT_COMMITTER_NAME="";
GIT_AUTHOR_NAME="";
GIT_COMMITTER_EMAIL="";
GIT_AUTHOR_EMAIL="";
git commit-tree "$@";
else
git commit-tree "$@";
fi" HEAD
一个班轮,但如果你有一个多用户存储库,要小心 - 这将改变所有提交以拥有相同(新)作者和提交者.
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
当您没有初始化$ 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测试
对于单个提交:
git commit --amend --author="Author Name "
(摘自asmeurer的回答)
如果只有前几个提交有不好的作者,你可以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" -C HEAD pick 1234 my bad commit 2 exec git commit --amend --author="New Author Name " -C HEAD
保存并退出编辑器(运行).
这个解决方案可能比其他解决方案更长,但它是高度可控的 - 我确切知道它所提交的提交内容.
感谢@asmeurer的灵感.
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"
'
正如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
当从另一位作者接管一个未合并的提交时,有一种简单的方法来处理它.
git commit --amend --reset-author
您可以将其用作别名,以便执行以下操作:
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
希望它有用.
这是@Brian版本的更精细版本:
要更改作者和提交者,您可以执行此操作(在bash中可以使用字符串中的换行符):
git filter-branch --env-filter '
if [ "$GIT_COMMITTER_NAME" = "" ];
then
GIT_COMMITTER_NAME="";
GIT_COMMITTER_EMAIL="";
GIT_AUTHOR_NAME="";
GIT_AUTHOR_EMAIL="";
fi' -- --all
您可能会收到以下错误之一:
临时目录已存在
从refs/original开始的refs已经存在
(这意味着先前已经在存储库上运行了另一个filter-branch,然后在refs/original处备份了原始分支引用)
如果要在不考虑这些错误的情况下强制运行,请添加--force
标志:
git filter-branch --force --env-filter '
if [ "$GIT_COMMITTER_NAME" = "" ];
then
GIT_COMMITTER_NAME="";
GIT_COMMITTER_EMAIL="";
GIT_AUTHOR_NAME="";
GIT_AUTHOR_EMAIL="";
fi' -- --all
-- --all
可能需要对该选项进行一些解释:它使filter-branch适用于所有refs(包括所有分支)的所有修订.这意味着,例如,标签也被重写并在重写的分支上可见.
一个常见的"错误"是使用HEAD
,这意味着只过滤当前分支上的所有修订.然后在重写的分支中不存在标签(或其他引用).
跑 git rebase -i
标记要更改的所有提交edit
(或e
)
循环以下两个命令,直到您处理完所有提交:
git commit --amend --reuse-message=HEAD --author="New Author
;
git rebase --continue
这将保留所有其他提交信息(包括日期).该--reuse-message=HEAD
选项阻止消息编辑器启动.
我使用以下内容为整个存储库重写作者,包括标记和所有分支:
git filter-branch --tag-name-filter cat --env-filter "
export GIT_AUTHOR_NAME='New name';
export GIT_AUTHOR_EMAIL='New email'
" -- --all
然后,如过滤器分支的MAN页面中所述,删除所有备份的原始引用filter-branch
(这是破坏性的,先备份):
git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d
我改编了这个解决方案,通过摄取一个简单的author-conv-file
格式(格式与git-cvsimport的格式相同).它的工作原理是更改author-conv-file
所有分支中定义的所有用户.
我们结合使用cvs2git
它将我们的存储库从cvs迁移到git.
即样品 author-conv-file
john=John Doejill=Jill Doe
剧本:
#!/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
一个用于更改最后N次提交的作者的命令:
git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name' --no-edit"
笔记
该--no-edit
标志可以确保git commit --amend
不要求额外的确认
使用时git rebase -i
,您可以手动选择更改作者的提交,
您编辑的文件将如下所示:
pick 897fe9e simplify code a little exec git commit --amend --author 'Author Name' --no-edit pick abb60f9 add new feature exec git commit --amend --author 'Author Name ' --no-edit pick dc18f70 bugfix exec git commit --amend --author 'Author Name ' --no-edit
然后,您仍然可以修改一些行,以查看要在哪里更改作者。这为您提供了介于自动化和控制之间的良好中间立场:您将看到将要运行的步骤,一旦保存,所有内容将立即应用。
我发现所提供的版本是积极的,特别是如果你从其他开发人员提交补丁,这将基本上窃取他们的代码.
下面的版本适用于所有分支,并分别更改作者和comitter以防止这种情况.
感谢leif81的所有选项.
#!/bin/bash
git filter-branch --env-filter '
if [ "$GIT_AUTHOR_NAME" = "" ];
then
GIT_AUTHOR_NAME="";
GIT_AUTHOR_EMAIL="";
fi
if [ "$GIT_COMMITTER_NAME" = "" ];
then
GIT_COMMITTER_NAME="";
GIT_COMMITTER_EMAIL="";
fi
' -- --all
更改承诺author name & email
的Amend
,然后替换old-commit with new-one
:
$ git checkout# checkout to the commit need to modify $ git commit --amend --author "name " # change the author name and email $ git replace # replace the old commit by new one $ git filter-branch -- --all # rewrite all futures commits based on the replacement $ git replace -d # remove the replacement for cleanliness $ git push -f origin HEAD # force push
另一种方式Rebasing
:
$ git rebase -i# 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 " # change the author name & email # Save changes and exit the editor $ git rebase --continue # finish the rebase
我应该指出,如果唯一的问题是作者/电子邮件与平常不同,这不是问题.正确的解决方法是创建一个.mailmap
在目录底部调用的文件,其中包含类似的行
Name you wantName you don't want
从那时起,命令git shortlog
就会认为这两个名字是相同的(除非你明确告诉他们不要).有关更多信息,请参见http://schacon.github.com/git/git-shortlog.html.
这具有所有其他解决方案的优点,因为您不必重写历史记录,如果您有上游,这可能会导致问题,并且始终是意外丢失数据的好方法.
当然,如果你做了自己的事情并且应该真的是其他人,并且你现在不介意重写历史记录,那么更改提交作者可能是一个好主意用于归因目的(在这种情况下我指导你到我的这里的其他答案).
如果您是此存储库的唯一用户,则可以使用(如svick编写)或/ plus过滤脚本(如docgnome answer中引用的文章中所述)或交互式rebase 重写历史记录.但是其中任何一个都会改变第一次更改提交后的修订; 对于任何基于他/她的分支预先重写的更改的人来说,这意味着麻烦.git filter-branch
git fast-export
git 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
这origin/master@{1}
是预重写状态(在获取之前),请参阅gitrevisions.
替代解决方案是使用refs/replace / mechanism,自1.6.5版本开始在Git中提供.在此解决方案中,您为具有错误电子邮件的提交提供替换; 然后任何提取'替换'引用的人(fetch = +refs/replace/*:refs/replace/*
在他们的 适当位置像refspec 一样.git/config
)会透明地获得替换,而那些不获取这些引用的人会看到旧的提交.
程序如下:
查找所有提交错误电子邮件的提交,例如使用
$ git log --author=user@wrong.email --all
对于每个错误的提交,创建替换提交,并将其添加到对象数据库
$ git cat-file -p| sed -e 's/user@wrong\.email/user@example.com/g' > tmp.txt $ git hash-object -t commit -w tmp.txt
现在您已经更正了对象数据库中的提交,您必须告诉git使用以下git replace
命令自动并透明地替换错误的提交:
$ git replace
最后,列出所有替换以检查此过程是否成功
$ git replace -l
并检查是否有替换
$ git log --author=user@wrong.email --all
你当然可以自动执行这个程序......好吧,除了使用git replace
哪个没有(还)批处理模式,所以你必须使用shell循环,或者"手工"替换.
没有测试!因人而异.
请注意,使用refs/replace/
机制时可能会遇到一些粗糙的问题:它是新的,尚未经过很好的测试.
最快,最简单的方法是使用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 ...
并且这将全部自动进行,当您有数百次提交时,该方法也将起作用。
如果您想要修复的提交是最新的,只有其中几个,您可以使用组合git reset
和git stash
在配置正确的名称和电子邮件后再次提交它们.
序列将是这样的(对于2个错误的提交,没有挂起的更改):
git config user.namegit config user.email git reset HEAD^ git stash git reset HEAD^ git commit -a git stash pop git commit -a
如果您使用Eclipse与EGit,那么有一个非常简单的解决方案.
假设:您在本地分支"local_master_user_x"中提交,由于用户无效,无法将其推送到远程分支"master".
签出远程分支'master'
选择"local_master_user_x"包含更改的项目/文件夹/文件
右键单击 - 替换为 - 分支 - 'local_master_user_x'
再次提交这些更改,这次是正确的用户并进入本地分支'master'
推送到远程'主'
使用交互式rebase,您可以在每次要更改的提交后放置修改命令.例如:
pick a07cb86 Project tile template with full details and styling x git commit --amend --reset-author -Chead
请注意,git存储两个不同的电子邮件地址,一个用于提交者(提交更改的人),另一个用于作者(编写更改的人).
提交者信息不会在大多数地方显示,但您可以使用git log -1 --format=%cn,%ce
(或使用show
而不是log
指定特定提交)来查看它.
虽然更改上次提交的作者非常简单git commit --amend --author "Author Name
,但是对于提交者信息没有单行或参数可以做同样的事情.
解决方案是(暂时或不临时)更改您的用户信息,然后修改提交,这将更新提交者到您当前的信息:
git config user.email my_other_email@example.com git commit --amend
我们今天遇到了一个问题,即作者姓名中的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机器上重新运行它.
你的问题很常见.请参阅" 使用Mailmap修复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 <branch> <branch2>
在repo上显示现有用户
$ git changemail --show-both
顺便说一句,在进行更改后,使用以下命令从filter-branch清除备份:git-backup-clean