Skip to content

Instantly share code, notes, and snippets.

@squibobblepants
Forked from jimfulton/svn2git.py
Last active December 13, 2015 23:58
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save squibobblepants/4995065 to your computer and use it in GitHub Desktop.
Save squibobblepants/4995065 to your computer and use it in GitHub Desktop.
##############################################################################
#
# 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.
"""
bitbuckethelp="""
Create a bitbucket repository. The argument is a string of the form
user/password
Where user is either your username or the organisation user name.
curl must be installed if you use this.
"""
parser.add_option('--github', '-g', help=githelp)
parser.add_option('--bitbucket', '-b', help=bitbuckethelp)
parser.add_option('--private', '-p', action='store_true',
help="Create a private repository (bitbucket only currently)")
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 options.private and options.github:
raise NotImplementedError(
"Currently only --bitbucket supports --private")
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 options.bitbucket:
bitbucket_user, bitbucket_password = options.bitbucket.split('/', 1)
is_private = 0
if options.private:
is_private = 1
s('curl -k -X POST --user "%s:%s" '
'"https://api.bitbucket.org/1.0/repositories" -d "name=%s" '
'-d "is_private=%d" -d "scm=git"'
% (bitbucket_user, bitbucket_password, name, is_private))
s('git remote add origin ssh://git@bitbucket.org/%s/%s.git'
% (bitbucket_user, name))
s("git push -u origin '*' --tags")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment