git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Converting to Git using svn-fe (Was: Speeding up the initial git-svn fetch)

From
Ramkumar Ramachandra <artagnon@gmail.com>
Date
Oct 19, 2010, 06:42 UTC
Message-ID
<20101019064210.GA14309@kytes>
In-Reply-To
<8043579.526738.1287452576766.JavaMail.root@mail.hq.genarts.com>
Hi Stephen,
Stephen Bash writes:
Show 20 quoted lines
> > From: "Ramkumar Ramachandra" <artagnon@gmail.com>
> > Stephen Bash writes:
> > > Extracting SVN's History
> > > ------------------------
> > > First we want to understand SVN's branching/tagging history. Modify
> > > buildSVNTree.pl as necessary, then run
> > >    perl buildSVNTree.pl > svnBranches.txt
> > 
> > > ...
> >
> > Unnecessary
> 
> I'm going to collapse all these comments because I think we're
> coming at this from different angles.  I agree, discovering the
> copies in git is "easy" (albeit an n^2 operation), and git will
> correctly identify file content.  But when I was asked to preserve
> the SVN history, I decided to extract a DAG from SVN and migrate
> that DAG to Git.  Thus the history itself is preserved (sans
> merges), not just the contents of the files.  This is the purpose of
> buildSVNTree.  I can elaborate further if requested.

Yep, they're certainly two different ways to approach the problem: I'd be interested in investigating why it will produce different results. Since we both agree that it's easier (and faster) to do it in Git-land, I'm looking into the the areas where it falls short.

Yes, I understand your script (although I can't actually read Perl :p), but the differences are still not very clear to me.

Show 18 quoted lines
> > > Ah, I should probably mention: svn-fe can produce "empty"
> > > commits, and filterBranch does nothing to remove them. By "empty" I
> > > mean there will be a commit object without any content changes. So
> > > creating a branch/tag in SVN creates a commit, but doesn't change
> > > content. That commit will be part of the new Git history.
> > > Similarly, filterBranch will create git tags from svn tags, but they
> > > point to one of these "empty" commits rather than the branch they
> > > are tagged from. It's not very git-ish, but it seems to work...
> > 
> > Oh, I didn't realize that fast-import allows the creation of empty
> > commits. We should probably fix this?
> 
> To be precise: svn-fe creates commits where
>   git diff-tree treeA treeB
> is empty with treeA being the tree object of /trunk/project and
> treeB being the tree of /branches/foo/project.  This version of my
> tools does not squash these commits, a future version probably will
> (this may cause problems with two-way communication?).

Right, that IS expected behavior. Don't they correspond to separate SVN revisions anyway? Why would you want to squash them?

[Ignore this; see later in the email]
Show 14 quoted lines
> > > filterBranch is probably the longest step of the process; there's a
> > > lot of filtering going on. It will be very verbose on STDOUT, so I
> > > recommend tee'ing to a file or a terminal with infinite scroll back.
> > > It also involves a lot of disk hits (somewhat reduced if $tempdir is
> > > a RAM disk), and potentially a lot of space (it will create a git
> > > repo for every branch/tag in your subversion history). For our
> > > repository this step took about 1.5-2 hours IIRC.
> > 
> > Wow, this really brute-force.
> 
> Yes it is.  If I get around to writing a new version, I'll at least
> advance to a single pass using commit-tree.  Beyond that I'm
> probably into the fast-import code, which I'll happily leave to the
> rest of you :)
*nod*
Show 20 quoted lines
> > > Note that SVN rev to Git commit can be one to many!
> >
> > Unless there's a one-to-one mapping between Git revisions and SVN
> > revisions, a two-way bridge will become very difficult to build. Can
> > you think of any scenarios where a one-to-one mapping doesn't make
> > sense?
> 
> I have 32 SVN revs in my history that touch multiple Git commit
> objects.  The simplest example is
>   svn mv svn://svnrepo/branches/badBranchName svn://svnrepo/branches/goodBranchName
> which creates a single SVN commit that touches two branches
> (badBranchName will have all it's contents deleted, goodBranchName
> will have an "empty commit" as described above).  The more devious
> version is the SVN rev where a developer checked out / (yes, I'm not
> kidding) and proceeded to modify a single file on all branches in
> one commit.  In our case, that one SVN rev touches 23 git commit
> objects.  And while the latter is somewhat a corner case, the former
> is common and probably needs to be dealt with appropriately (it's
> kind of a stupid operation in Git-land, so maybe it can just be
> squashed).

Ouch! Thanks for the illustrative example- I understand now. We have to bend backwards to perform a one-to-one mapping. It's finally struck me- one-to-one mapping is nearly impossible to achieve, and I don't know if it makes sense to strive for it anymore. Looks like Jonathan got it earlier.

> > Grafts and filter-branch. db-svn-filter-root does this more elegantly.
> 
> I found a 'db-svn-filter-root' branch, but it was not entirely
> obvious to me what code I should be looking at...

