一、背景

最近搭建好GitLab后,准备陆陆续续的将之前在SVN仓库中保存的代码迁移到GitLab上,昨天顺利将三个Android组件的代码迁移到GitLab后,其他同事发现迁移是成功了,但是pull下来命令后查看git log 发现所有人的有些都配置成了我的邮箱,尴尬啊。

GitLab上面全部变成了我的提交记录,尴尬。

二、原因分析

下面具体分析下为什么产生这个的原因。

具体原因是因为再做SVN–>Git迁移准备的时候,第一步要建议SVN用户到Git用户的映射文件。而这个映射文件最终我将所有用户的名字改过来了,但是邮箱没有改,全部填了我自己的邮箱。

ouyangpeng = ouyangpeng <ouyangpeng = ouyangpeng <ouyangpeng@csdn.com>>
lihongmeng = lihongmeng <ouyangpeng@oaserver.dw.gdbbk.com>
liyang = liyang <ouyangpeng@oaserver.dw.gdbbk.com>
wangshuyin = wangshuyin <ouyangpeng@oaserver.dw.gdbbk.com>
wuqi = wuqi <ouyangpeng@oaserver.dw.gdbbk.com>
youpeng = youpeng <ouyangpeng@oaserver.dw.gdbbk.com>
zhangjie = zhangjie <ouyangpeng@oaserver.dw.gdbbk.com>

在 Subversion,每个提交者在都在主机上有一个用户名,记录在提交信息中。如果想让已有的信息更好的映射到 Git 作者数据里,则需要 从 Subversion 用户名到 Git 作者的一个映射关系,因为Git是用邮箱来标识一个提交者的。建立一个叫做 userinfo.txt 的文件,每行一条svn作者 = 作者昵称 <邮箱地址>,用如下格式表示映射关系

ouyangpeng = ouyangpeng <ouyangpeng@csdn.com>
abc= abc<abc@csdn.com>

在SVN代码的文件目录下,使用如下命令获取到所有提交者的名字。

获取svn提交的作者名并保存到userinfo.txt

svn log --xml | grep "^<author" | sort -u | \awk -F '<author>' '{print $2}' | awk -F '</author>' '{print $1}' > userinfo.txt

得到以下文本,文本格式如下所示:

ouyangpeng
lihongmeng
liyang
wangshuyin
wuqi
youpeng
zhangjie

然后根据以上的格式编辑作者的邮件信息等,就是在这一步由于粗心,只是替换了对应的Git用户,并没有将邮箱替换过来,编译后的文本如下所示:

ouyangpeng = ouyangpeng <ouyangpeng = ouyangpeng <ouyangpeng@csdn.com>>
lihongmeng = lihongmeng <ouyangpeng@oaserver.dw.gdbbk.com>
liyang = liyang <ouyangpeng@oaserver.dw.gdbbk.com>
wangshuyin = wangshuyin <ouyangpeng@oaserver.dw.gdbbk.com>
wuqi = wuqi <ouyangpeng@oaserver.dw.gdbbk.com>
youpeng = youpeng <ouyangpeng@oaserver.dw.gdbbk.com>
zhangjie = zhangjie <ouyangpeng@oaserver.dw.gdbbk.com>

如上所示,所有的SVN用户名都有对应的Git用户名,但是此用户的邮箱都填了我的oa邮箱,并没有填写对应的git用户的邮箱,尴尬!因此才导致迁移后的git log 里面所有人的邮箱都是我的邮箱。

三、解决方案

具体如何从svn迁移到git的话,在本篇博客不讨论了。本篇博客只记录下如何修改git已提交的记录中的Author和Email?

1、查询解决方案

查询【stack overflow】 网站,

https://stackoverflow.com/questions/750172/change-the-author-and-committer-name-and-e-mail-of-multiple-commits-in-git

得到下面的解决方法:

原文如下:

