Thread (31 messages) flat view 31 messages, 2 authors, 2016-06-15

Re: Trying to sync two svn repositories with git-svn (repost)

From: Josef Wolf <hidden>
Date: 2016-06-15 22:46:46

On Thu, May 14, 2009 at 02:35:18AM -0400, Avery Pennarun wrote:
By far the sanest thing you could possibly do is to create a central
"public" branch that contains all the common commits, then merge from
that public branch to the site-specific branches, but never merge in
the opposite direction.  In case you happen to make some changes on
the site-specific branches that you want to share, you can just
cherry-pick them; the resulting conflicts when merging back are likely
to be fairly minor.  This would be entirely consistent with git's
normal operations, and would be easy:

   git checkout public
   git cherry-pick stuff   # as rarely as possible; do the work
directly on public if you can

   git checkout svn-1
   git merge --no-ff public
   git svn dcommit

   git checkout svn-2
   git merge --no-ff public
   git svn dcommit

No criss-cross merges, no insanity, no question about whether it's correct.
Indeed, this looks pretty simple.  But AFAICS, this works only when
starting out with a virgin repository.  In my situation, public is
currently empty and have to be constructed from scratch by picking
from the privates.

So it seems I have to sync the privates in a first step and build the
public from that in a second step.

So here's my second plan:
1. instead of doing the cherry-picking in a single repository, it might
   be helpful to do it in separate repositories: one repository for each
   direction.  While there are still two remote svn repositories in each
   svn repository, there is no need for criss-cross anymore.  The flow
   of the data is in one direction and it seems (at least at first glance)
   I can use git-svn-rebase to get a linear history.
2. After the synchronization is done, I would merge the two repositories
   into a third one to create the public repository.  Since this will be
   a pure git environment, I hope that the problems that are caused svn's
   lack of merge support will vanish.
3. Once the public repository exists, create the privates based on that
   public.

Here's my first attempt for the first step:

  # setup a repository template for the synchronization and configure the
  # svn remotes
  mkdir -p svn-sync.templ
  (
    cd svn-sync.templ
    git svn init --stdlayout file:///svn/svn-1
    git config merge.stat true
    for remote in svn-1 svn-2; do
      git config svn-remote.$remote.url      file:///svn/$remote
      git config svn-remote.$remote.fetch    trunk:refs/remotes/$remote/trunk
      git config svn-remote.$remote.branches branches/*:refs/remotes/$remote/*
      git config svn-remote.$remote.tags     tags/*:refs/remotes/$remote/tags/*
      git svn fetch -R $remote
      git checkout -b $remote $remote/trunk
      git tag $remote-orig $remote
    done
    git gc
  )
  
  # now copy the template to create the repositories where the actual
  # synchronization will be done
  cp -a svn-sync.templ  to-svn-1
  cp -a svn-sync.templ  to-svn-2
  
  # move cherries from svn-1 to svn-2 in the to-svn-2 repository
  (
    cd to-svn-2
    git svn fetch svn-1
    git checkout svn-2
    [ pick cherries ]
    git svn dcommit
    git tag -f svn-1-lastmerge svn-1
  )
  
  # move cherries from svn-2 to svn-1 in the to-svn-1 repository
  (
    cd to-svn-1
    git svn fetch svn-2
    git checkout svn-1
    [ pick cherries ]
    git svn dcommit
    git tag -f svn-2-lastmerge svn-2
  )
  
  # time passes
  
  # Move new commits from svn-1 to svn-2
  (
    cd to-svn-2
    git checkout svn-1
    git svn rebase
    git checkout svn-2
    git svn rebase svn-1
    [ more cherries ]
    git svn dcommit
    git tag -f svn-1-lastmerge svn-1
  )
  
  # Move new commits from svn-2 to svn-1
  (
    cd to-svn-1
    git checkout svn-2
    git svn rebase
    git checkout svn-1
    git svn rebase svn-2
    [ more cherries ]
    git svn dcommit
    git tag -f svn-2-lastmerge svn-2
  )

At first glance, this seems to work.  But there's the drawback that I
have to keep track of what have been merged manually.  So there's
certainly room for improvement :)
More as an academic exercise than anything, I did find a way that will
let you do criss-cross merging of all changes on A and B.  I still
don't *really* recommend you use it, because it's extremely error
prone, and there are lots of places where you could get merge
conflicts and then end up in trouble.  (The above simple method, in
contrast, might get conflicts sometimes, but you can just fix them as
you encounter them and be done with it.)

The script below demonstrates how to take branches remote-ab and
remote-ac, and auto-pick their changes (as they happen) into a new
(automatically managed) branch public.  Then it merges public back
into each branch, while avoiding conflicts.  The magic itself happens
in extract() and crossmerge().

If nothing else, this method makes the gitk output far more sane than
the original method.  This is because it doesn't include the history
of 'public' in the site-specific branches.  That was the fundamental
flaw in the method I had identified originally.  You can trick that
original method into working too, but it's stunningly complex.  This
is much more sane, albeit still not really sane.
I will have to play a little bit with this script to get a better
understanding how it works.  But from the description, I got the
impression that it matches my (current) work flow pretty good:
Currently, initial changes are done in some private repository and
propagated to the other repositories from there.  The only exception
is that currently, there's no such thing as a "public" repository.
P.S. Sorry for the mess.  I suppose I should have broken down and
written (or asked for :)) a minimal test case earlier, as it quickly
revealed the problem.
Oh, I have learned a lot in this thread.  And BTW: I _have_ tried to
write a minimal test case several times.  But I simply was not able to
reproduce the problems there.  The problems showed up only on the real
repositories.

Thank you very much Avery!
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help