public
Last active

  • Download Gist
git-svn-copy-local-branches
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
#!/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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.