简体   繁体   中英

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.

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.

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.

The Subversion post-commit hook will include git svn rebase , and the 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.

How can I solve these problems? What will the Subversion and Git hooks look like?

Here is what I've come up with:

  1. Create the git-svn repository if it doesn't exist already:

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

    The master branch is created automatically to track the 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

     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:

     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:

     # 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 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:

     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:

     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:

     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 . I chose to use one non-bare git-svn repository which is also the central repository.

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.

You're better off with just having each developer learn to use git-svn directly. 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. 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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