Skip to content

Instantly share code, notes, and snippets.

@jimfulton
Created January 31, 2013 15:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jimfulton/4683891 to your computer and use it in GitHub Desktop.
Save jimfulton/4683891 to your computer and use it in GitHub Desktop.
Here's a Python script I wrote to convert subverstion projects to git. I wrote it after I had some problems with the Ruby svn2git program. Like the Ruby svn2git program, it's a fairly thin wrapper over the git svn plugin, which does most of the heavy lifting. This isn't "finished", but it's good enough for most cases and I doubt I'll do any more…
##############################################################################
#
# Copyright (c) 2012 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""%prog [options] subversion_url
svn to git conversion helper
Based loosely on the svn2git ruby tool.
You must have git and the svn git plugin installed.
A repository directory will be created with a name derived from the
subversion URL.
The subversion URL must point to a subversion project with a standard
layout, with trunk, branches, and tags.
"""
import optparse
parser = optparse.OptionParser(__doc__)
githelp="""
Create a github repository. The argument is a string of the form
DEST/token. where DEST is either 'users/USERNAME' or 'orgs/ORGNAME' and
token is a github OAuth token:
https://help.github.com/articles/creating-an-oauth-token-for-command-line-use
curl must be installed if you use this.
"""
parser.add_option('--github', '-g', help=githelp)
parser.add_option('--restart', '-r', action='store_true',
help="Restart after fetch times out")
parser.add_option(
'--authors', '-a',
help = 'Path to authors.txt file (required)')
import os
import sys
import xml.etree.ElementTree
def s(command):
print 'Running command:', command
if os.system(command):
raise SystemError
def r(command):
f = os.popen(command)
result = f.read()
f.close()
return result
def main(args=None):
if args is None:
args = sys.argv[1:]
options, args = parser.parse_args(args)
url, = args
if url.endswith('/'):
url = url[:-1]
name = url.rsplit('/', 1)[1]
if not options.restart:
os.mkdir(name)
os.chdir(name)
if not options.restart:
s('git svn init --no-metadata -s %s' % url)
assert options.authors
s('git config svn.authorsfile %s' % options.authors)
s('git svn fetch')
for tag in r('svn ls %s/tags' % url).strip().split():
if tag[-1] == '/':
tag = tag[:-1]
f = os.popen('svn log --xml -l1 %s/tags/%s' % (url, tag))
date = xml.etree.ElementTree.ElementTree(
file=f).find('logentry').find('date').text
f.close()
s("GIT_COMMITTER_DATE=%r git tag %r 'tags/%s'" % (
date.replace('T', ' ').replace('Z', ' +0000'),
tag, tag,
))
for branch in r('svn ls %s/branches' % url).strip().split():
if branch[-1] == '/':
branch = branch[:-1]
s('git checkout %s' % branch)
s('git checkout -b %s' % branch)
# Not sure if this is necessary, or sufficient. The Ruby
# version ran into trouble when git left files around between
# branche checkouts. I haven't had the problem, with this
# script, which unlike the Ruby version, doesn't process
# deleted branches.
s('git reset --hard HEAD')
s('git checkout trunk')
s('git branch -D master')
s('git checkout -f -b master')
s('git branch -d -r trunk')
s('git gc')
if options.github:
github_dest, github_token = options.github.rsplit('/', 1)
if github_dest.startswith('users/'):
github_user = github_dest[6:]
github_dest = 'user'
else:
assert github_dest.startswith('orgs/')
github_user = github_dest.split('/')[1]
s('curl -v -XPOST -H "Authorization: token %s"'
' https://api.github.com/%s/repos -d '
"""'{"name": "'"%s"'"}'"""
% (github_token, github_dest, name))
s('git remote add origin ssh://git@github.com/%s/%s.git'
% (github_user, name))
s("git push -u origin '*' --tags")
if __name__ == '__main__':
main()
@squibobblepants
Copy link

I made a fork to add support for Bitbucket too, including private repository creation (Bitbucket only): https://gist.github.com/squibobblepants/4995065

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment