Class: Grit::Commit

Inherits:
Object
  • Object
show all
Extended by:
Lazy
Defined in:
lib/grit/commit.rb,
lib/grit_ext/commit.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Lazy

extended, lazy_reader

Constructor Details

#initialize(repo, id, parents, tree, author, authored_date, committer, committed_date, message) ⇒ Commit

Instantiate a new Commit

+id+ is the id of the commit
+parents+ is an array of commit ids (will be converted into Commit instances)
+tree+ is the correspdonding tree id (will be converted into a Tree object)
+author+ is the author string
+authored_date+ is the authored Time
+committer+ is the committer string
+committed_date+ is the committed Time
+message+ is an array of commit message lines

Returns Grit::Commit (baked)



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/grit/commit.rb', line 53

def initialize(repo, id, parents, tree, author, authored_date, committer, committed_date, message)
  @repo = repo
  @id = id
  @parents = parents.map { |p| Commit.create(repo, :id => p) }
  @tree = Tree.create(repo, :id => tree)
  @author = author
  @authored_date = authored_date
  @committer = committer
  @committed_date = committed_date
  @message = message.join("\n")
  @short_message = message.find { |x| !x.strip.empty? } || ''
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id



6
7
8
# File 'lib/grit/commit.rb', line 6

def id
  @id
end

#repoObject (readonly)

Returns the value of attribute repo



7
8
9
# File 'lib/grit/commit.rb', line 7

def repo
  @repo
end

Class Method Details

.actor(line) ⇒ Object

Parse out the actor (author or committer) info

Returns [String (actor name and email), Time (acted at time)]



291
292
293
294
# File 'lib/grit/commit.rb', line 291

def self.actor(line)
  m, actor, epoch = *line.match(/^.+? (.*) (\d+) .*$/)
  [Actor.from_string(actor), Time.at(epoch.to_i)]
end

.count(repo, ref) ⇒ Object

Count the number of commits reachable from this ref

+repo+ is the Repo
+ref+ is the ref from which to begin (SHA1 or name)

Returns Integer



101
102
103
# File 'lib/grit/commit.rb', line 101

def self.count(repo, ref)
  repo.git.rev_list({}, ref).size / 41
end

.create(repo, atts) ⇒ Object

Create an unbaked Commit containing just the specified attributes

+repo+ is the Repo
+atts+ is a Hash of instance variable data

Returns Grit::Commit (unbaked)



75
76
77
# File 'lib/grit/commit.rb', line 75

def self.create(repo, atts)
  self.allocate.create_initialize(repo, atts)
end

.diff(repo, a, b = nil, paths = [], options = {}) ⇒ Object

Show diffs between two trees.

repo - The current Grit::Repo instance. a - A String named commit. b - An optional String named commit. Passing an array assumes you

wish to omit the second named commit and limit the diff to the
given paths.

paths - An optional Array of paths to limit the diff. options - An optional Hash of options. Merged into => true.

Returns Grit::Diff[] (baked)



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/grit/commit.rb', line 197

def self.diff(repo, a, b = nil, paths = [], options = {})
  if b.is_a?(Array)
    paths = b
    b     = nil
  end
  paths.unshift("--") unless paths.empty?
  paths.unshift(b)    unless b.nil?
  paths.unshift(a)
  options = {:full_index => true}.update(options)
  text    = repo.git.diff(options, *paths)
  Diff.list_from_string(repo, text)
end

.find_all(repo, ref, options = {}) ⇒ Object

Find all commits matching the given criteria.

+repo+ is the Repo
+ref+ is the ref from which to begin (SHA1 or name) or nil for --all
+options+ is a Hash of optional arguments to git
  :max_count is the maximum number of commits to fetch
  :skip is the number of commits to skip

Returns Grit::Commit[] (baked)



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/grit/commit.rb', line 113

def self.find_all(repo, ref, options = {})
  allowed_options = [:max_count, :skip, :since]

  default_options = {:pretty => "raw"}
  actual_options = default_options.merge(options)

  if ref
    output = repo.git.rev_list(actual_options, ref)
  else
    output = repo.git.rev_list(actual_options.merge(:all => true))
  end

  self.list_from_string(repo, output)
rescue Grit::GitRuby::Repository::NoSuchShaFound
  []
end

.list_from_string(repo, text) ⇒ Object

Parse out commit information into an array of baked Commit objects

+repo+ is the Repo
+text+ is the text output from the git command (raw format)

Returns Grit::Commit[] (baked)

really should re-write this to be more accepting of non-standard commit messages

  • it broke when 'encoding' was introduced - not sure what else might show up



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/grit/commit.rb', line 139

def self.list_from_string(repo, text)
  text_gpgless = text.gsub(/gpgsig -----BEGIN PGP SIGNATURE-----[\n\r](.*[\n\r])*? -----END PGP SIGNATURE-----[\n\r]/, "")
  lines = text_gpgless.split("\n")

  commits = []

  while !lines.empty?
    # GITLAB patch
    # Skip all garbage unless we get real commit
    while !lines.empty? && lines.first !~ /^commit [a-zA-Z0-9]*$/
      lines.shift
    end

    id = lines.shift.split.last
    tree = lines.shift.split.last

    parents = []
    parents << lines.shift.split.last while lines.first =~ /^parent/

    author_line = lines.shift
    author_line << lines.shift if lines[0] !~ /^committer /
    author, authored_date = self.actor(author_line)

    committer_line = lines.shift
    committer_line << lines.shift if lines[0] && lines[0] != '' && lines[0] !~ /^encoding/
    committer, committed_date = self.actor(committer_line)

    # not doing anything with this yet, but it's sometimes there
    encoding = lines.shift.split.last if lines.first =~ /^encoding/

    # GITLAB patch
    # Skip Signature and other raw data
    lines.shift while lines.first =~ /^ /

    lines.shift

    message_lines = []
    message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/

    lines.shift while lines.first && lines.first.empty?

    commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
  end

  commits
