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

时间:2011-04-07 20:09:35

标签: svn git git-svn githooks svn-hooks

我的项目在网络文件系统上有一个Subversion存储库,一个新团队希望使用Git访问它,并能够提交它并从中获取更新。

我想到的是在同一个网络文件系统上创建Subversion存储库的新的git-svn克隆,并确保这两个存储库始终是最新的。

这样做的方法可能是为Subversion和新的Git存储库添加一个post-commit挂钩,每个存储库都会更新另一个存储库。

Subversion后提交挂钩将包含git svn rebase,而Git包含git svn dcommit

问题是我必须使用某种锁来确保没有人提交到任何一个存储库,而其他人也被提交,因为它们总是必须在任何提交之前保持同步。这有几个缺点,其中包括提交Subversion或推送到Git存储库所需的时间(它必须等待钩子完成),以及某些用户可能无法运行的事实{{1 (因为它没有安装在他们的机器上),这意味着他们在提交/推送时无法更新其他存储库。

我该如何解决这些问题? Subversion和Git钩子会是什么样子?

2 个答案:

答案 0 :(得分:13)

以下是我的想法:

  1. 创建git-svn存储库(如果它尚不存在):

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

    自动创建master分支以跟踪trunk

  2. 为避免使用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. 为每个Subversion分支创建一个Subversion跟踪分支:

    for BRANCH in $(svn ls <svn_url>/branches/); do
        git branch $BRANCH remotes/svn/$BRANCH
    done
    
  4. 确保在中央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. 允许推送到中央Git存储库:

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

    创建post-receive hook以重置并将提交发送到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
    

    重置是必要的,因为否则当前分支在每次接收后都是过时的。

  6. 最后,创建钩子以从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
    

    从Subversion post-commit hook中调用它:

    cat <svn_path>/hooks/post-commit
    
        cd <git_path>
        . .git/hooks/svn-rebase-all
    
    chmod +x <svn_path>/hooks/post-commit
    
  7. 不是使用单个git-svn中央存储库,而是可以使用裸中央Git存储库和中间非裸git-svn存储库,如this answer中所示。 我选择使用一个非裸git-svn存储库,它也是中央存储库。

    任何人都可以使用Git处理项目,方法是克隆<git_path>并推送到它,或者通过签出<svn_url>并使用它来使用Subversion。

答案 1 :(得分:4)

让每个开发人员学会直接使用git-svn,你会感觉更好。 git和SVN模型之间存在太多的阻抗不匹配,无法稳健地实现您所需的功能。你可以让它几乎可靠地工作的唯一方法是制定git-svn所具有的相同类型的限制,但有更多移动部件可能会破坏。在我看来,你的修订控制系统并不是你想要部分可靠的东西。

或者只是完全抛弃SVN并尽可能地移动到git。