mss-svn2git 1.2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog.markdown +26 -0
- data/README.markdown +142 -0
- data/Rakefile +44 -0
- data/VERSION.yml +4 -0
- data/bin/svn2git +26 -0
- data/lib/svn2git.rb +2 -0
- data/lib/svn2git/migration.rb +180 -0
- metadata +61 -0
data/ChangeLog.markdown
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# 1.2.1 - 2009-04-19
|
2
|
+
|
3
|
+
* Fixed a problem with the svn2git binary not loading command-line args properly.
|
4
|
+
|
5
|
+
# 1.2.0 - 2009-04-17
|
6
|
+
|
7
|
+
* Reworked command-line options so they work similarly to every other app in the world.
|
8
|
+
* Better error messaging when no URL provided.
|
9
|
+
* Improved docs.
|
10
|
+
|
11
|
+
# 1.1.1 - 2009-04-15
|
12
|
+
|
13
|
+
* Started using Jeweler for gem management.
|
14
|
+
* Fixed issue with not loading up RubyGems appropriately.
|
15
|
+
|
16
|
+
# 1.1.0 - 2009-01-02
|
17
|
+
|
18
|
+
* First release since nirvdrum fork.
|
19
|
+
|
20
|
+
* Fixed issues with handling of tags and branches.
|
21
|
+
* Added better logging of output from git-svn.
|
22
|
+
* Wrap external command processing to capture failures.
|
23
|
+
|
24
|
+
# 1.0.0 - 2008-07-19
|
25
|
+
|
26
|
+
* Forked version from jcoglan.
|
data/README.markdown
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
svn2git
|
2
|
+
=======
|
3
|
+
|
4
|
+
_svn2git_ is a tiny utility for migrating projects from Subversion to Git
|
5
|
+
while keeping the trunk, branches and tags where they should be. It uses
|
6
|
+
git-svn to clone an svn repository and does some clean-up to make sure
|
7
|
+
branches and tags are imported in a meaningful way, and that the code checked
|
8
|
+
into master ends up being what's currently in your svn trunk rather than
|
9
|
+
whichever svn branch your last commit was in.
|
10
|
+
|
11
|
+
Examples
|
12
|
+
--------
|
13
|
+
|
14
|
+
Say I have this code in svn:
|
15
|
+
|
16
|
+
trunk
|
17
|
+
...
|
18
|
+
branches
|
19
|
+
1.x
|
20
|
+
2.x
|
21
|
+
tags
|
22
|
+
1.0.0
|
23
|
+
1.0.1
|
24
|
+
1.0.2
|
25
|
+
1.1.0
|
26
|
+
2.0.0
|
27
|
+
|
28
|
+
git-svn will go through the commit history to build a new git repo. It will
|
29
|
+
import all branches and tags as remote svn branches, whereas what you really
|
30
|
+
want is git-native local branches and git tag objects. So after importing this
|
31
|
+
project I'll get:
|
32
|
+
|
33
|
+
$ git branch
|
34
|
+
* master
|
35
|
+
$ git branch -a
|
36
|
+
* master
|
37
|
+
1.x
|
38
|
+
2.x
|
39
|
+
tags/1.0.0
|
40
|
+
tags/1.0.1
|
41
|
+
tags/1.0.2
|
42
|
+
tags/1.1.0
|
43
|
+
tags/2.0.0
|
44
|
+
trunk
|
45
|
+
$ git tag -l
|
46
|
+
[ empty ]
|
47
|
+
|
48
|
+
After svn2git is done with your project, you'll get this instead:
|
49
|
+
|
50
|
+
$ git branch
|
51
|
+
* master
|
52
|
+
1.x
|
53
|
+
2.x
|
54
|
+
$ git tag -l
|
55
|
+
1.0.0
|
56
|
+
1.0.1
|
57
|
+
1.0.2
|
58
|
+
1.1.0
|
59
|
+
2.0.0
|
60
|
+
|
61
|
+
Finally, it makes sure the HEAD of master is the same as the current trunk of
|
62
|
+
the svn repo.
|
63
|
+
|
64
|
+
Installation
|
65
|
+
------------
|
66
|
+
|
67
|
+
Make sure you have git installed, then install the gem:
|
68
|
+
|
69
|
+
$ sudo apt-get install git-core git-svn
|
70
|
+
$ sudo gem install nirvdrum-svn2git
|
71
|
+
|
72
|
+
Usage
|
73
|
+
-----
|
74
|
+
|
75
|
+
There are a number of ways in which you can create a git repo from an existing
|
76
|
+
svn repo. The differentiating factor is the svn repo layout. Below is an
|
77
|
+
enumerated listing of the varying supported layouts and the proper way to
|
78
|
+
create a git repo from a svn repo in the specified layout.
|
79
|
+
|
80
|
+
1. The svn repo is in the standard layout of (trunk, branches, tags) at the
|
81
|
+
root level of the repo.
|
82
|
+
|
83
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --trunk trunk --branches branches --tags tags
|
84
|
+
|
85
|
+
2. The svn repo is NOT in standard layout and has only a trunk and tags at the
|
86
|
+
root level of the repo.
|
87
|
+
|
88
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --trunk trunk --tags tags
|
89
|
+
|
90
|
+
3. The svn repo is NOT in standard layout and has only a trunk and branches at
|
91
|
+
the root level of the repo.
|
92
|
+
|
93
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --trunk trunk --branches branches
|
94
|
+
|
95
|
+
4. The svn repo is NOT in standard layout and has only a trunk at the root
|
96
|
+
level of the repo.
|
97
|
+
|
98
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --trunk trunk
|
99
|
+
|
100
|
+
5. The svn repo is NOT in standard layout and has no trunk, branches, or tags
|
101
|
+
at the root level of the repo. Instead the root level of the repo is
|
102
|
+
equivalent to the trunk and there are no tags or branches.
|
103
|
+
|
104
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --rootistrunk
|
105
|
+
|
106
|
+
The above will create a git repository in the current directory with the git
|
107
|
+
version of the svn repository. Hence, you need to make a directory that you
|
108
|
+
want your new git repo to exist in, change into it and then run one of the
|
109
|
+
above commands. Note that in the above cases the trunk, branches, tags options
|
110
|
+
are simply folder names relative to the provided repo path. For example if you
|
111
|
+
specified trunk=foo branches=bar and tags=foobar it would be referencing
|
112
|
+
http://svn.yoursite.com/path/to/repo/foo as your trunk, and so on. However, in
|
113
|
+
case 5 it references the root of the repo as trunk.
|
114
|
+
|
115
|
+
Authors
|
116
|
+
-------
|
117
|
+
|
118
|
+
To convert all your svn authors to git format, create a file somewhere on your
|
119
|
+
system with the list of conversions to make, one per line, for example:
|
120
|
+
|
121
|
+
jcoglan = James Coglan <jcoglan@never-you-mind.com>
|
122
|
+
stnick = Santa Claus <nicholas@lapland.com>
|
123
|
+
|
124
|
+
Then pass an +authors+ option to +svn2git+ pointing to your file:
|
125
|
+
|
126
|
+
svn2git http://repos.com/myproject --authors ~/authors.txt
|
127
|
+
|
128
|
+
Alternatively, you can place the authors file into ~/.svn2git/authors and
|
129
|
+
svn2git will load it out of there. This allows you to build up one authors
|
130
|
+
file for all your projects and have it loaded for each repository that you
|
131
|
+
migrate.
|
132
|
+
|
133
|
+
Debugging
|
134
|
+
---------
|
135
|
+
|
136
|
+
If you're having problems with converting your repository and you're not sure why,
|
137
|
+
try turning on verbose logging. This will print out more information from the
|
138
|
+
underlying git-svn process.
|
139
|
+
|
140
|
+
You can turn on verbose logging with the '-v' or '--verbose' flags, like so:
|
141
|
+
|
142
|
+
$ svn2git http://svn.yoursite.com/path/to/repo --verbose
|
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,26 @@
|
|
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 'svn2git'
|
24
|
+
|
25
|
+
migration = Svn2Git::Migration.new(ARGV)
|
26
|
+
migration.run!
|
data/lib/svn2git.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module Svn2Git
|
5
|
+
DEFAULT_AUTHORS_FILE = "~/.svn2git/authors"
|
6
|
+
|
7
|
+
class Migration
|
8
|
+
|
9
|
+
attr_reader :dir
|
10
|
+
|
11
|
+
def initialize(args)
|
12
|
+
@options = parse(args)
|
13
|
+
show_help_message("Missing SVN_URL parameter") if args.empty?
|
14
|
+
show_help_message('Too many arguments') if args.size > 1
|
15
|
+
|
16
|
+
@url = args.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def run!
|
20
|
+
clone!
|
21
|
+
fix_tags
|
22
|
+
fix_branches
|
23
|
+
fix_trunk
|
24
|
+
optimize_repos
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse(args)
|
28
|
+
# Set up reasonable defaults for options.
|
29
|
+
options = {}
|
30
|
+
options[:verbose] = false
|
31
|
+
options[:rootistrunk] = false
|
32
|
+
options[:trunk] = 'trunk'
|
33
|
+
options[:branches] = 'branches'
|
34
|
+
options[:tags] = 'tags'
|
35
|
+
|
36
|
+
if File.exists?(File.expand_path(DEFAULT_AUTHORS_FILE))
|
37
|
+
options[:authors] = DEFAULT_AUTHORS_FILE
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Parse the command-line arguments.
|
42
|
+
@opts = OptionParser.new do |opts|
|
43
|
+
opts.banner = 'Usage: svn2git SVN_URL [options]'
|
44
|
+
|
45
|
+
opts.separator ''
|
46
|
+
opts.separator 'Specific options:'
|
47
|
+
|
48
|
+
opts.on('--trunk TRUNK_PATH', 'Subpath to trunk from repository URL (default: trunk)') do |trunk|
|
49
|
+
options[:trunk] = trunk
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on('--branches BRANCHES_PATH', 'Subpath to branches from repository URL (default: branches)') do |branches|
|
53
|
+
options[:branches] = branches
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on('--tags TAGS_PATH', 'Subpath to tags from repository URL (default: tags)') do |tags|
|
57
|
+
options[:tags] = tags
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on('--authors AUTHORS_FILE', "Path to file containing svn-to-git authors mapping (default: #{DEFAULT_AUTHORS_FILE})") do |authors|
|
61
|
+
options[:authors] = authors
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on('--rootistrunk', 'Use this if the root level of the repo isequivalent to the trunk and there are no tags or branches') do
|
65
|
+
options[:rootistrunk] = true
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on('-v', '--verbose', 'Be verbose in logging -- useful for debugging issues') do
|
69
|
+
options[:verbose] = true
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.separator ""
|
73
|
+
|
74
|
+
# No argument, shows at tail. This will print an options summary.
|
75
|
+
# Try it and see!
|
76
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
77
|
+
puts opts
|
78
|
+
exit
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@opts.parse! args
|
83
|
+
options
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def clone!
|
89
|
+
trunk = @options[:trunk]
|
90
|
+
branches = @options[:branches]
|
91
|
+
tags = @options[:tags]
|
92
|
+
rootistrunk = @options[:rootistrunk]
|
93
|
+
authors = @options[:authors]
|
94
|
+
|
95
|
+
if rootistrunk
|
96
|
+
# Non-standard repository layout. The repository root is effectively 'trunk.'
|
97
|
+
run_command("git svn init --no-metadata --trunk=#{@url}")
|
98
|
+
|
99
|
+
else
|
100
|
+
cmd = "git svn init --no-metadata "
|
101
|
+
|
102
|
+
# Add each component to the command that was passed as an argument.
|
103
|
+
cmd += "--trunk=#{trunk} " unless trunk.nil?
|
104
|
+
cmd += "--tags=#{tags} " unless tags.nil?
|
105
|
+
cmd += "--branches=#{branches} " unless branches.nil?
|
106
|
+
|
107
|
+
cmd += @url
|
108
|
+
|
109
|
+
run_command(cmd)
|
110
|
+
end
|
111
|
+
|
112
|
+
run_command("git config svn.authorsfile #{authors}") if authors
|
113
|
+
run_command("git svn fetch")
|
114
|
+
|
115
|
+
get_branches
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_branches
|
119
|
+
@remote = `git branch -r`.split(/\n/)
|
120
|
+
@tags = @remote.find_all { |b| b.strip =~ %r{^#{@options[:tags]}\/} }
|
121
|
+
end
|
122
|
+
|
123
|
+
def fix_tags
|
124
|
+
@tags.each do |tag|
|
125
|
+
id = tag.strip.gsub(%r{^#{@options[:tags]}\/}, '')
|
126
|
+
subject = `git log -1 --pretty=format:"%s" #{tag.strip()}`
|
127
|
+
date = `git log -1 --pretty=format:"%ci" #{tag.strip()}`
|
128
|
+
`export GIT_COMMITER_DATE="#{date}"`
|
129
|
+
run_command("git tag -a -m '#{subject}' '#{id.strip()}' '#{tag.strip()}'")
|
130
|
+
run_command("git branch -d -r #{tag.strip()}")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def fix_branches
|
135
|
+
svn_branches = @remote.find_all { |b| not @tags.include?(b) }
|
136
|
+
svn_branches.each do |branch|
|
137
|
+
branch = branch.strip
|
138
|
+
next if branch == 'trunk'
|
139
|
+
run_command("git checkout #{branch}")
|
140
|
+
run_command("git checkout -b #{branch}")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def fix_trunk
|
145
|
+
trunk = @remote.find { |b| b.strip == 'trunk' }
|
146
|
+
if trunk
|
147
|
+
run_command("git checkout trunk")
|
148
|
+
run_command("git branch -D master")
|
149
|
+
run_command("git checkout -f -b master")
|
150
|
+
run_command("git branch -d -r trunk")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def optimize_repos
|
155
|
+
run_command("git gc")
|
156
|
+
end
|
157
|
+
|
158
|
+
def run_command(cmd)
|
159
|
+
log "Running command: #{cmd}"
|
160
|
+
|
161
|
+
IO.popen(cmd) do |stdout|
|
162
|
+
stdout.each do |line|
|
163
|
+
log line
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def log(msg)
|
169
|
+
puts msg if @options[:verbose]
|
170
|
+
end
|
171
|
+
|
172
|
+
def show_help_message(msg)
|
173
|
+
puts "Error starting script: #{msg}\n\n"
|
174
|
+
puts @opts.help
|
175
|
+
exit
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mss-svn2git
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.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-19 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
|
+
- ChangeLog.markdown
|
25
|
+
- README.markdown
|
26
|
+
files:
|
27
|
+
- ChangeLog.markdown
|
28
|
+
- README.markdown
|
29
|
+
- Rakefile
|
30
|
+
- VERSION.yml
|
31
|
+
- bin/svn2git
|
32
|
+
- lib/svn2git.rb
|
33
|
+
- lib/svn2git/migration.rb
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: https://www.negativetwenty.net/redmine/projects/svn2git
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: A tool for migrating svn projects to git
|
60
|
+
test_files: []
|
61
|
+
|