我的 connect6-ng 是在 connect6 的基础上进行的。原项目使用 SVN 做版本控制,但我更喜欢使用 Git。所以我在开始 connect6-ng 时先检出了 SVN 仓库里的最新版本然后取出其中源代码初始化了 Git 仓库,并没有继续 SVN 历史。
董渊老师建议我能把两段历史连接起来,以体现出项目的延续性。老师还帮忙使用 git-svn 在 Ubuntu 9.10 下将 connect6 项目的 SVN 历史转换到了 Git 仓库下:
mkdir connect6.git
cd connect6.git/
git-svn init http://connect6.googlecode.com/svn/ --no-metadata
git config svn.authorsfile ../authors.txt
git-svn fetch
git log
cd ..
tar -zcvf connect6.git.tgz connect6.git/
其中authors.txt的内容为:
qq280833822 = CHEN Shuang <qq280833822@gmail.com>
wanglei = WANG Lei <leopardguo25@gmail.com>
我收到 connect6.git.tgz
后在连接两段历史前,对前一段历史记录做了一些更改:使用 git filter-branch
删除了仓库里的 *.class
文件、/trunk/connect6.jar
文件,因为我觉得这些中间文件或目标文件放在仓库里意义不大。另外,我又将 trunk 目录做成了仓库的根目录,这和后面我的仓库更接近。处理后的仓库目录我命名为 connect6-shrinked/
。
参考 stackoverflow 中这个问题的回答,我使用其中的第三种方法(refs/replace/) 将 SVN 仓库历史转换成的 git 历史添加在了 connect6-ng 提交历史的前面,连上了两段历史。不太详细的步骤如下:
切换到新项目 connect6-ng 的顶层目录,把 connect6-shrinked
加为一个远程仓库,命名为 history:
$ git remote add history file:///path/to/connect6-shrinked/
然后找出 connect6-ng 项目最初的提交(Initial commit)的 SHA1 值,保存到 $TAIL
变量中:
$ TAIL=$(git rev-list --topo-order master | tail -n 1)
接着找出要导入历史的旧项目的最近的一次提交,保存到 $TOP
变量中:
$ TOP=$(git rev-parse --verify history^0)
然后读取 $TAIL
这个 commit 对象的内容:
$ git cat-file commit $TAIL > TAIL_COMMIT
手工编辑 TAIL_COMMIT
这个文件,加入一行 parent $TOP
(其中 $TOP 换成对应的 SHA-1 值),这使得新项目的初始提交有了旧项目的顶部作为父提交。将新的 TAIL_COMMIT
写入仓库:
$ NEW_TAIL=$(git hash-object -t commit -w TAIL_COMMIT)
最后使用 git replace
:
$ git replace $TAIL $NEW_TAIL
这样就连接好了两段历史记录,可以用 git log
等查看。
要把合并后的历史 push 出去,需要在自己仓库 .git/config
文件中对应 remote 部分加一行:
push = +refs/replace/*:refs/replace/*
在合并两段历史之前已经从 connect6-ng 远程仓库 clone 了代码仓库的同学,如果不做修改,还是只能看到较新的一段历史。要想看到旧的SVN导出的历史,需要修改自己的 .git/config
里 origin 部分(或者其他指向 connect6-ng 远程仓库的 remote 分支名)添加一行:
fetch = +refs/replace/*:refs/replace/*
这样之后 git fetch
和 git pull
就可以拉取 refs/replace/
下的后来添加的历史了。
附注:本文参考了董渊老师和我的邮件、stackoverflow 上的回答等,一并感谢。