Skip to content

Instantly share code, notes, and snippets.

@purcell
Created September 22, 2010 12:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save purcell/591602 to your computer and use it in GitHub Desktop.
Save purcell/591602 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
if ARGV.size < 2
puts "Usage: #{$0} <src dir> <dest dir> [branch name]"
puts " CAUTION! Running without a branch name, it will try to copy all 'local' branches, but this is probably not what you want, and is untested. Copy just those branches you really need."
exit
end
src_repo = File.expand_path(ARGV[0])
dest_repo = File.expand_path(ARGV[1])
[src_repo, dest_repo].each do |path|
unless File.exist?(path) && File.directory?(path)
puts "directory #{path} doesn't exist or isn't a directory"
exit
end
end
branch_name = ARGV[2] if ARGV[2]
# There is a 'git' gem, but I didn't want to figure out how to call it to get the functionality I needed. The following
# methods were first tested on the command line, and originally came from this blog post:
# http://www.sanityinc.com/articles/relocating-git-svn-repositories.
# find git branches whose latest commit hasn't been checked into svn
def local_branches(repo_path)
result = []
%x[(cd #{repo_path} && git branch | cut -c3-)].split("\n").each do |branch|
result << branch unless %x[(cd #{repo_path} && git log -1 --pretty=full #{branch})] =~ /git-svn-id:/
end
result
end
# return the git commit sha for the newest commit that *has* been checked into svn
def newest_svn_commit_on_branch(repo_path, branch)
%x[(cd #{repo_path} && git rev-list -n1 #{branch} --grep=git-svn-id:)].strip
end
# return the svn revision number corresponding to a git commit sha
def find_svn_rev_for_commit(repo_path, commit)
%x[(cd #{repo_path} && git svn find-rev #{commit})].strip
end
# return the git commit sha for the commit corresponding to an svn revision
def find_commit_for_svn_rev(repo_path, svn_rev)
%x[(cd #{repo_path} && git rev-list master --grep="git-svn-id:.*@#{svn_rev}")].strip
end
def branch_exists?(repo_path, branch)
%x[(cd #{repo_path} && git branch -M #{branch} #{branch} &> /dev/null)]
$? == 0
end
# create a branch on a git repo from a certain git commit and checkout that branch
def create_branch_and_checkout(repo_path, commit, branch)
%x[(cd #{repo_path} && git checkout -b #{branch} #{commit})]
end
# return a patch containing every commit in a branch on a repo, starting from a certain commit
def create_patch(repo_path, commit, branch)
%x[(cd #{repo_path} && git format-patch --stdout #{commit}..#{branch})]
end
# apply a patch to the current branch of a repo
def apply_patch(repo_path, patch)
%x[(cd #{repo_path} && echo #{patch} | git am)]
end
# create a patch from the src repo and apply it to the dest repo
def copy_branch_commits(src_repo_path, src_branch, src_branch_point, dest_repo_path)
%x[(cd #{src_repo_path} && git format-patch --stdout #{src_branch_point}..#{src_branch}) | (cd #{dest_repo_path} && git am)]
end
def copy_branch(src_repo_path, src_branch, dest_repo_path)
src_branch_point = newest_svn_commit_on_branch(src_repo_path, src_branch)
raise "Couldn't find an svn commit on branch '#{src_branch}' in repo '#{src_repo_path}'" if src_branch_point.empty?
svn_revision = find_svn_rev_for_commit(src_repo_path, src_branch_point)
raise "Couldn't extract the svn revision for commit '#{src_branch_point}' in repo '#{src_repo_path}'" if svn_revision.empty?
dest_branch_point = find_commit_for_svn_rev(dest_repo_path, svn_revision)
raise "Couldn't find the git commit containing svn revision '#{svn_revision}' in repo '#{dest_repo_path}'" if dest_branch_point.empty?
create_branch_and_checkout(dest_repo_path, dest_branch_point, src_branch)
copy_branch_commits(src_repo_path, src_branch, src_branch_point, dest_repo_path)
end
if branch_name
if branch_exists?(dest_repo, branch_name)
puts "** Skipped branch [#{branch_name}] because it already exists"
else
copy_branch(src_repo, branch_name, dest_repo)
end
else
local_branches(src_repo).each do |branch|
if branch_exists?(dest_repo, branch)
puts "** Skipped branch [#{branch}] because it already exists"
else
puts "Copying branch #{branch}"
copy_branch(src_repo, branch, dest_repo)
puts " Copy successful"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment