schacon-grit 0.9.4 → 1.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/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)
|