nirvdrum-svn2git 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +126 -0
- data/Rakefile +44 -0
- data/VERSION.yml +4 -0
- data/bin/svn2git +37 -0
- data/lib/svn2git/migration.rb +120 -0
- data/lib/svn2git.rb +2 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
== svn2git
|
2
|
+
|
3
|
+
+svn2git+ is a tiny utility for migrating projects from Subversion to Git
|
4
|
+
while keeping the trunk, branches and tags where they should be. It uses
|
5
|
+
git-svn to clone an svn repository and does some clean-up to make sure
|
6
|
+
branches and tags are imported in a meaningful way, and that the code checked
|
7
|
+
into master ends up being what's currently in your svn trunk rather than
|
8
|
+
whichever svn branch your last commit was in.
|
9
|
+
|
10
|
+
=== Examples
|
11
|
+
|
12
|
+
Say I have this code in svn:
|
13
|
+
|
14
|
+
trunk
|
15
|
+
...
|
16
|
+
branches
|
17
|
+
1.x
|
18
|
+
2.x
|
19
|
+
tags
|
20
|
+
1.0.0
|
21
|
+
1.0.1
|
22
|
+
1.0.2
|
23
|
+
1.1.0
|
24
|
+
2.0.0
|
25
|
+
|
26
|
+
git-svn will go through the commit history to build a new git repo. It will
|
27
|
+
import all branches and tags as remote svn branches, whereas what you really
|
28
|
+
want is git-native local branches and git tag objects. So after importing this
|
29
|
+
project I'll get:
|
30
|
+
|
31
|
+
$ git branch
|
32
|
+
* master
|
33
|
+
$ git branch -a
|
34
|
+
* master
|
35
|
+
1.x
|
36
|
+
2.x
|
37
|
+
tags/1.0.0
|
38
|
+
tags/1.0.1
|
39
|
+
tags/1.0.2
|
40
|
+
tags/1.1.0
|
41
|
+
tags/2.0.0
|
42
|
+
trunk
|
43
|
+
$ git tag -l
|
44
|
+
[ empty ]
|
45
|
+
|
46
|
+
After svn2git is done with your project, you'll get this instead:
|
47
|
+
|
48
|
+
$ git branch
|
49
|
+
* master
|
50
|
+
1.x
|
51
|
+
2.x
|
52
|
+
$ git tag -l
|
53
|
+
1.0.0
|
54
|
+
1.0.1
|
55
|
+
1.0.2
|
56
|
+
1.1.0
|
57
|
+
2.0.0
|
58
|
+
|
59
|
+
Finally, it makes sure the HEAD of master is the same as the current trunk of
|
60
|
+
the svn repo.
|
61
|
+
|
62
|
+
=== Installation
|
63
|
+
|
64
|
+
Make sure you have git installed, then install the gem:
|
65
|
+
|
66
|
+
$ sudo apt-get install git-core git-svn
|
67
|
+
$ sudo gem install svn2git
|
68
|
+
|
69
|
+
=== Usage
|
70
|
+
|
71
|
+
There are a number of ways in which you can create a git repo from an existing
|
72
|
+
svn repo. The differentiating factor is the svn repo layout. Below is an
|
73
|
+
enumerated listing of the varying supported layouts and the proper way to
|
74
|
+
create a git repo from a svn repo in the specified layout.
|
75
|
+
|
76
|
+
1. The svn repo is in the standard layout of (trunk, branches, tags) at the
|
77
|
+
root level of the repo.
|
78
|
+
|
79
|
+
$ svn2git http://svn.yoursite.com/path/to/repo trunk=trunk branches=branches tags=tags
|
80
|
+
|
81
|
+
2. The svn repo is NOT in standard layout and has only a trunk and tags at the
|
82
|
+
root level of the repo.
|
83
|
+
|
84
|
+
$ svn2git http://svn.yoursite.com/path/to/repo trunk=trunk tags=tags
|
85
|
+
|
86
|
+
3. The svn repo is NOT in standard layout and has only a trunk and branches at
|
87
|
+
the root level of the repo.
|
88
|
+
|
89
|
+
$ svn2git http://svn.yoursite.com/path/to/repo trunk=trunk branches=branches
|
90
|
+
|
91
|
+
4. The svn repo is NOT in standard layout and has only a trunk at the root
|
92
|
+
level of the repo.
|
93
|
+
|
94
|
+
$ svn2git http://svn.yoursite.com/path/to/repo trunk=trunk
|
95
|
+
|
96
|
+
5. The svn repo is NOT in standard layout and has no trunk, branches, or tags
|
97
|
+
at the root level of the repo. Instead the root level of the repo is
|
98
|
+
equivalent to the trunk and there are no tags or branches.
|
99
|
+
|
100
|
+
$ svn2git http://svn.yoursite.com/path/to/repo rootistrunk=true
|
101
|
+
|
102
|
+
The above will create a git repository in the current directory with the git
|
103
|
+
version of the svn repository. Hence, you need to make a directory that you
|
104
|
+
want your new git repo to exist in, change into it and then run one of the
|
105
|
+
above commands. Note that in the above cases the trunk, branches, tags options
|
106
|
+
are simply folder names relative to the provided repo path. For example if you
|
107
|
+
specified trunk=foo branches=bar and tags=foobar it would be referencing
|
108
|
+
http://svn.yoursite.com/path/to/repo/foo as your trunk, and so on. However, in
|
109
|
+
case 5 it references the root of the repo as trunk.
|
110
|
+
|
111
|
+
=== Authors
|
112
|
+
|
113
|
+
To convert all your svn authors to git format, create a file somewhere on your
|
114
|
+
system with the list of conversions to make, one per line, for example:
|
115
|
+
|
116
|
+
jcoglan = James Coglan <jcoglan@never-you-mind.com>
|
117
|
+
stnick = Santa Claus <nicholas@lapland.com>
|
118
|
+
|
119
|
+
Then pass an +authors+ option to +svn2git+ pointing to your file:
|
120
|
+
|
121
|
+
svn2git http://repos.com/myproject authors=~/authors.txt
|
122
|
+
|
123
|
+
Alternatively, you can place the authors file into ~/.svn2git/authors and
|
124
|
+
svn2git will load it out of there. This allows you to build up one authors
|
125
|
+
file for all your projects and have it loaded for each repository that you
|
126
|
+
migrate.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |spec|
|
7
|
+
spec.name = "svn2git"
|
8
|
+
spec.summary = "A tool for migrating svn projects to git"
|
9
|
+
spec.authors = ["James Coglan", "Kevin Menard"]
|
10
|
+
spec.homepage = "https://www.negativetwenty.net/redmine/projects/svn2git"
|
11
|
+
spec.email = "nirvdrum@gmail.com"
|
12
|
+
end
|
13
|
+
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# spec = Gem::Specification.new do |spec|
|
20
|
+
#
|
21
|
+
# spec.version = "1.1.0"
|
22
|
+
# spec.platform = Gem::Platform::RUBY
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# spec.require_path = "lib"
|
26
|
+
# spec.files = FileList["lib/**/*"].to_a
|
27
|
+
# spec.autorequire = "lib/svn2git.rb"
|
28
|
+
# spec.bindir = "bin"
|
29
|
+
# spec.executables = ["svn2git"]
|
30
|
+
# spec.default_executable = "svn2git"
|
31
|
+
#
|
32
|
+
#
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# spec.test_files = FileList["test/**/*"].to_a
|
36
|
+
# spec.has_rdoc = true
|
37
|
+
# spec.extra_rdoc_files = ["README"]
|
38
|
+
# spec.rdoc_options << "--main" << "README" << '--line-numbers' << '--inline-source'
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# Rake::GemPackageTask.new(spec) do |pkg|
|
42
|
+
# pkg.need_tar = true
|
43
|
+
# end
|
44
|
+
#
|
data/VERSION.yml
ADDED
data/bin/svn2git
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright (c) 2008 James Coglan
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'rubygems'
|
24
|
+
gem 'svn2git'
|
25
|
+
|
26
|
+
require 'svn2git'
|
27
|
+
|
28
|
+
url = ARGV.shift
|
29
|
+
options = ARGV.inject({}) do |memo, arg|
|
30
|
+
parts = arg.split('=')
|
31
|
+
memo[parts.first.to_sym] = parts.last
|
32
|
+
memo
|
33
|
+
end
|
34
|
+
|
35
|
+
migration = Svn2Git::Migration.new(url, options)
|
36
|
+
migration.run!
|
37
|
+
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Svn2Git
|
2
|
+
DEFAULT_AUTHORS_FILE = "~/.svn2git/authors"
|
3
|
+
|
4
|
+
class Migration
|
5
|
+
|
6
|
+
attr_reader :dir
|
7
|
+
|
8
|
+
def initialize(url, options = {})
|
9
|
+
@url = url
|
10
|
+
@dir = @url.scan(/[^\/]+/).last
|
11
|
+
|
12
|
+
@options = options
|
13
|
+
@options[:trunk] ||= 'trunk'
|
14
|
+
@options[:branches] ||= 'branches'
|
15
|
+
@options[:tags] ||= 'tags'
|
16
|
+
|
17
|
+
@authors = options[:authors]
|
18
|
+
if @authors.nil? && File.exists?(File.expand_path(DEFAULT_AUTHORS_FILE))
|
19
|
+
@authors = DEFAULT_AUTHORS_FILE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def run!
|
24
|
+
clone!
|
25
|
+
fix_tags
|
26
|
+
fix_branches
|
27
|
+
fix_trunk
|
28
|
+
optimize_repos
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def clone!
|
34
|
+
trunk = @options[:trunk]
|
35
|
+
branches = @options[:branches]
|
36
|
+
tags = @options[:tags]
|
37
|
+
rootistrunk = @options[:rootistrunk]
|
38
|
+
|
39
|
+
if (!rootistrunk.nil?)
|
40
|
+
# Non-standard repository layout. The repository root is effectively 'trunk.'
|
41
|
+
run_command("git svn init --no-metadata --trunk=#{@url}")
|
42
|
+
|
43
|
+
else
|
44
|
+
cmd = "git svn init --no-metadata "
|
45
|
+
|
46
|
+
# Add each component to the command that was passed as an argument.
|
47
|
+
cmd += "--trunk=#{trunk} " unless trunk.nil?
|
48
|
+
cmd += "--tags=#{tags} " unless tags.nil?
|
49
|
+
cmd += "--branches=#{branches} " unless branches.nil?
|
50
|
+
|
51
|
+
cmd += @url
|
52
|
+
|
53
|
+
run_command(cmd)
|
54
|
+
end
|
55
|
+
|
56
|
+
run_command("git config svn.authorsfile #{@authors}") if @authors
|
57
|
+
run_command("git svn fetch")
|
58
|
+
|
59
|
+
get_branches
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_branches
|
63
|
+
@remote = `git branch -r`.split(/\n/)
|
64
|
+
@tags = @remote.find_all { |b| b.strip =~ %r{^#{@options[:tags]}\/} }
|
65
|
+
end
|
66
|
+
|
67
|
+
def fix_tags
|
68
|
+
@tags.each do |tag|
|
69
|
+
id = tag.strip.gsub(%r{^#{@options[:tags]}\/}, '')
|
70
|
+
subject = `git log -1 --pretty=format:"%s" #{tag.strip()}`
|
71
|
+
date = `git log -1 --pretty=format:"%ci" #{tag.strip()}`
|
72
|
+
`export GIT_COMMITER_DATE="#{date}"`
|
73
|
+
run_command("git tag -a -m '#{subject}' '#{id.strip()}' '#{tag.strip()}'")
|
74
|
+
run_command("git branch -d -r #{tag.strip()}")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fix_branches
|
79
|
+
svn_branches = @remote.find_all { |b| not @tags.include?(b) }
|
80
|
+
svn_branches.each do |branch|
|
81
|
+
branch = branch.strip
|
82
|
+
next if branch == 'trunk'
|
83
|
+
run_command("git checkout #{branch}")
|
84
|
+
run_command("git checkout -b #{branch}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def fix_trunk
|
89
|
+
trunk = @remote.find { |b| b.strip == 'trunk' }
|
90
|
+
if trunk
|
91
|
+
run_command("git checkout trunk")
|
92
|
+
run_command("git branch -D master")
|
93
|
+
run_command("git checkout -f -b master")
|
94
|
+
run_command("git branch -d -r trunk")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def optimize_repos
|
99
|
+
run_command("git gc")
|
100
|
+
end
|
101
|
+
|
102
|
+
def run_command(cmd)
|
103
|
+
log "Running command: #{cmd}"
|
104
|
+
|
105
|
+
IO.popen(cmd) do |stdout|
|
106
|
+
stdout.each do |line|
|
107
|
+
log line
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def log(msg)
|
115
|
+
puts msg if @options[:verbose]
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
data/lib/svn2git.rb
ADDED
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nirvdrum-svn2git
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Coglan
|
8
|
+
- Kevin Menard
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-04-15 00:00:00 -07:00
|
14
|
+
default_executable: svn2git
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description:
|
18
|
+
email: nirvdrum@gmail.com
|
19
|
+
executables:
|
20
|
+
- svn2git
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README
|
25
|
+
files:
|
26
|
+
- Rakefile
|
27
|
+
- VERSION.yml
|
28
|
+
- bin/svn2git
|
29
|
+
- lib/svn2git.rb
|
30
|
+
- lib/svn2git/migration.rb
|
31
|
+
- README
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: https://www.negativetwenty.net/redmine/projects/svn2git
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options:
|
36
|
+
- --charset=UTF-8
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.2.0
|
55
|
+
signing_key:
|
56
|
+
specification_version: 2
|
57
|
+
summary: A tool for migrating svn projects to git
|
58
|
+
test_files: []
|
59
|
+
|