简体   繁体   English

自动同步Subversion存储库和Git存储库

[英]Automatically synchronizing a Subversion repository and a Git repository

My project has a Subversion repository on a network file system, and a new team would like to access it using Git, and be able to commit to it and get updates from it. 我的项目在网络文件系统上有一个Subversion存储库,一个新团队希望使用Git访问它,并能够提交它并从中获取更新。

What I have in mind is to create a new bare git-svn clone of the Subversion repository on the same network file system, and make sure the two repositories are always up to date with respect to each other. 我想到的是在同一网络文件系统上创建Subversion存储库的新裸git-svn克隆,并确保这两个存储库始终相互更新。

The way to do this is probably to add a post-commit hook for both Subversion and the new Git repository, that will each update the other's repository. 这样做的方法可能是为Subversion和新的Git存储库添加一个post-commit钩子,它们将更新另一个的存储库。

The Subversion post-commit hook will include git svn rebase , and the Git one git svn dcommit . Subversion post-commit钩子将包括git svn rebase ,以及Git one git svn dcommit

The problem is that I will have to use some kind of lock to make sure no one commits to either repository while other is also being committed to, because they always have to be in sync before any commit. 问题是我将不得不使用某种锁来确保没有人提交到任何一个存储库,而其他人也被提交,因为它们总是必须在任何提交之前保持同步。 This has several disadvantages, among them the time it will take to commit to Subversion or to push to the Git repository (it has to wait for the hook to finish), and the fact that some users may not be able to run git svn (because it's not installed on their machine), which means they can't update the other repository when committing/pushing. 这有几个缺点,其中包括提交Subversion或推送到Git存储库所需的时间(它必须等待钩子完成),以及一些用户可能无法运行git svn的事实(因为它没有安装在他们的机器上),这意味着他们在提交/推送时无法更新其他存储库。

How can I solve these problems? 我该如何解决这些问题? What will the Subversion and Git hooks look like? Subversion和Git钩子会是什么样子?

Here is what I've come up with: 这是我提出的:

  1. Create the git-svn repository if it doesn't exist already: 如果git-svn存储库不存在,请创建它:

     git svn init --std-layout <svn_url> <git-svn_path> 

    The master branch is created automatically to track the trunk . 将自动创建master分支以跟踪trunk

  2. To avoid name ambiguities with Subversion-tracking branches, make the original Subversion branches show as remotes/svn/<branch name> : go to the newly-created git-svn repository and run 为避免使用Subversion跟踪分支出现名称歧义,请将原始Subversion分支显示为remotes/svn/<branch name> :转到新创建的git-svn存储库并运行

     git config svn-remote.svn.fetch trunk:refs/remotes/svn/trunk git config svn-remote.svn.branches branches/*:refs/remotes/svn/* git config svn-remote.svn.tags tags/*:refs/remotes/svn/tags/* rm .git/refs/remotes/* git svn fetch 
  3. Create a Subversion-tracking branch for each Subversion branch: 为每个Subversion分支创建一个Subversion跟踪分支:

     for BRANCH in $(svn ls <svn_url>/branches/); do git branch $BRANCH remotes/svn/$BRANCH done 
  4. Make sure no non-Subversion-tracking branches are created on the central Git repository: 确保在中央Git存储库上没有创建非Subversion跟踪分支:

     # Used by hooks/update: git config hooks.denyCreateBranch true git config hooks.allowDeleteBranch false cp .git/hooks/update.sample .git/hooks/update chmod +x .git/hooks/update 
  5. Allow pushing to the central Git repository: 允许推送到中央Git存储库:

     git config receive.denyCurrentBranch ignore git config receive.denyNonFastForwards true git config push.default current 

    And create the post-receive hook to reset and send the commits to Subversion: 并创建post-receive挂钩以重置并将提交发送到Subversion:

     cat .git/hooks/post-receive #!/bin/sh date >> receive.log git reset --quiet --hard while read LINE do BRANCH=${LINE##*/} echo Updating $BRANCH git checkout --quiet --force $BRANCH git svn dcommit done 2>&1 | tee -a receive.log git checkout --quiet --force master chmod +x .git/hooks/post-receive 

    The reset is necessary, because otherwise the current branch is out-of-date after each receive. 重置是必要的,因为否则当前分支在每次接收后都是过时的。

  6. Finally, create the hook to get updates from Subversion: 最后,创建钩子以从Subversion获取更新:

     cat .git/hooks/svn-rebase-all #!/bin/sh date >> .git/svn-rebase.log git reset --quiet --hard for REF in .git/refs/heads/* do BRANCH=${REF##*/} echo Updating $BRANCH git checkout --quiet --force $BRANCH git svn rebase done 2>&1 | tee -a .git/svn-rebase.log git checkout --quiet --force master chmod +x .git/hooks/svn-rebase-all 

    And call it from the Subversion post-commit hook: 并从Subversion post-commit钩子调用它:

     cat <svn_path>/hooks/post-commit cd <git_path> . .git/hooks/svn-rebase-all chmod +x <svn_path>/hooks/post-commit 

Instead of using a single git-svn central repository, one can use a bare central Git repository and an intermediate non-bare git-svn repository, as in this answer . 可以使用裸中央Git存储库和中间非裸git-svn存储库,而不是使用单个git-svn中央存储库,如本答案所示 I chose to use one non-bare git-svn repository which is also the central repository. 我选择使用一个非裸git-svn存储库,它也是中央存储库。

Anyone can work on the project using Git by cloning <git_path> and pushing to it, or using Subversion by checking out <svn_url> and committing to it. 任何人都可以使用Git通过克隆<git_path>并推送到它来工作,或者通过签出<svn_url>并提交它来使用Subversion。

You're better off with just having each developer learn to use git-svn directly. 只需让每个开发人员学会直接使用git-svn你就会变得更好。 There's simply too much of an impedance mismatch between the git and SVN models to be able to robustly implement what you are looking for. git和SVN模型之间存在太多的阻抗不匹配,无法稳健地实现您所需的功能。 The only way you could get it to work even nearly reliably would be to enact the same sort of restrictions that git-svn would have, but with more moving parts that could break. 你可以让它几乎可靠地工作的唯一方法是制定与git-svn相同的限制,但是有更多移动部件可能会破坏。 In my opinion, your revision control system is not the sort of thing that you want to be just partially reliable. 在我看来,你的修订控制系统并不是你想要部分可靠的东西。

Alternatively just ditch SVN altogether and move all the way to git, if possible. 或者,如果可能的话,只需完全抛弃SVN并一直移动到git。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM