自动同步Subversion仓库和Git仓库

6

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

我想到的方法是在同一网络文件系统上创建一个新的裸的git-svn克隆子版本库,并确保两个仓库始终保持相互更新。

要做到这一点,可能需要为Subversion和新的Git仓库添加后置挂钩,以便每个仓库都可以更新另一个仓库。

Subversion后置挂钩将包括git svn rebase,而Git的后置挂钩将包括git svn dcommit

问题在于,在另一个仓库提交时,必须使用某种锁定机制确保没有人提交到任何一个仓库,因为任何提交之前它们总是需要保持同步。这带来了一些缺点,其中包括提交到Subversion或推送到Git存储库所需的时间(必须等待挂钩完成),以及一些用户可能无法运行git svn(因为它没有安装在他们的计算机上),这意味着他们无法在提交/推送时更新其他存储库。

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

2个回答

13

这是我想到的方法:

  1. 如果还没有创建 git-svn 仓库,则创建它:

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

    master 分支会自动创建来追踪 trunk

  3. 为了避免与 Subversion 追踪分支的名称混淆,将原始 Subversion 分支显示为 remotes/svn/<分支名称>:进入新创建的 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
    
    为每个 Subversion 分支创建一个 Subversion 跟踪分支:
    for BRANCH in $(svn ls <svn_url>/branches/); do
        git branch $BRANCH remotes/svn/$BRANCH
    done
    
  4. 确保在中央Git存储库上没有创建任何非Subversion跟踪的分支:

  5. # 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
    
  6. 允许向中央Git仓库推送:

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

    创建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
    
  8. 重置是必要的,因为否则每次接收后当前分支都会过期。

  9. 最后,创建钩子以从Subversion获取更新:

  10. 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提交后钩子中调用它:

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

可以使用一个裸的中央 Git 存储库和一个中间的非裸 git-svn 存储库来替代使用单个 git-svn 中央存储库,例如在这个答案中。我选择使用一个非裸的 git-svn 存储库作为中央存储库。

任何人都可以使用 Git 克隆 <git_path> 并推送到它,或者使用 Subversion 检出 <svn_url> 并提交到它来参与项目。


git config hooks.denycreatebranch false @Daniel 你是不是想说“true”? - basin
@basin 是的,我想是这样。谢谢。 - Daniel Hershcovich

4
你最好让每个开发人员直接学习使用git-svn。Git和SVN模型之间的阻抗不匹配太大,无法稳健地实现你所需求的功能。即使你想要实现近乎可靠的工作方式,唯一的方法就是实行与git-svn相同的限制,但这会增加更多可能出错的部分。在我看来,你的修订控制系统并不是你想要只有部分可靠性的东西。
或者,如果可能的话,完全放弃SVN并转向Git。

1
我确实计划在某个时候将我的团队全部迁移到Git,但我认为逐步移动git-svn允许的方式是一个巨大的优势。我想其他团队将不得不完全复制我的git-svn克隆,并自己使用git svn dcommit和git svn rebase。 - Daniel Hershcovich
2
如果多个Git仓库正在使用git-svn从中央svn仓库推送/拉取,我相信这就是被推荐的方式,那么在这些Git仓库之间直接推送/拉取将会很困难。这是因为在“git svn rebase”期间,Git分支会被重新设置基础。 - Joshua Tacoma
没错,这也会使未来向纯Git配置的转换更加困难,因为每个人都必须通过创建补丁并将其应用于从新的中央Git存储库克隆的存储库来“迁移”他们的Git存储库。 - Daniel Hershcovich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接