To change the author and committer, you can do this (with linebreaks in the string which is possible in 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

This is a more elaborated version of @Brian’s version:

To change the author and committer, you can do this (with linebreaks in the string which is possible in 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

You might get one of these errors:

  1. The temporary directory exists already
  2. Refs starting with refs/original exists already

    (this means another filter-branch has been run previously on the repository and the then original branch reference is backed up at refs/original)
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

A little explanation of the -- --all option might be needed: It makes the filter-branch work on all revisions on all refs (which includes all branches). This means, for example, that tags are also rewritten and is visible on the rewritten branches.

A common “mistake” is to use HEAD instead, which means filtering all revisions on just the current branch. And then no tags (or other refs) would exist in the rewritten branch.

2、编写解决方案脚本

按照上面的思路,我自己改写了下脚本,如下所示,

在git项目下,新建一个shell脚本文件,明明为 modify_email_by_name.sh,shell脚本的内容如下所示:

  #!/bin/bash 

 git filter-branch  --force --env-filter '
#如果Git用户名等于老的Git用户名 wangshuyin
if [ "$GIT_COMMITTER_NAME" = "wangshuyin" ] || [ "$GIT_AUTHOR_EMAIL" = "wangshuyin" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="wangshuyin";
GIT_AUTHOR_EMAIL="wangshuyin@oaserver.dw.gdbbk.com"; #替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="wangshuyin";
GIT_COMMITTER_EMAIL="wangshuyin@oaserver.dw.gdbbk.com";
fi #如果Git用户名等于老的Git用户名 lihongmeng
if [ "$GIT_COMMITTER_NAME" = "lihongmeng" ] || [ "$GIT_AUTHOR_EMAIL" = "lihongmeng" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="lihongmeng";
GIT_AUTHOR_EMAIL="lihongmeng@oaserver.dw.gdbbk.com";
#替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="lihongmeng";
GIT_COMMITTER_EMAIL="lihongmeng@oaserver.dw.gdbbk.com";
fi #如果Git用户名等于老的Git用户名 liyang
if [ "$GIT_COMMITTER_NAME" = "liyang" ] || [ "$GIT_AUTHOR_EMAIL" = "liyang" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="liyang";
GIT_AUTHOR_EMAIL="liyang@oaserver.dw.gdbbk.com"; #替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="liyang";
GIT_COMMITTER_EMAIL="liyang@oaserver.dw.gdbbk.com";
fi #如果Git用户名等于老的Git用户名 wuqi
if [ "$GIT_COMMITTER_NAME" = "wuqi" ] || [ "$GIT_AUTHOR_EMAIL" = "wuqi" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="wuqi";
GIT_AUTHOR_EMAIL="wuqi@oaserver.dw.gdbbk.com"; #替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="wuqi";
GIT_COMMITTER_EMAIL="wuqi@oaserver.dw.gdbbk.com";
fi #如果Git用户名等于老的Git用户名 youpeng
if [ "$GIT_COMMITTER_NAME" = "youpeng" ] || [ "$GIT_AUTHOR_EMAIL" = "youpeng" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="youpeng";
GIT_AUTHOR_EMAIL="youpeng@oaserver.dw.gdbbk.com"; #替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="youpeng";
GIT_COMMITTER_EMAIL="youpeng@oaserver.dw.gdbbk.com";
fi #如果Git用户名等于老的Git用户名 zhangjie
if [ "$GIT_COMMITTER_NAME" = "zhangjie" ] || [ "$GIT_AUTHOR_EMAIL" = "zhangjie" ];
then
#替换用户名为新的用户名,替换邮箱为正确的邮箱
GIT_AUTHOR_NAME="zhangjie";
GIT_AUTHOR_EMAIL="zhangjierj@oaserver.dw.gdbbk.com"; #替换提交的用户名为新的用户名,替换提交的邮箱为正确的邮箱
GIT_COMMITTER_NAME="zhangjie";
GIT_COMMITTER_EMAIL="zhangjierj@oaserver.dw.gdbbk.com";
fi
' --tag-name-filter cat -- --branches --tags

因为项目人数总共就6个,因此我全部列出来,然后遍历的去改变git log 已经提交的日志中的用户名和密码。如下所示:

3、执行解决方案脚本

在执行脚本之前,先查看本地分支和远程分支是否同步

使用如下Git命令查看所有远程分支:

git branch -r

使用如下Git命令查看所有本地分支:

git branch

如下图所示:

然后再使用命令如下命令,拉取远程分支并建立并切换到本地分支

git checkout -b 本地分支名x origin/远程分支名x

使用该方式会在本地新建分支x,并自动切换到该本地分支x。

如上图所示,拉取完毕之后,并保证和远程分支都相同了,然后再执行modify_email_by_name.sh脚本文件

然后执行命令,使modify_email_by_name.sh脚本文件可执行

chmod +x modify_email_by_name.sh

接着执行modify_email_by_name.sh脚本文件

./modify_email_by_name.sh

如上所示,所有的分支都被重写了一遍。

接着使用git log 命令查看一下被修改后的提交记录,如下所示:

由上图可以看到,所有的邮箱都改为正常映射的邮箱了。

4、执行过程错误

在执行编写脚本过程中,不停改脚本不停执行脚本,因此可能出现问题。

当执行脚本的时候,报了如下的错误

.git-rewrite already exists,please remove it

解决方法是:

参考文档:http://alistairboettiger.info/wordpress/?p=6171

 $ rm -rf .git-rewrite
$ git filter-branch --tree-filter 'rm -rf ./External' HEAD

如下图所示:

在执行脚本的时候,有一次我只是写了一个用户的替换方案,执行完后改变脚本文件再执行的时候,报了如下错误:

Cannot create a new backup.

A previous backup already exists in refs/original/

Force overwriting the backup with -f

解决方法是:

参考文档:

http://www.davidverhasselt.com/git-how-to-remove-your-password-from-a-repository/

https://stackoverflow.com/questions/6403601/purging-file-from-git-repo-failed-unable-to-create-new-backup

执行代码:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch Rakefile' HEAD

如下图所示:

5、提交正确的历史记录到GitLab服务器

执行命令

git push --force --tags origin 'refs/heads/*'

改掉之后,再次查看GitLab上的提交记录,会发现都正常换过来了,如下所示:

对比下修改之前的gitlab记录

四、参考文档

  1. https://stackoverflow.com/questions/750172/change-the-author-and-committer-name-and-e-mail-of-multiple-commits-in-git
  2. https://help.github.com/articles/changing-author-info/
  3. http://blog.csdn.net/diu_brother/article/details/51982993
  4. http://www.jianshu.com/p/b6add8187c06
  5. http://lmbj.net/blog/how-do-i-change-the-author-of-a-commit-in-git/
  6. http://www.davidverhasselt.com/git-how-to-remove-your-password-from-a-repository/
  7. https://stackoverflow.com/questions/6403601/purging-file-from-git-repo-failed-unable-to-create-new-backup
  8. http://alistairboettiger.info/wordpress/?p=6171

作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!

转载请保留原文地址:http://blog.csdn.net/ouyang_peng/article/details/75329779

如果本文对您有所帮助,欢迎您扫码下图所示的支付宝和微信支付二维码对本文进行打赏。

git学习------>如何修改git已提交的记录中的Author和Email?的更多相关文章

  1. Git学习系列之Git基本操作提交项目(图文详解)

    前面博客 Git学习系列之Git基本操作克隆项目(图文详解) 然后可以 cd 切换到 LispGentleIntro 目录, 新增或者修改某些文件.这里只是模拟一下操作, 实际情况可能是 使用 Ecl ...

  2. Git学习系列之Git基本操作推送项目(图文详解)

    前面博客 Git学习系列之Git基本操作提交项目(图文详解) 如果完成到一定程度,那么可以推送到远端在线仓库. 推送之前,请确保你已经设置了全局的 user.name 和 user.email, 如果 ...

  3. git学习------>写给 Git 初学者的7个建议

    PS:本文转载于(http://blog.jobbole.com/50603/),本文由 伯乐在线 - 吴鹏煜 翻译. 英文出处:(http://sixrevisions.com/web-develo ...

  4. Git学习系列之Git基本操作拉取项目(图文详解)

    前面博客 Git学习系列之Git基本操作推送项目(图文详解) 当然,如果多人协作,或者多个客户端进行修改,那么我们还要拉取(Pull ... )别人推送到在线仓库的内容下来. 大神们是不推荐使用 pu ...

  5. Git学习系列之Git 的缺点有哪些?

    不多说,直接上干货 前面,谈及了 Git学习系列之Git 的优势有哪些? 缺点: (1)资料少(起码中文资料很少). (2)学习周期相对而言比较长. (3)不符合常规思维. (4)代码保密性差,一旦开 ...

  6. [git 学习篇] --创建git创库

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013743256916071d ...

  7. vs推送git失败,修改git下config的Log

    一开始写完程序套推送到Git中,然后就来了一下,下面的异常: 异常1 发布到远程存储库时遇到错误: Git failed with a fatal error. fatal: HttpRequestE ...

  8. Git学习笔记(SourceTree克隆、提交、推送、拉取等)

    学习一下sourcetree使用git 目录 一 克隆Clone 二 提交Commit和推送Push 三 拉取pull和获取fetch 四 版本回退reset 五 检出checkout 六 标签Tag ...

  9. git 学习笔记 —— 切换和恢复提交版本( git reset/reflog/tag 命令)

    记录一下关于 git 不同提交版本间切换的操作以及如何恢复至切换之前的版本. 切换到之前提交的版本 —— git reset --hard 笔者在使用 git 时,首先接触到了一个"黑魔法& ...

随机推荐

  1. Ci 错误 In order to use the Session class you are required to set an encryption key in your config file.

    说明自己没有给session 加密  ,在配置文件config中     $config['encryption_key'] = '2rf3f3fwefwefwef2';

  2. GDI+学习笔记

    7.1.1 GDI+概述 GDI+是微软在Windows 2000以后操作系统中提供的新的图形设备接口,其通过一套部署为托管代码的类来展现, 这套类被称为GDI+的“托管类接口”,GDI+主要提供了以 ...

  3. 第二百七十五节,MySQL数据库安装和介绍

    MySQL数据库安装 一.概述 1.什么是数据库 ? 答:数据的仓库,称其为数据库 2.什么是 MySQL.Oracle.SQLite.Access.MS SQL Server等 ? 答:他们均是一种 ...

  4. MyBatis应用程序根据XML配置文件创建SqlSessionFactory

    MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个Sq ...

  5. EMPTY表示元素不能包含文本,也不能包含子元素

    <?xml version=”1.0″ encoding=”GB2312″?> <!ELEMENT Customer EMPTY> <!ATTLIST Customer称 ...

  6. MFC通过button控制编辑框是否显示系统时间(动态显示)

    1.在dlg.h中public bool flag; static UINT time(void *param); 2.在构造函数中 flag=false; 3.在button的生成函数中 if(fl ...

  7. Swift AVFoundation 二维码扫描和生成

    项目最终不须要支持iOS6了(泪崩),在二维码扫描这一块,可以全然的放弃ZXing库,改用系统的AVFoundation了,拿swift写了个Demo,效果例如以下: github地址:点这里 有关A ...

  8. 有用的Python代码片段

    我列出的这些有用的Python代码片段,为我节省了大量的时间,并且我希望他们也能为你节省一些时间.大多数的这些片段出自寻找解决方案,查找博客和StackOverflow解决类似问题的答案.下面所有的代 ...

  9. iOS开发中多线程基础

    耗时操作演练 代码演练 编写耗时方法 - (void)longOperation { for (int i = 0; i < 10000; ++i) { NSLog(@"%@ %d&q ...

  10. 第1章 部署虚拟环境安装linux系统

    章节简述: 本章节带领读者从0基础了解虚拟机软件与红帽系统,完整的演示了在VM与KVM中安装红帽RHEL7系统的方法. 特别增加了超级实用的Linux系统找回root密码.虚拟机功能增强包.VNC远程 ...