将Git存储库发布到SVN

时间:2012-10-16 21:51:12

标签: git svn mirroring

我和我的小团队在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

我本来可以发誓这个曾经有过工作,有人有什么建议吗?感谢。

2 个答案:

答案 0 :(得分:9)

您的方法存在一些问题:

  • 您似乎使用的是预先存在的git repo,而不是通过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 rebasedcommit

如果有人想在沙箱中测试此方法,您可以下载my test script。我建议您在运行之前进行可视化安全审核; - )

答案 1 :(得分:4)

1 希望将问题分成几个问题:

  1. 将Git历史记录导入现有的Subversion存储库;
  2. 之后自动同步Git和SVN存储库。
  3. 我的提案基于SubGit 2

    将Git存储库导入SVN

    1. 如果您在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
      
    2. 如果您没有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正常工作。

    3. Git和SVN存储库的自动同步

      1. 如果您对Subversion存储库具有本地访问权限,则可以在安装SubGit后保持其工作。正如我已经提到的那样,它会在将更改发送到其中一个存储库后立即进行转换,因此在这种情况下不需要维护任何cron作业。

      2. 如果您对Subversion存储库没有本地访问权限但仍想使用SubGit,我建议您使用svnsync来同步svnserver上托管的SVN存储库和SubGit 3控制的SVN存储库

        您可以在this HOW-TO找到有关如何设置此类镜像的指南。

        请注意,对于这种情况,您的项目应该有一个单独的Subversion存储库,否则很难保持svnsync正常工作。

      3. 如果您因任何原因决定使用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处理得很好。

      4. 1 完全披露:我是SubGit开发人员之一。

        2 SubGit是一种商业产品,但对于拥有多达10名提交者的小型团队而言是免费的。我认为它适用于你的情况。

        3 我们的团队正在开发SubGit 2.0,它支持位于不同主机上的SVN和Git存储库的同步。基本上,您可以在任何地方创建Git存储库,并使用指定的SVN URL将SubGit安装到其中。之后,您可以使用任何这些存储库 - 更改会在它们之间自动转换。

        我们将发布具有该功能的EAP版本,因此可以尽快尝试。