Created
September 22, 2010 12:48
-
-
Save purcell/591602 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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