Skip to content

Instantly share code, notes, and snippets.

@alloy
Forked from evanphx/git2svn.rb
Created March 11, 2009 22:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alloy/77795 to your computer and use it in GitHub Desktop.
Save alloy/77795 to your computer and use it in GitHub Desktop.
require 'time'
git = ARGV.shift
svn = ARGV.shift
class Git2SVN
def initialize(git, svn)
@git = git
@svn = svn
@repo = File.expand_path File.join(@svn, "repo")
@scratch = File.expand_path File.join(@svn, "scratch")
@rev_data = File.join(@svn, "last_revs.yaml")
end
def sh(cmd)
puts "CMD: #{cmd}"
system cmd
end
def create_svn
return if File.exist?(@repo)
sh "svnadmin create #{@repo}"
sh "echo '#!/bin/sh\\nexit 0\\n' > #{@repo}/hooks/pre-revprop-change"
sh "chmod a+x #{@repo}/hooks/pre-revprop-change"
end
def create_scratch
return if File.exist?(@scratch)
clone_git
sh "svn co file://#{@repo} tmp"
sh "mv tmp/.svn #{@scratch}"
end
def clone_git
sh "git clone #{@git} #{@scratch}"
end
def enter
Dir.chdir @scratch
end
def load_data
if File.exists?(@rev_data)
@last_revs = YAML.load @rev_data
else
@last_revs = []
end
@current_revs = `git rev-list --all`.split("\n").reverse
end
def save_data
File.open(@rev_data, "w") do |f|
f << @last_revs.to_yaml
end
end
def outstanding_revs
@current_revs - @last_revs
end
def set_rev(rev)
sh "git reset --hard #{rev}"
end
Commit = Struct.new(:hash, :when, :tree, :parent, :author, :committer, :log)
def current_info
data = `git cat-file commit HEAD`.split("\n")
c = Commit.new
c.hash = `git rev-parse HEAD`.strip
c.tree = data.shift.split(" ",2).last
c.parent = data.shift.split(" ",2).last
com = data.shift.split(" ",2)
m = /(.*) (\d+) [+-]\d+/.match(com.last)
c.author = m[1]
c.when = Time.gm *Time.at(m[2].to_i).to_a
c.committer = data.shift.split(" ",2).last
data.shift
c.log = data.join("\n")
return c
end
def write_log(c)
File.open("current-log", "w") do |f|
f.puts c.log
end
end
def fix_props(c, rev)
sh "svn propset -r #{rev} --revprop svn:author '#{c.author}'"
sh "svn propset -r #{rev} --revprop svn:date '#{c.when.xmlschema(6)}'"
sh "svn propset -r #{rev} --revprop git:hash '#{c.hash}'"
end
def drive_changes
dirs = {}
stats = `git diff-tree --name-status -t -r --root HEAD`.split("\n")
stats.shift
stats.each do |line|
stat, name = line.split(/\s+/, 2)
case stat
when "A"
dir = File.dirname(name).split("/")
dir.shift if dir.first == "."
path = nil
until dir.empty?
if path.nil?
path = dir.shift
else
path = File.join(path, dir.shift)
end
unless dirs[path]
if /^\?/.match(`svn status '#{path}'`)
`svn add '#{path}' 2>&1`
end
dirs[path] = true
end
end
`svn add --force '#{name}' 2>&1`
when "D"
`svn rm '#{name}'`
when "M", "T"
# noop
else
raise "Unknown status '#{stat}'"
end
end
end
def update
sh "git pull"
revs = outstanding_revs()
revs.each_with_index do |rev, idx|
puts "=== #{rev} (#{idx + 1}/#{revs.size}) ==="
set_rev rev
drive_changes()
c = current_info()
write_log(c)
m = /Committed revision (\d+)/.match(`svn commit -F current-log`)
fix_props(c, m[1].to_i) if m
end
end
end
g = Git2SVN.new "~/git/test", "."
g.create_svn
g.create_scratch
g.enter
g.load_data
g.update
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment