Class: Gitlab::Git::Commit
Constant Summary
collapse
- MAX_COMMIT_MESSAGE_DISPLAY_SIZE =
10.megabytes
- SHA1_LENGTH =
40
- SHA256_LENGTH =
64
- MIN_SHA_LENGTH =
7
- MAX_SHA_LENGTH =
SHA256_LENGTH
- RAW_SHA_PATTERN =
"\\h{#{MIN_SHA_LENGTH},#{MAX_SHA_LENGTH}}".freeze
- SHA_PATTERN =
/#{RAW_SHA_PATTERN}/
- RAW_FULL_SHA_PATTERN =
Match a full SHA. Note that because this expression is not anchored it will match any SHA that is at least SHA1_LENGTH long.
"\\h{#{SHA1_LENGTH}}(?:\\h{#{SHA256_LENGTH - SHA1_LENGTH}})?".freeze
- FULL_SHA_PATTERN =
/#{RAW_FULL_SHA_PATTERN}/
- SERIALIZE_KEYS =
[
:id, :message, :parent_ids,
:authored_date, :author_name, :author_email,
:committed_date, :committer_name, :committer_email,
:trailers, :extended_trailers, :referenced_by
].freeze
EncodingHelper::BOM_UTF8, EncodingHelper::ENCODING_CONFIDENCE_THRESHOLD, EncodingHelper::ESCAPED_CHARS, EncodingHelper::UNICODE_REPLACEMENT_CHARACTER
Instance Attribute Summary collapse
Class Method Summary
collapse
-
.batch_by_oid(repo, oids) ⇒ Object
Only to be used when the object ids will not necessarily have a relation to each other.
-
.batch_signature_extraction(repository, commit_ids) ⇒ Object
-
.between(repo, base, head, limit: nil) ⇒ Object
Get commits between two revspecs See also #repository.commits_between.
-
.decorate(repository, commit, ref = nil) ⇒ Object
-
.extract_signature_lazily(repository, commit_id) ⇒ Object
-
.find(repo, commit_id = "HEAD") ⇒ Object
-
.find_all(repo, options = {}) ⇒ Object
Prefer ‘list_all` since it deprecates this RPC and `FindCommits`.
-
.find_commit(repo, commit_id) ⇒ Object
-
.get_message(repository, commit_id) ⇒ Object
-
.get_messages(repository, commit_ids) ⇒ Object
-
.last(repo) ⇒ Object
Get last commit for HEAD.
-
.last_for_path(repo, ref, path = nil, literal_pathspec: false) ⇒ Object
Get last commit for specified path and ref.
-
.list_all(repo, options = {}) ⇒ Object
ListCommits lists all commits reachable via a set of references by doing a graph walk.
-
.shas_with_signatures(repository, shas) ⇒ Object
-
.where(options) ⇒ Object
Instance Method Summary
collapse
wrapped_gitaly_errors
#binary_io, #detect_binary?, #detect_encoding, #detect_libgit2_binary?, #encode!, #encode_binary, #encode_utf8, #encode_utf8_no_detect, #encode_utf8_with_escaping!, #encode_utf8_with_replacement_character, #force_encode_utf8, #strip_bom, #unquote_path
Constructor Details
#initialize(repository, raw_commit, head = nil, lazy_load_parents: false) ⇒ Commit
Returns a new instance of Commit.
222
223
224
225
226
227
228
229
230
|
# File 'lib/gitlab/git/commit.rb', line 222
def initialize(repository, raw_commit, head = nil, lazy_load_parents: false)
raise "Nil as raw commit passed" unless raw_commit
@repository = repository
@head = head
@lazy_load_parents = lazy_load_parents
init_commit(raw_commit)
end
|
Instance Attribute Details
#head ⇒ Object
Returns the value of attribute head.
11
12
13
|
# File 'lib/gitlab/git/commit.rb', line 11
def head
@head
end
|
#raw_commit ⇒ Object
Returns the value of attribute raw_commit.
11
12
13
|
# File 'lib/gitlab/git/commit.rb', line 11
def raw_commit
@raw_commit
end
|
#repository ⇒ Object
Returns the value of attribute repository.
36
37
38
|
# File 'lib/gitlab/git/commit.rb', line 36
def repository
@repository
end
|
Class Method Details
.batch_by_oid(repo, oids) ⇒ Object
Only to be used when the object ids will not necessarily have a relation to each other. The last 10 commits for a branch for example, should go through .where
191
192
193
194
195
|
# File 'lib/gitlab/git/commit.rb', line 191
def batch_by_oid(repo, oids)
wrapped_gitaly_errors do
repo.gitaly_commit_client.list_commits_by_oid(oids)
end
end
|
205
206
207
|
# File 'lib/gitlab/git/commit.rb', line 205
def (repository, commit_ids)
repository.gitaly_commit_client.get_commit_signatures(commit_ids)
end
|
.between(repo, base, head, limit: nil) ⇒ Object
Get commits between two revspecs See also #repository.commits_between
Ex.
Commit.between(repo, '29eda46b', 'master') Commit.between(repo, '29eda46b', 'master', limit: 100)
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# File 'lib/gitlab/git/commit.rb', line 125
def between(repo, base, head, limit: nil)
return [] if Gitlab::Git.blank_ref?(base) || Gitlab::Git.blank_ref?(head)
wrapped_gitaly_errors do
revisions = [head, "^#{base}"] client = repo.gitaly_commit_client
if limit
client.list_commits(revisions, pagination_params: { limit: limit }).reverse!
else
client.list_commits(revisions, reverse: true)
end
end
end
|
.decorate(repository, commit, ref = nil) ⇒ Object
180
181
182
|
# File 'lib/gitlab/git/commit.rb', line 180
def decorate(repository, commit, ref = nil)
Gitlab::Git::Commit.new(repository, commit, ref)
end
|
197
198
199
200
201
202
203
|
# File 'lib/gitlab/git/commit.rb', line 197
def (repository, commit_id)
BatchLoader.for(commit_id).batch(key: repository) do |commit_ids, loader, args|
(args[:key], commit_ids).each do |commit_id, signature_data|
loader.call(commit_id, signature_data)
end
end
end
|
.find(repo, commit_id = "HEAD") ⇒ Object
71
72
73
74
75
76
77
78
79
80
81
82
83
|
# File 'lib/gitlab/git/commit.rb', line 71
def find(repo, commit_id = "HEAD")
return commit_id if commit_id.is_a?(Gitlab::Git::Commit)
return unless valid?(commit_id)
commit = find_commit(repo, commit_id)
decorate(repo, commit) if commit
rescue Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository, ArgumentError
nil
end
|
.find_all(repo, options = {}) ⇒ Object
Prefer ‘list_all` since it deprecates this RPC and `FindCommits`.
Returns commits collection
Ex.
Commit.find_all(
repo,
ref: 'master',
max_count: 10,
skip: 5,
order: :date
)
+options+ is a Hash of optional arguments to git
:ref is the ref from which to begin (SHA1 or name)
:max_count is the maximum number of commits to fetch
:skip is the number of commits to skip
:order is the commits order and allowed value is :none (default), :date,
:topo, or any combination of them (in an array). Commit ordering types
are documented here: https://git-scm.com/docs/git-log#_commit_ordering
.find_commit(repo, commit_id) ⇒ Object
85
86
87
88
89
|
# File 'lib/gitlab/git/commit.rb', line 85
def find_commit(repo, commit_id)
wrapped_gitaly_errors do
repo.gitaly_commit_client.find_commit(commit_id)
end
end
|
.get_message(repository, commit_id) ⇒ Object
209
210
211
212
213
214
215
|
# File 'lib/gitlab/git/commit.rb', line 209
def get_message(repository, commit_id)
BatchLoader.for(commit_id).batch(key: repository) do |commit_ids, loader, args|
get_messages(args[:key], commit_ids).each do |commit_id, message|
loader.call(commit_id, message)
end
end
end
|
.get_messages(repository, commit_ids) ⇒ Object
217
218
219
|
# File 'lib/gitlab/git/commit.rb', line 217
def get_messages(repository, commit_ids)
repository.gitaly_commit_client.get_commit_messages(commit_ids)
end
|
.last(repo) ⇒ Object
Get last commit for HEAD
Ex.
Commit.last(repo)
96
97
98
|
# File 'lib/gitlab/git/commit.rb', line 96
def last(repo)
find(repo)
end
|
.last_for_path(repo, ref, path = nil, literal_pathspec: false) ⇒ Object
Get last commit for specified path and ref
Ex.
Commit.last_for_path(repo, '29eda46b', 'app/models')
Commit.last_for_path(repo, 'master', 'Gemfile')
107
108
109
110
111
112
113
114
115
116
|
# File 'lib/gitlab/git/commit.rb', line 107
def last_for_path(repo, ref, path = nil, literal_pathspec: false)
where(
repo: repo,
ref: ref,
path: path,
limit: 1,
literal_pathspec: literal_pathspec
).first
end
|
.list_all(repo, options = {}) ⇒ Object
ListCommits lists all commits reachable via a set of references by doing a graph walk. This deprecates FindAllCommits and FindCommits (except Follow is not yet supported). Any unknown revisions will cause the RPC to fail.
174
175
176
177
178
|
# File 'lib/gitlab/git/commit.rb', line 174
def list_all(repo, options = {})
wrapped_gitaly_errors do
Gitlab::GitalyClient::CommitService.new(repo).list_commits(options[:revisions], options.except(:revisions))
end
end
|
.shas_with_signatures(repository, shas) ⇒ Object
.where(options) ⇒ Object
Get commits collection
Ex.
Commit.where(
repo: repo,
ref: 'master',
path: 'app/models',
limit: 10,
offset: 5,
)
56
57
58
59
60
61
|
# File 'lib/gitlab/git/commit.rb', line 56
def where(options)
repo = options.delete(:repo)
raise 'Gitlab::Git::Repository is required' unless repo.respond_to?(:log)
repo.log(options)
end
|
Instance Method Details
#==(other) ⇒ Object
38
39
40
41
42
|
# File 'lib/gitlab/git/commit.rb', line 38
def ==(other)
return false unless other.is_a?(Gitlab::Git::Commit)
id && id == other.id
end
|
#author_email ⇒ Object
368
369
370
|
# File 'lib/gitlab/git/commit.rb', line 368
def author_email
encode! @author_email
end
|
#author_name ⇒ Object
364
365
366
|
# File 'lib/gitlab/git/commit.rb', line 364
def author_name
encode! @author_name
end
|
#authored_date ⇒ Object
288
289
290
291
292
|
# File 'lib/gitlab/git/commit.rb', line 288
def authored_date
strong_memoize(:authored_date) do
init_date_from_gitaly(raw_commit.author) if raw_commit
end
end
|
#commit_tree_entry(path) ⇒ Object
394
395
396
397
398
399
400
401
402
403
404
405
406
407
|
# File 'lib/gitlab/git/commit.rb', line 394
def commit_tree_entry(path)
entry = @repository.gitaly_commit_client.tree_entry(id, path, 1)
return unless entry
entry = entry.to_h
entry.delete(:data)
entry[:name] = File.basename(path)
entry[:type] = entry[:type].downcase
entry
end
|
#committed_date ⇒ Object
282
283
284
285
286
|
# File 'lib/gitlab/git/commit.rb', line 282
def committed_date
strong_memoize(:committed_date) do
init_date_from_gitaly(raw_commit.committer) if raw_commit
end
end
|
#committer_email ⇒ Object
376
377
378
|
# File 'lib/gitlab/git/commit.rb', line 376
def committer_email
encode! @committer_email
end
|
#committer_name ⇒ Object
372
373
374
|
# File 'lib/gitlab/git/commit.rb', line 372
def committer_name
encode! @committer_name
end
|
#created_at ⇒ Object
261
262
263
|
# File 'lib/gitlab/git/commit.rb', line 261
def created_at
committed_date
end
|
#date ⇒ Object
325
326
327
|
# File 'lib/gitlab/git/commit.rb', line 325
def date
committed_date
end
|
#deltas ⇒ Object
302
303
304
305
306
307
|
# File 'lib/gitlab/git/commit.rb', line 302
def deltas
@deltas ||= begin
deltas = @repository.gitaly_commit_client.commit_deltas(self)
deltas.map { |delta| Gitlab::Git::Diff.new(delta) }
end
end
|
#diff_from_parent(options = {}) ⇒ Object
Returns a diff object for the changes from this commit’s first parent. If there is no parent, then the diff is between this commit and an empty repo. See Repository#diff for keys allowed in the options
hash.
298
299
300
|
# File 'lib/gitlab/git/commit.rb', line 298
def diff_from_parent(options = {})
@repository.gitaly_commit_client.diff_from_parent(self, options)
end
|
#different_committer? ⇒ Boolean
Was this commit committed by a different person than the original author?
266
267
268
|
# File 'lib/gitlab/git/commit.rb', line 266
def different_committer?
author_name != committer_name || author_email != committer_email
end
|
#diffs(options = {}) ⇒ Object
329
330
331
|
# File 'lib/gitlab/git/commit.rb', line 329
def diffs(options = {})
Gitlab::Git::DiffCollection.new(diff_from_parent(options), options)
end
|
#first_ref_by_oid(repo) ⇒ Object
352
353
354
355
356
357
358
|
# File 'lib/gitlab/git/commit.rb', line 352
def first_ref_by_oid(repo)
ref = repo.refs_by_oid(oid: id, limit: 1).first
return unless ref
strip_ref_prefix(ref)
end
|
#gitaly_commit? ⇒ Boolean
384
385
386
|
# File 'lib/gitlab/git/commit.rb', line 384
def gitaly_commit?
raw_commit.is_a?(Gitaly::GitCommit)
end
|
#has_zero_stats? ⇒ Boolean
309
310
311
312
313
|
# File 'lib/gitlab/git/commit.rb', line 309
def has_zero_stats?
stats.total == 0
rescue StandardError
true
end
|
#init_commit(raw_commit) ⇒ Object
232
233
234
235
236
237
238
239
240
241
|
# File 'lib/gitlab/git/commit.rb', line 232
def init_commit(raw_commit)
case raw_commit
when Hash
init_from_hash(raw_commit)
when Gitaly::GitCommit
init_from_gitaly(raw_commit)
else
raise "Invalid raw commit type: #{raw_commit.class}"
end
end
|
#merge_commit? ⇒ Boolean
380
381
382
|
# File 'lib/gitlab/git/commit.rb', line 380
def merge_commit?
parent_ids.size > 1
end
|
#message ⇒ Object
360
361
362
|
# File 'lib/gitlab/git/commit.rb', line 360
def message
encode! @message
end
|
#no_commit_message ⇒ Object
315
316
317
|
# File 'lib/gitlab/git/commit.rb', line 315
def no_commit_message
"No commit message"
end
|
#parent_id ⇒ Object
278
279
280
|
# File 'lib/gitlab/git/commit.rb', line 278
def parent_id
parent_ids.first
end
|
#parent_ids ⇒ Object
270
271
272
273
274
275
276
|
# File 'lib/gitlab/git/commit.rb', line 270
def parent_ids
return @parent_ids unless @lazy_load_parents
@parent_ids = @repository.commit(id).parent_ids if @parent_ids.nil? || @parent_ids.empty?
@parent_ids
end
|
#parents ⇒ Object
333
334
335
|
# File 'lib/gitlab/git/commit.rb', line 333
def parents
parent_ids.map { |oid| self.class.find(@repository, oid) }.compact
end
|
#ref_names(repo) ⇒ Object
Get ref names collection
Ex.
commit.ref_names(repo)
346
347
348
349
350
|
# File 'lib/gitlab/git/commit.rb', line 346
def ref_names(repo)
refs(repo).map do |ref|
strip_ref_prefix(ref)
end
end
|
#safe_message ⇒ Object
257
258
259
|
# File 'lib/gitlab/git/commit.rb', line 257
def safe_message
@safe_message ||= message
end
|
#sha ⇒ Object
243
244
245
|
# File 'lib/gitlab/git/commit.rb', line 243
def sha
id
end
|
#short_id(length = 10) ⇒ Object
247
248
249
|
# File 'lib/gitlab/git/commit.rb', line 247
def short_id(length = 10)
id.to_s[0..length]
end
|
#stats ⇒ Object
337
338
339
|
# File 'lib/gitlab/git/commit.rb', line 337
def stats
Gitlab::Git::CommitStats.new(@repository, self)
end
|
#to_gitaly_commit ⇒ Object
409
410
411
412
413
414
415
416
417
418
419
420
421
|
# File 'lib/gitlab/git/commit.rb', line 409
def to_gitaly_commit
return raw_commit if gitaly_commit?
message_split = raw_commit.message.split("\n", 2)
Gitaly::GitCommit.new(
id: raw_commit.oid,
subject: message_split[0] ? message_split[0].chomp.b : "",
body: raw_commit.message.b,
parent_ids: raw_commit.parent_ids,
author: gitaly_commit_author_from_raw(raw_commit.author),
committer: gitaly_commit_author_from_raw(raw_commit.committer)
)
end
|
#to_hash ⇒ Object
319
320
321
322
323
|
# File 'lib/gitlab/git/commit.rb', line 319
def to_hash
serialize_keys.map.with_object({}) do |key, hash|
hash[key] = send(key) end
end
|
#tree_entry(path) ⇒ Object
388
389
390
391
392
|
# File 'lib/gitlab/git/commit.rb', line 388
def tree_entry(path)
return unless path.present?
commit_tree_entry(path)
end
|
#tree_id ⇒ Object
251
252
253
254
255
|
# File 'lib/gitlab/git/commit.rb', line 251
def tree_id
return unless raw_commit
raw_commit.tree_id
end
|