Um, there's just one commit that deviates from the branch it's based on (but you don't know that, and I should have been clearer): look at contrib/svn-fe/svn-filter-root.py

It's just a minimalistic mapper, but it's fast and done nicely. You can use ideas from it when you're building yours.

Show 13 quoted lines
> > > Hiding 'Deleted' Branches
> > > -------------------------
> > 
> > Hm. You didn't include the history of deleted branches in the main
> > repository. Why? 
> 
> The commit objects are still there, I simply moved the refs to
> refs/hidden/{heads,tags}.  Because my goal was to maintain the full
> SVN history I needed to somehow protect the objects from garbage
> collection.  At the time I didn't know about "git merge -s ours", so
> this strategy achieved my goal of protecting the objects.  In this
> case, the refs are not cloned, but are fetch-able, so I found it to
> be a reasonable solution.
Oh.
Show 10 quoted lines
> > Does it make sense to provide the user an option to
> > exclude some (deleted) branches in the SVN history? It'll make the
> > two-way mapping extremely difficult.
> 
> I think there are cases where a user could say "I don't care about
> dead development branches".  In my current system, all branches,
> even those that do not contribute back to the trunk are saved in the
> hidden namespace.  But I could see users that don't care about some
> or all extraneous branches and would be happy to not convert them or
> to let them be garbage collected.

When I made this comment, I was thinking of the one-to-one mapping. It makes much more sense now.

Show 14 quoted lines
> > Thanks for the interesting and insightful read :)
> 
> I'm glad it's stimulating conversation.  I'm beginning to wonder if
> there might be competing design goals for one-way vs. two-way
> compatibility...  Performance is one place where opinions probably
> greatly differ (I didn't mind taking an extra 30 minutes to mirror
> my SVN repo because it probably saved more than that in
> communication overhead later in the process, but that mirror
> operation is very taxing on your timeline); my exhaustive search of
> all SVN copies is another (I wanted to be *extremely* certain I knew
> about all the misplaced branches/tags, but it's inefficient for a
> casual developer who just wants to interact with an SVN server).
> It's all just food for thought, and I'm happy to carry on the
> conversation from my different point-of-view :)

Ok, I still don't get this part- why mirror at all? Can't all the information be mined out of the in-memory tree that svn-fe builds while parsing the dumpfile? From the SVN-side, all that's required is a streaming dumpfile like the one that `svnrdump dump` produces.

-- Ram
Previous: Stephen BashNext: Stephen Bash
Message 30 of 52 in “Speeding up the initial git-svn fetch”
  1. Matt StumpOct 13, 2010
  2. Stephen BashOct 13, 2010
  3. Matt StumpOct 13, 2010
  4. Stephen BashOct 13, 2010
  5. Converting to Git using svn-fe (Was: Speeding up the initial git-svn fetch)Stephen Bash, Oct 14, 2010
  6. Jonathan NiederOct 14, 2010
  7. Sverre RabbelierOct 14, 2010
  8. Stephen BashOct 15, 2010
  9. Sverre RabbelierOct 15, 2010
  10. Stephen BashOct 16, 2010
  11. Sverre RabbelierOct 17, 2010
  12. David Michael BarrOct 17, 2010
  13. Ramkumar RamachandraOct 18, 2010
  14. Jonathan NiederOct 18, 2010
  15. Ramkumar RamachandraOct 18, 2010
  16. Sverre RabbelierOct 18, 2010
  17. Jonathan NiederOct 18, 2010
  18. Ramkumar RamachandraOct 18, 2010
  19. Sverre RabbelierOct 18, 2010
  20. Jonathan NiederOct 18, 2010
  21. Sverre RabbelierOct 18, 2010
  22. Jonathan NiederOct 18, 2010
  23. Sverre RabbelierOct 18, 2010
  24. Jonathan NiederOct 18, 2010
  25. Sverre RabbelierOct 18, 2010
  26. Jonathan NiederOct 18, 2010
  27. Ramkumar RamachandraOct 19, 2010
  28. Stephen BashOct 19, 2010
  29. Stephen BashOct 19, 2010
  30. Ramkumar RamachandraOct 19, 2010
  31. Stephen BashOct 19, 2010
  32. David Michael BarrOct 19, 2010
  33. Stephen BashOct 19, 2010
  34. Will PalmerOct 20, 2010
  35. Jakub NarebskiOct 20, 2010
  36. Will PalmerOct 20, 2010
  37. Jakub NarebskiOct 20, 2010
  38. mrevilgnomeOct 21, 2010
  39. Jakub NarebskiOct 21, 2010
  40. Stephen BashOct 21, 2010
  41. Will PalmerOct 21, 2010
  42. Stephen BashOct 21, 2010
  43. Jakub NarebskiOct 21, 2010
  44. Stephen BashOct 21, 2010
  45. Jakub NarebskiOct 21, 2010
  46. Stephen BashOct 21, 2010
  47. Jakub NarebskiOct 22, 2010
  48. Jakub NarebskiOct 21, 2010
  49. Jonathan NiederOct 21, 2010
  50. Ramkumar RamachandraOct 20, 2010
  51. Stephen BashOct 20, 2010
  52. Ramkumar RamachandraOct 20, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.