end

.parse_batch(repo, sha, size, object) ⇒ Object

Parses output from the `git-cat-file –batch'.

repo - Grit::Repo instance. sha - String SHA of the Commit. size - Fixnum size of the object. object - Parsed String output from `git cat-file –batch`.

Returns an Array of Grit::Commit objects.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/grit/commit.rb', line 25

def self.parse_batch(repo, sha, size, object)
  info, message = object.split("\n\n", 2)

  lines = info.split("\n")
  tree = lines.shift.split(' ', 2).last
  parents = []
  parents << lines.shift[7..-1] while lines.first[0, 6] == 'parent'
  author,    authored_date  = Grit::Commit.actor(lines.shift)
  committer, committed_date = Grit::Commit.actor(lines.shift)

  Grit::Commit.new(
    repo, sha, parents, tree,
    author, authored_date,
    committer, committed_date,
    message.to_s.split("\n"))
end

Instance Method Details

#author_stringObject



296
297
298
# File 'lib/grit/commit.rb', line 296

def author_string
  "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
end

#create_initialize(repo, atts) ⇒ Object

Initializer for Commit.create

+repo+ is the Repo
+atts+ is a Hash of instance variable data

Returns Grit::Commit (unbaked)



84
85
86
87
88
89
90
# File 'lib/grit/commit.rb', line 84

def create_initialize(repo, atts)
  @repo = repo
  atts.each do |k, v|
    instance_variable_set("@#{k}", v)
  end
  self
end

#dateObject



247
248
249
# File 'lib/grit/commit.rb', line 247

def date
  @committed_date
end

#diffs(options = {}) ⇒ Object

Shows diffs between the commit's parent and the commit.

options - An optional Hash of options, passed to Grit::Commit.diff.

Returns Grit::Diff[] (baked)



230
231
232
# File 'lib/grit/commit.rb', line 230

def diffs(options = {})
  show
end

#id_abbrevObject



66
67
68
# File 'lib/grit/commit.rb', line 66

def id_abbrev
  @id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
end

#inspectObject

Pretty object inspection



282
283
284
# File 'lib/grit/commit.rb', line 282

def inspect
  %Q{#<Grit::Commit "#{@id}">}
end

#lazy_sourceObject



92
93
94
# File 'lib/grit/commit.rb', line 92

def lazy_source
  self.class.find_all(@repo, @id, {:max_count => 1}).first
end

#messageObject



7
8
9
# File 'lib/grit_ext/commit.rb', line 7

def message
  GritExt.encode! old_message
end

#notesObject



255
256
257
258
259
260
261
262
263
264
# File 'lib/grit/commit.rb', line 255

def notes
  ret = {}
  notes = Note.find_all(@repo)
  notes.each do |note|
    if n = note.commit.tree/(self.id)
      ret[note.name] = n.data
    end
  end
  ret
end

#old_messageObject



4
# File 'lib/grit_ext/commit.rb', line 4

alias_method :old_message, :message

#old_short_messageObject



5
# File 'lib/grit_ext/commit.rb', line 5

alias_method :old_short_message, :short_message

#patch_idObject

Calculates the commit's Patch ID. The Patch ID is essentially the SHA1 of the diff that the commit is introducing.

Returns the 40 character hex String if a patch-id could be calculated

or nil otherwise.


271
272
273
274
275
276
277
278
279
# File 'lib/grit/commit.rb', line 271

def patch_id
  show = @repo.git.show({}, @id)
  patch_line = @repo.git.native(:patch_id, :input => show)
  if patch_line =~ /^([0-9a-f]{40}) [0-9a-f]{40}\n$/
    $1
  else
    nil
  end
end

#shaObject



243
244
245
# File 'lib/grit/commit.rb', line 243

def sha
  @id
end

#short_messageObject



11
12
13
# File 'lib/grit_ext/commit.rb', line 11

def short_message
  GritExt.encode! old_short_message
end

#showObject



210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/grit/commit.rb', line 210

def show
  if parents.size > 1
    diff = @repo.git.native(:diff, {:full_index => true}, "#{parents[0].id}...#{parents[1].id}")
  else
    diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
  end

  if diff =~ /diff --git a/
    diff = diff.sub(/.*?(diff --git a)/m, '\1')
  else
    diff = ''
  end
  Diff.list_from_string(@repo, diff)
end

#statsObject



234
235
236
# File 'lib/grit/commit.rb', line 234

def stats
  stats = @repo.commit_stats(self.sha, 1)[0][-1]
end

#to_hashObject



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/grit/commit.rb', line 300

def to_hash
  {
    'id'       => id,
    'parents'  => parents.map { |p| { 'id' => p.id } },
    'tree'     => tree.id,
    'message'  => message,
    'author'   => {
      'name'  => author.name,
      'email' => author.email
    },
    'committer' => {
      'name'  => committer.name,
      'email' => committer.email
    },
    'authored_date'  => authored_date.xmlschema,
    'committed_date' => committed_date.xmlschema,
  }
end

#to_patchObject



251
252
253
# File 'lib/grit/commit.rb', line 251

def to_patch
  @repo.git.format_patch({'1' => true, :stdout => true}, to_s)
end

#to_sObject

Convert this Commit to a String which is just the SHA1 id



239
240
241
# File 'lib/grit/commit.rb', line 239

def to_s
  @id
end