schacon-grit 0.9.4 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/API.txt +101 -0
- data/History.txt +42 -2
- data/LICENSE +22 -0
- data/README.md +210 -0
- data/VERSION.yml +4 -0
- data/lib/grit.rb +17 -5
- data/lib/grit/blame.rb +61 -0
- data/lib/grit/blob.rb +11 -2
- data/lib/grit/commit.rb +44 -31
- data/lib/grit/commit_stats.rb +26 -2
- data/lib/grit/diff.rb +8 -8
- data/lib/grit/git-ruby.rb +87 -6
- data/lib/grit/git-ruby/git_object.rb +29 -6
- data/lib/grit/git-ruby/internal/{mmap.rb → file_window.rb} +2 -2
- data/lib/grit/git-ruby/internal/loose.rb +6 -6
- data/lib/grit/git-ruby/internal/pack.rb +22 -20
- data/lib/grit/git-ruby/object.rb +8 -2
- data/lib/grit/git-ruby/repository.rb +33 -24
- data/lib/grit/git.rb +189 -11
- data/lib/grit/index.rb +15 -14
- data/lib/grit/merge.rb +45 -0
- data/lib/grit/ref.rb +8 -29
- data/lib/grit/repo.rb +144 -21
- data/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/submodule.rb +5 -1
- data/lib/grit/tag.rb +22 -66
- data/lib/grit/tree.rb +20 -1
- metadata +32 -47
- data/Manifest.txt +0 -71
- data/README.txt +0 -213
- data/Rakefile +0 -29
- data/grit.gemspec +0 -62
- data/lib/grit/head.rb +0 -83
- data/test/test_actor.rb +0 -35
- data/test/test_blob.rb +0 -79
- data/test/test_commit.rb +0 -190
- data/test/test_config.rb +0 -58
- data/test/test_diff.rb +0 -18
- data/test/test_git.rb +0 -64
- data/test/test_grit.rb +0 -32
- data/test/test_head.rb +0 -47
- data/test/test_real.rb +0 -19
- data/test/test_reality.rb +0 -17
- data/test/test_remote.rb +0 -14
- data/test/test_repo.rb +0 -285
- data/test/test_tag.rb +0 -25
- data/test/test_tree.rb +0 -96
data/lib/grit/blame.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Blame
|
4
|
+
|
5
|
+
attr_reader :lines
|
6
|
+
|
7
|
+
def initialize(repo, file, commit)
|
8
|
+
@repo = repo
|
9
|
+
@file = file
|
10
|
+
@commit = commit
|
11
|
+
@lines = []
|
12
|
+
load_blame
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_blame
|
16
|
+
output = @repo.git.blame({'p' => true}, @commit, '--', @file)
|
17
|
+
process_raw_blame(output)
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_raw_blame(output)
|
21
|
+
lines, final = [], []
|
22
|
+
info, commits = {}, {}
|
23
|
+
|
24
|
+
# process the output
|
25
|
+
output.split("\n").each do |line|
|
26
|
+
if line[0, 1] == "\t"
|
27
|
+
lines << line[1, line.size]
|
28
|
+
elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
|
29
|
+
if !commits[m[1]]
|
30
|
+
commits[m[1]] = @repo.commit(m[1])
|
31
|
+
end
|
32
|
+
info[m[3].to_i] = [commits[m[1]], m[2].to_i]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# get it together
|
37
|
+
info.sort.each do |lineno, commit|
|
38
|
+
final << BlameLine.new(lineno, commit[1], commit[0], lines[lineno - 1])
|
39
|
+
end
|
40
|
+
|
41
|
+
@lines = final
|
42
|
+
end
|
43
|
+
|
44
|
+
# Pretty object inspection
|
45
|
+
def inspect
|
46
|
+
%Q{#<Grit::Blame "#{@file} <#{@commit}>">}
|
47
|
+
end
|
48
|
+
|
49
|
+
class BlameLine
|
50
|
+
attr_accessor :lineno, :oldlineno, :commit, :line
|
51
|
+
def initialize(lineno, oldlineno, commit, line)
|
52
|
+
@lineno = lineno
|
53
|
+
@oldlineno = oldlineno
|
54
|
+
@commit = commit
|
55
|
+
@line = line
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Blame
|
60
|
+
|
61
|
+
end # Grit
|
data/lib/grit/blob.rb
CHANGED
@@ -104,14 +104,23 @@ module Grit
|
|
104
104
|
info = nil
|
105
105
|
end
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
blames
|
109
109
|
end
|
110
110
|
|
111
|
+
def basename
|
112
|
+
File.basename(name)
|
113
|
+
end
|
114
|
+
|
111
115
|
# Pretty object inspection
|
112
116
|
def inspect
|
113
117
|
%Q{#<Grit::Blob "#{@id}">}
|
114
118
|
end
|
119
|
+
|
120
|
+
# Compares blobs by name
|
121
|
+
def <=>(other)
|
122
|
+
name <=> other.name
|
123
|
+
end
|
115
124
|
end # Blob
|
116
|
-
|
125
|
+
|
117
126
|
end # Grit
|
data/lib/grit/commit.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Grit
|
2
|
-
|
2
|
+
|
3
3
|
class Commit
|
4
4
|
attr_reader :id
|
5
5
|
lazy_reader :parents
|
@@ -10,7 +10,8 @@ module Grit
|
|
10
10
|
lazy_reader :committed_date
|
11
11
|
lazy_reader :message
|
12
12
|
lazy_reader :short_message
|
13
|
-
|
13
|
+
lazy_reader :author_string
|
14
|
+
|
14
15
|
# Instantiate a new Commit
|
15
16
|
# +id+ is the id of the commit
|
16
17
|
# +parents+ is an array of commit ids (will be converted into Commit instances)
|
@@ -34,11 +35,11 @@ module Grit
|
|
34
35
|
@message = message.join("\n")
|
35
36
|
@short_message = message[0] || ''
|
36
37
|
end
|
37
|
-
|
38
|
+
|
38
39
|
def id_abbrev
|
39
40
|
@id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
# Create an unbaked Commit containing just the specified attributes
|
43
44
|
# +repo+ is the Repo
|
44
45
|
# +atts+ is a Hash of instance variable data
|
@@ -47,7 +48,7 @@ module Grit
|
|
47
48
|
def self.create(repo, atts)
|
48
49
|
self.allocate.create_initialize(repo, atts)
|
49
50
|
end
|
50
|
-
|
51
|
+
|
51
52
|
# Initializer for Commit.create
|
52
53
|
# +repo+ is the Repo
|
53
54
|
# +atts+ is a Hash of instance variable data
|
@@ -60,11 +61,11 @@ module Grit
|
|
60
61
|
end
|
61
62
|
self
|
62
63
|
end
|
63
|
-
|
64
|
+
|
64
65
|
def lazy_source
|
65
66
|
self.class.find_all(@repo, @id, {:max_count => 1}).first
|
66
67
|
end
|
67
|
-
|
68
|
+
|
68
69
|
# Count the number of commits reachable from this ref
|
69
70
|
# +repo+ is the Repo
|
70
71
|
# +ref+ is the ref from which to begin (SHA1 or name)
|
@@ -73,7 +74,7 @@ module Grit
|
|
73
74
|
def self.count(repo, ref)
|
74
75
|
repo.git.rev_list({}, ref).size / 41
|
75
76
|
end
|
76
|
-
|
77
|
+
|
77
78
|
# Find all commits matching the given criteria.
|
78
79
|
# +repo+ is the Repo
|
79
80
|
# +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
|
@@ -84,21 +85,21 @@ module Grit
|
|
84
85
|
# Returns Grit::Commit[] (baked)
|
85
86
|
def self.find_all(repo, ref, options = {})
|
86
87
|
allowed_options = [:max_count, :skip, :since]
|
87
|
-
|
88
|
+
|
88
89
|
default_options = {:pretty => "raw"}
|
89
90
|
actual_options = default_options.merge(options)
|
90
|
-
|
91
|
+
|
91
92
|
if ref
|
92
93
|
output = repo.git.rev_list(actual_options, ref)
|
93
94
|
else
|
94
95
|
output = repo.git.rev_list(actual_options.merge(:all => true))
|
95
96
|
end
|
96
|
-
|
97
|
+
|
97
98
|
self.list_from_string(repo, output)
|
98
99
|
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
99
100
|
[]
|
100
101
|
end
|
101
|
-
|
102
|
+
|
102
103
|
# Parse out commit information into an array of baked Commit objects
|
103
104
|
# +repo+ is the Repo
|
104
105
|
# +text+ is the text output from the git command (raw format)
|
@@ -110,40 +111,40 @@ module Grit
|
|
110
111
|
#
|
111
112
|
def self.list_from_string(repo, text)
|
112
113
|
lines = text.split("\n")
|
113
|
-
|
114
|
+
|
114
115
|
commits = []
|
115
|
-
|
116
|
+
|
116
117
|
while !lines.empty?
|
117
118
|
id = lines.shift.split.last
|
118
119
|
tree = lines.shift.split.last
|
119
|
-
|
120
|
+
|
120
121
|
parents = []
|
121
122
|
parents << lines.shift.split.last while lines.first =~ /^parent/
|
122
|
-
|
123
|
+
|
123
124
|
author, authored_date = self.actor(lines.shift)
|
124
125
|
committer, committed_date = self.actor(lines.shift)
|
125
|
-
|
126
|
+
|
126
127
|
# not doing anything with this yet, but it's sometimes there
|
127
128
|
encoding = lines.shift.split.last if lines.first =~ /^encoding/
|
128
|
-
|
129
|
+
|
129
130
|
lines.shift
|
130
|
-
|
131
|
+
|
131
132
|
message_lines = []
|
132
133
|
message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
|
133
|
-
|
134
|
+
|
134
135
|
lines.shift while lines.first && lines.first.empty?
|
135
|
-
|
136
|
+
|
136
137
|
commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
|
137
138
|
end
|
138
|
-
|
139
|
+
|
139
140
|
commits
|
140
141
|
end
|
141
|
-
|
142
|
+
|
142
143
|
# Show diffs between two trees:
|
143
144
|
# +repo+ is the Repo
|
144
145
|
# +a+ is a named commit
|
145
|
-
# +b+ is an optional named commit. Passing an array assumes you
|
146
|
-
# wish to omit the second named commit and limit the diff to the
|
146
|
+
# +b+ is an optional named commit. Passing an array assumes you
|
147
|
+
# wish to omit the second named commit and limit the diff to the
|
147
148
|
# given paths.
|
148
149
|
# +paths* is an array of paths to limit the diff.
|
149
150
|
#
|
@@ -174,10 +175,14 @@ module Grit
|
|
174
175
|
if parents.empty?
|
175
176
|
show
|
176
177
|
else
|
177
|
-
self.class.diff(@repo, parents.first.id, @id)
|
178
|
+
self.class.diff(@repo, parents.first.id, @id)
|
178
179
|
end
|
179
180
|
end
|
180
181
|
|
182
|
+
def stats
|
183
|
+
stats = @repo.commit_stats(self.sha, 1)[0][-1]
|
184
|
+
end
|
185
|
+
|
181
186
|
# Convert this Commit to a String which is just the SHA1 id
|
182
187
|
def to_s
|
183
188
|
@id
|
@@ -186,18 +191,22 @@ module Grit
|
|
186
191
|
def sha
|
187
192
|
@id
|
188
193
|
end
|
189
|
-
|
194
|
+
|
190
195
|
def date
|
191
196
|
@committed_date
|
192
197
|
end
|
193
|
-
|
198
|
+
|
199
|
+
def to_patch
|
200
|
+
@repo.git.format_patch({'1' => true, :stdout => true}, to_s)
|
201
|
+
end
|
202
|
+
|
194
203
|
# Pretty object inspection
|
195
204
|
def inspect
|
196
205
|
%Q{#<Grit::Commit "#{@id}">}
|
197
206
|
end
|
198
|
-
|
207
|
+
|
199
208
|
# private
|
200
|
-
|
209
|
+
|
201
210
|
# Parse out the actor (author or committer) info
|
202
211
|
#
|
203
212
|
# Returns [String (actor name and email), Time (acted at time)]
|
@@ -206,6 +215,10 @@ module Grit
|
|
206
215
|
[Actor.from_string(actor), Time.at(epoch.to_i)]
|
207
216
|
end
|
208
217
|
|
218
|
+
def author_string
|
219
|
+
"%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
|
220
|
+
end
|
221
|
+
|
209
222
|
def to_hash
|
210
223
|
{
|
211
224
|
'id' => id,
|
@@ -225,5 +238,5 @@ module Grit
|
|
225
238
|
}
|
226
239
|
end
|
227
240
|
end # Commit
|
228
|
-
|
241
|
+
|
229
242
|
end # Grit
|
data/lib/grit/commit_stats.rb
CHANGED
@@ -62,12 +62,12 @@ module Grit
|
|
62
62
|
lines.shift
|
63
63
|
|
64
64
|
message_lines = []
|
65
|
-
message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
|
65
|
+
message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/ || lines.first == ''
|
66
66
|
|
67
67
|
lines.shift while lines.first && lines.first.empty?
|
68
68
|
|
69
69
|
files = []
|
70
|
-
while lines.first =~ /^(
|
70
|
+
while lines.first =~ /^([-\d]+)\s+([-\d]+)\s+(.+)/
|
71
71
|
(additions, deletions, filename) = lines.shift.split
|
72
72
|
additions = additions.to_i
|
73
73
|
deletions = deletions.to_i
|
@@ -88,6 +88,13 @@ module Grit
|
|
88
88
|
%Q{#<Grit::CommitStats "#{@id}">}
|
89
89
|
end
|
90
90
|
|
91
|
+
# Convert to an easy-to-traverse structure
|
92
|
+
def to_diffstat
|
93
|
+
files.map do |metadata|
|
94
|
+
DiffStat.new(*metadata)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
91
98
|
# private
|
92
99
|
|
93
100
|
def to_hash
|
@@ -99,6 +106,23 @@ module Grit
|
|
99
106
|
'total' => total
|
100
107
|
}
|
101
108
|
end
|
109
|
+
|
102
110
|
end # CommitStats
|
103
111
|
|
112
|
+
class DiffStat
|
113
|
+
attr_reader :filename, :additions, :deletions
|
114
|
+
|
115
|
+
def initialize(filename, additions, deletions, total=nil)
|
116
|
+
@filename, @additions, @deletions = filename, additions, deletions
|
117
|
+
end
|
118
|
+
|
119
|
+
def net
|
120
|
+
additions - deletions
|
121
|
+
end
|
122
|
+
|
123
|
+
def inspect
|
124
|
+
"#{filename}: +#{additions} -#{deletions}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
104
128
|
end # Grit
|
data/lib/grit/diff.rb
CHANGED
@@ -2,21 +2,21 @@ module Grit
|
|
2
2
|
|
3
3
|
class Diff
|
4
4
|
attr_reader :a_path, :b_path
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :a_blob, :b_blob
|
6
6
|
attr_reader :a_mode, :b_mode
|
7
7
|
attr_reader :new_file, :deleted_file
|
8
8
|
attr_reader :diff
|
9
9
|
|
10
|
-
def initialize(repo, a_path, b_path,
|
10
|
+
def initialize(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
|
11
11
|
@repo = repo
|
12
12
|
@a_path = a_path
|
13
13
|
@b_path = b_path
|
14
|
-
@
|
15
|
-
@
|
14
|
+
@a_blob = a_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => a_blob)
|
15
|
+
@b_blob = b_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => b_blob)
|
16
16
|
@a_mode = a_mode
|
17
17
|
@b_mode = b_mode
|
18
|
-
@new_file = new_file
|
19
|
-
@deleted_file = deleted_file
|
18
|
+
@new_file = new_file || @a_blob.nil?
|
19
|
+
@deleted_file = deleted_file || @b_blob.nil?
|
20
20
|
@diff = diff
|
21
21
|
end
|
22
22
|
|
@@ -51,7 +51,7 @@ module Grit
|
|
51
51
|
deleted_file = true
|
52
52
|
end
|
53
53
|
|
54
|
-
m,
|
54
|
+
m, a_blob, b_blob, b_mode = *lines.shift.match(%r{^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$})
|
55
55
|
b_mode.strip! if b_mode
|
56
56
|
|
57
57
|
diff_lines = []
|
@@ -60,7 +60,7 @@ module Grit
|
|
60
60
|
end
|
61
61
|
diff = diff_lines.join("\n")
|
62
62
|
|
63
|
-
diffs << Diff.new(repo, a_path, b_path,
|
63
|
+
diffs << Diff.new(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
|
64
64
|
end
|
65
65
|
|
66
66
|
diffs
|
data/lib/grit/git-ruby.rb
CHANGED
@@ -39,9 +39,9 @@ module Grit
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# git diff --full-index 'ec037431382e83c3e95d4f2b3d145afbac8ea55d' 'f1ec1aea10986159456846b8a05615b87828d6c6'
|
42
|
-
def diff(options, sha1, sha2)
|
43
|
-
|
44
|
-
end
|
42
|
+
#def diff(options, sha1, sha2)
|
43
|
+
# try_run { ruby_git.diff(sha1, sha2, options) }
|
44
|
+
#end
|
45
45
|
|
46
46
|
def rev_list(options, ref = 'master')
|
47
47
|
options.delete(:skip) if options[:skip].to_i == 0
|
@@ -72,8 +72,8 @@ module Grit
|
|
72
72
|
(sha1, sha2) = string.split('..')
|
73
73
|
return [rev_parse({}, sha1), rev_parse({}, sha2)]
|
74
74
|
end
|
75
|
-
|
76
|
-
if
|
75
|
+
|
76
|
+
if /^[0-9a-f]{40}$/.match(string) # passing in a sha - just no-op it
|
77
77
|
return string.chomp
|
78
78
|
end
|
79
79
|
|
@@ -103,6 +103,87 @@ module Grit
|
|
103
103
|
return method_missing('rev-parse', {}, string).chomp
|
104
104
|
end
|
105
105
|
|
106
|
+
def refs(options, prefix)
|
107
|
+
refs = []
|
108
|
+
already = {}
|
109
|
+
Dir.chdir(@git_dir) do
|
110
|
+
files = Dir.glob(prefix + '/**/*')
|
111
|
+
files.each do |ref|
|
112
|
+
next if !File.file?(ref)
|
113
|
+
id = File.read(ref).chomp
|
114
|
+
name = ref.sub("#{prefix}/", '')
|
115
|
+
if !already[name]
|
116
|
+
refs << "#{name} #{id}"
|
117
|
+
already[name] = true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if File.file?('packed-refs')
|
122
|
+
File.readlines('packed-refs').each do |line|
|
123
|
+
if m = /^(\w{40}) (.*?)$/.match(line)
|
124
|
+
next if !Regexp.new('^' + prefix).match(m[2])
|
125
|
+
name = m[2].sub("#{prefix}/", '')
|
126
|
+
if !already[name]
|
127
|
+
refs << "#{name} #{m[1]}"
|
128
|
+
already[name] = true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
refs.join("\n")
|
136
|
+
end
|
137
|
+
|
138
|
+
def tags(options, prefix)
|
139
|
+
refs = []
|
140
|
+
already = {}
|
141
|
+
|
142
|
+
Dir.chdir(repo.path) do
|
143
|
+
files = Dir.glob(prefix + '/**/*')
|
144
|
+
|
145
|
+
files.each do |ref|
|
146
|
+
next if !File.file?(ref)
|
147
|
+
|
148
|
+
id = File.read(ref).chomp
|
149
|
+
name = ref.sub("#{prefix}/", '')
|
150
|
+
|
151
|
+
if !already[name]
|
152
|
+
refs << "#{name} #{id}"
|
153
|
+
already[name] = true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if File.file?('packed-refs')
|
158
|
+
lines = File.readlines('packed-refs')
|
159
|
+
lines.each_with_index do |line, i|
|
160
|
+
if m = /^(\w{40}) (.*?)$/.match(line)
|
161
|
+
next if !Regexp.new('^' + prefix).match(m[2])
|
162
|
+
name = m[2].sub("#{prefix}/", '')
|
163
|
+
|
164
|
+
# Annotated tags in packed-refs include a reference
|
165
|
+
# to the commit object on the following line.
|
166
|
+
next_line = lines[i + 1]
|
167
|
+
|
168
|
+
id =
|
169
|
+
if next_line && next_line[0] == ?^
|
170
|
+
next_line[1..-1].chomp
|
171
|
+
else
|
172
|
+
m[1]
|
173
|
+
end
|
174
|
+
|
175
|
+
if !already[name]
|
176
|
+
refs << "#{name} #{id}"
|
177
|
+
already[name] = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
refs.join("\n")
|
185
|
+
end
|
186
|
+
|
106
187
|
def file_size(ref)
|
107
188
|
try_run { ruby_git.cat_file_size(ref).to_s }
|
108
189
|
end
|
@@ -113,7 +194,7 @@ module Grit
|
|
113
194
|
|
114
195
|
def blame_tree(commit, path = nil)
|
115
196
|
begin
|
116
|
-
path = path.
|
197
|
+
path = [path].join('/').to_s + '/' if (path && path != '')
|
117
198
|
path = '' if !path.is_a? String
|
118
199
|
commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
|
119
200
|
clean_paths(commits)
|