DEV Community

Max Pixel
Max Pixel

Posted on

Exploring Two-Way Sync Between SVN and Plastic SCM

I'm often asked by customers to do work on some project that is being tracked in SVN. Having been spoiled by Plastic SCM's very well-thought-out system, SVN's crufty paradigm soup of fragility and slowness is mind-numbingly infuriating. I looked into what I could do to work with Plastic on my end without any inconvenience or interruption to the customer (that is to say, without creating any additional inconvenience or interruption beyond that which is already imposed upon them by SVN).

The simplest approach is, of course, to point an SVN client and a Plastic client to the same workspace folder, managing back-and-forth manually: Pull latest in SVN, commit in Plastic; merge to main in Plastic, commit in SVN. I thought it would be worth exploring the possibility of a solution that would actually maintain the entire history of the SVN repository in Plastic, so that I can see annotate history in my IDE, see incremental Blueprint change diffs in Unreal Engine, etc. Really, so that I can use it as proper and fully-featured version control rather than just a file transfer mechanism with an undo feature.

I quickly found Plastic's guest blog post about migrating from SVN using git-svn and then Git Sync (Git Sync being Plastic's built-in feature to synchronize between Plastic and Git). I started following the steps in the post, but found that git svn was a bit too cumbersome - there were a lot of things that left me thinking, "this could really use a script to simplify the process and improve the default behavior". I figured, if I was thinking that, then somebody has probably already thought the same thing and created those scripts.

I found svn2git (in particular, this implementation of svn2git in a Docker container with a nice config file and automatic recurring sync). How about that? Not only had somebody already written the scripts, but they happen to be my crazy internet doppleganger. I didn't even know I had one! Touche, Crazy Max, touche.

After making several fixes to Crazy's setup, and modifying it to use git:// instead of ssh://, I have SVN to Git to Plastic working very well. The svn2git container is configured to push each repo to a git daemon container (eventually I would like to figure out how to avoid this data redundancy - to have the git daemon use the same .git folders as svn2git - but currently one seems to require bare while the other requires working copy). I then use Git Sync from the Plastic GUI (I plan to automate this at an interval, too).

I realized that I could ditch the git daemon, and instead use Plastic GitServer, configuring svn2git to push directly to that, instead. Having read that Plastic Git Server maintains two copies of the data (Git format and Jet format, I assume), I decided to stick with the git daemon middleman in favor leaving open the possibility of consolidating the git daemon and git svn "databases" (I doubt I can have git svn and Plastic GitSync use the same .git files as easily).

Once I had this working, the next step was to figure out how I would get data going back in the other direction. My team prefers branch-per-task, but most SVN-using customers tend to prefer big commits to trunk as the default mode of operation. Again, there is a very "straightforward" solution: I can point SVN to the same workspace and commit to it while Plastic is on the feature branch; but even if the customer doesn't care about task branches and granular commits, wouldn't it be much better if I could see those merges in Plastic? Especially so with Plastic GUI's feature to show merged vs unmerged branches as different colors in the graph view.

So, let's say that I merge our task branch into /main, sync that to master in the intermediate Git repo, pull it into the git svn working copy, and then finally dcommit it to SVN. Given that Git Sync syncs everything without any ability to filter branches, I must expect that my task-branches and merge-commits will be synced as such into Git. This is an unfortunate waste of hard disk space, but it's not a dealbreaker as long as the Git-to-SVN push treats the merge-commit as a regular one. After reading about git svn dcommit's behavior when merges are present, it appears that this is exactly how git svn behaves by default - yay! However, this action will replace the original merge-commit with a new one. My past experience tells me that replacing commits in Git causes Plastic to fail subsequent Git Sync operations unless the conflicting changeset is removed from Plastic. I was still willing to give it a shot, however...

At some point in the past, some error message that I got from Plastic brought to my attention the existence of %LOCALAPPDATA%\plastic4\sync\git. I poked around in there and found that cset.mapping.conf contains very straightforward association between Plastic changesets and Git commits. I figured I could potentially work around any issues by replacing the mege-commit git-hash with the svn-rebase git-hash in this file.

To my surprise, however, I didn't end up needing to touch those hidden files. When I ran a Git Sync after everything else, Plastic brought the replacement merge commit in alongside the existing one. The resulting forked head prevented it from pushing the first merge-commit back again. I was surprised again to see that the replacement commit appeared with an identical merge link! I didn't expect this having read that git svn dcommit destroys merge links, but it seems that the Git community has fixed that shortcoming. At that point, all I had to do was to delete the original merge-commit, leaving the replacement one.

I'm left with a working bi-directional system. It will require a bit of additional automation before I'm totally satisfied with it, but it's already sufficient to begin saving myself and my team some time and agony.

Top comments (1)

Collapse
 
kfsone profile image
Oliver Smith

As part of looking as options for moving to a more modern workflow for a geo-diverse dev team that's been svn based, I'd previously used Phabricator, because it gives you a means to dvcs ephemeral branching to protect real branches/Trunk, and was the only github-style SCM that still seemed to support git, and I'd used it at Facebook. Then we looked at Perforce, and I spent months working with the P4 people helping them solve issues with importing our repos.

During that process, I came across TmateSoft's "SubGit" which I eventually started to use in anger while looking at GitLab and BitBucket, and for the last year I've been using SVN<--subgit-->BitBucket server instance glitch free. Given I'm not particularly comfortable with git, still, that's been quite the experience.

But really I'm just wondering if you'd subgit between svn and plastic, or if you had any thoughts on whether that might be a viable alternative to svn <--svn2git--> plastic?