我和我的小团队在Git工作,而较大的团队使用Subversion。我想安排一个cron作业,每小时将我们的存储库当前HEAD
发布到SVN仓库中的某个目录。
我以为我弄明白了,但我之前写下的食谱现在似乎没有起作用:
git clone ssh://me@gitserver/git-repo/Projects/ProjX px2
cd px2
svn mkdir --parents http://me@svnserver/svn/repo/play/me/fromgit/ProjX
git svn init -s http://me@svnserver/svn/repo/play/me/fromgit/ProjX
git svn fetch
git rebase trunk master
git svn dcommit
以下是我尝试时会发生的事情:
% git clone ssh://me@gitserver/git-repo/Projects/ProjX px2
Cloning into 'ProjX'...
...
% cd px2
% svn mkdir --parents http://me@svnserver/svn/repo/play/me/fromgit/ProjX
Committed revision 123.
% git svn init -s http://me@svnserver/svn/repo/play/me/fromgit/ProjX
Using higher level of URL: http://me@svnserver/svn/repo/play/me/fromgit/ProjX => http://me@svnserver/svn/repo
% git svn fetch
W: Ignoring error from SVN, path probably does not exist: (160013): Filesystem has no item: File not found: revision 100, path '/play/me/fromgit/ProjX'
W: Do not be alarmed at the above message git-svn is just searching aggressively for old history.
This may take a while on large repositories
% git rebase trunk master
fatal: Needed a single revision
invalid upstream trunk
我本来可以发誓这个曾经有过工作,有人有什么建议吗?感谢。
答案 0 :(得分:9)
您的方法存在一些问题:
git svn init
初始化的git repo。 Rebasing假定一个共同的祖先,但如果你的git repo之前是通过git init
初始化的,那么git svn init
将创建第二个根(即无父级)提交,并且从一个尖端到另一个尖端的变基不会没有--onto
的工作。-s
选项git svn init
,这会导致它搜索branches/
,tags/
和trunk/
。正如警告(Using higher level...
)明确指出的那样,这会导致git-svn
配置指向svn repo的顶部,而不是fromgit/ProjX
子目录。trunk
,即使这个分支没有充分的理由存在; git svn init
实际上创建了一个名为remotes/git-svn
的跟踪分支。所以你想要的实际顺序是:
# 1st time only
svn mkdir --parents http://me@svnserver/svn/repo/play/me/fromgit/ProjX
mkdir px2
cd px2
git svn init http://me@svnserver/svn/repo/play/me/fromgit/ProjX
git svn fetch
现在黑客可以在git和svn中同时发生。下次你想从git到svn dcommit
时,你只需:
cd px2
git svn rebase
git svn dcommit
如果您已经初始化了git存储库,开始入侵它,并且需要将该历史记录移植到svn中,那么第一次使用的序列就更难了,因为您需要将所有git历史记录移植到svn中,即使他们没有共同的祖先:
# 1st time only
svn mkdir --parents http://me@svnserver/svn/repo/play/me/fromgit/ProjX
git clone ssh://me@gitserver/git-repo/Projects/ProjX px2
cd px2
git svn init http://me@svnserver/svn/repo/play/me/fromgit/ProjX
git svn fetch
# transplant original git branch onto git-svn branch
root_commit=$( git rev-list --reverse HEAD | head -n1 )
git tag original-git
git reset --hard $root_commit
git reset --soft git-svn
git commit -C $root_commit
# N.B. this bit requires git >= 1.7.2
git cherry-pick $root_commit..original-git
# For older gits you could do
# git rev-list $root_commit..original-git | xargs -n1 git cherry-pick
# or use git rebase --onto but that requires jumping through some
# hoops to stop moving remotes/git-svn.
随后,像以前一样执行相同的svn rebase
和dcommit
。
如果有人想在沙箱中测试此方法,您可以下载my test script。我建议您在运行之前进行可视化安全审核; - )
答案 1 :(得分:4)
我 1 希望将问题分成几个问题:
我的提案基于SubGit 2 。
如果您在svnserver上可以本地访问Subversion存储库,那么设置非常简单,并且在SubGit Book中有详细记录:
我们假设Subversion存储库位于$ SVN_REPO,Git存储库位于$ GIT_REPO。首先,运行以下命令:
$ subgit configure $SVN_REPO
然后调整生成的$ SVN_REPO / conf / subgit.conf文件,如下所示:
[git "ProjX"]
repository = $GIT_REPO
translationRoot = /play/me/fromgit/ProjX
trunk = trunk:refs/heads/master
branches = branches/*:refs/heads/*
shelves = shelves/*:refs/shelves/*
tags = tags/*:refs/tags/*
我对你的案例的translateRoot选项不太确定。该值必须是相对于SVN存储库根目录的项目路径,请指定一个正确的。
不要忘记删除其他'git'部分,因此SubGit不会将SVN存储库的这些部分转换为Git。
您可以选择调整$ SVN_REPO / conf / authors.txt文件,以指定Git提交者名称应如何转换为SVN作者姓名:
SvnAuthor = Git Committer <git.committer@company.com>
最后,将您的Git存储库导入SVN:
$ subgit install $SVN_REPO
此时$ SVN_REPO和$ GIT_REPO有SubGit安装的特殊挂钩。 Subversion和Git服务器会在每次传入修改时触发这些挂钩。这样SubGit就会自动同步SVN和Git存储库。创建的镜像是双向的,即一些开发人员可以使用SVN客户端,其他人可以选择任何Git客户端。
如果您不需要这种同步,请将其禁用:
$ subgit uninstall [--purge] $SVN_REPO
如果您没有Subversion存储库的本地访问权限,那么事情会变得更加棘手但仍然可能:
首先,将整个SVN存储库提取到您的计算机,以便您可以在本地访问它:
$ svnadmin create repo
$ svnrdump dump http://me@svnserver/svn/repo | svnadmin load repo
现在请记住获取的存储库的最新版本:
$ svn info file:///path/to/repo
Path: repo
URL: file:///path/to/repo
Repository Root: file:///path/to/repo
Repository UUID: cbc56e97-717f-4d50-b705-cb6de2c836eb
Revision: $LATEST_REVISION
Node Kind: directory
Last Changed Author: SvnAuthor
Last Changed Rev: $LATEST_REVISION
Last Changed Date: 2012-10-27 14:01:38 +0200 (Sat, 27 Oct 2012)
然后重复前一个子句中的所有步骤。因此,本地SVN存储库应该存储导入的Git历史记录。
最后,将生成的历史记录发送回SVN:
$ svnsync initialize http://me@svnserver/svn/repo file://path/to/repo
$ svn propset --revprop -r0 svn:sync-last-merged-rev $LATEST_REVISION http://me@svnserver/svn/repo
$ svnsync synchronize http://me@svnserver/svn/repo
请注意,远程存储库必须启用 pre-revprop-change 挂钩才能使svnsync正常工作。
如果您对Subversion存储库具有本地访问权限,则可以在安装SubGit后保持其工作。正如我已经提到的那样,它会在将更改发送到其中一个存储库后立即进行转换,因此在这种情况下不需要维护任何cron作业。
如果您对Subversion存储库没有本地访问权限但仍想使用SubGit,我建议您使用svnsync来同步svnserver上托管的SVN存储库和SubGit 3控制的SVN存储库
您可以在this HOW-TO找到有关如何设置此类镜像的指南。
请注意,对于这种情况,您的项目应该有一个单独的Subversion存储库,否则很难保持svnsync正常工作。
如果您因任何原因决定使用git-svn
,我建议您在使用SubGit导入Git历史记录后创建一个新的Subversion存储库:
$ git svn init -s http://me@svnserver/svn/repo/play/me/fromgit/ProjX
$ git svn fetch
根据我的经验,将Git历史记录导入SVN并不是git-svn
的目的。另一方面,SubGit处理得很好。
1 完全披露:我是SubGit开发人员之一。
2 SubGit是一种商业产品,但对于拥有多达10名提交者的小型团队而言是免费的。我认为它适用于你的情况。
3 我们的团队正在开发SubGit 2.0,它支持位于不同主机上的SVN和Git存储库的同步。基本上,您可以在任何地方创建Git存储库,并使用指定的SVN URL将SubGit安装到其中。之后,您可以使用任何这些存储库 - 更改会在它们之间自动转换。
我们将发布具有该功能的EAP版本,因此可以尽快尝试。