Skip to content
This repository was archived by the owner on May 12, 2018. It is now read-only.

Commit 1ce1c60

Browse files
committed
Merge pull request #49 from mr-vinn/faster-log
Improve Repository#log performance
2 parents 71ceb0f + cd78ed4 commit 1ce1c60

File tree

1 file changed

+63
-26
lines changed

1 file changed

+63
-26
lines changed

lib/gitlab_git/repository.rb

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -796,43 +796,80 @@ def build_log(sha, options)
796796
# +follow+ option is true and the file specified by +path+ was renamed,
797797
# then the path value is set to the old path.
798798
def commit_touches_path?(commit, path, follow)
799-
if commit.parents.empty?
800-
diff = commit.diff
799+
if follow
800+
touches_path_diff?(commit, path)
801801
else
802-
diff = commit.parents[0].diff(commit)
803-
diff.find_similar! if follow
802+
touches_path_tree?(commit, path)
804803
end
804+
end
805805

806-
# Check the commit's deltas to see if it touches the :path
807-
# argument
808-
diff.each_delta do |d|
809-
if path_matches?(path, d.old_file[:path], d.new_file[:path])
810-
if should_follow?(follow, d, path)
811-
# Look for the old path in ancestors
812-
path.replace(d.old_file[:path])
813-
end
806+
# Returns true if +commit+ introduced changes to +path+, using commit
807+
# trees to make that determination.
808+
def touches_path_tree?(commit, path)
809+
parent = commit.parents[0]
810+
entry = tree_entry(commit, path)
814811

815-
return true
816-
end
812+
if parent.nil?
813+
# This is the root commit, return true if it has +path+ in its tree
814+
return entry != nil
817815
end
818816

819-
false
817+
parent_entry = tree_entry(parent, path)
818+
819+
if entry.nil? && parent_entry.nil?
820+
false
821+
elsif entry.nil? || parent_entry.nil?
822+
true
823+
else
824+
entry[:oid] != parent_entry[:oid]
825+
end
820826
end
821827

822-
# Used by the #commit_touches_path method to determine whether the
823-
# specified file has been renamed and should be followed in ancestor
824-
# commits. Returns true if +follow_option+ is true, the file is renamed
825-
# in this commit, and the new file's path matches the path option.
826-
def should_follow?(follow_option, delta, path)
827-
follow_option && delta.renamed? && path == delta.new_file[:path]
828+
# Find the entry for +path+ in the tree for +commit+
829+
def tree_entry(commit, path)
830+
pathname = Pathname.new(path)
831+
tmp_entry = nil
832+
833+
pathname.each_filename do |dir|
834+
if tmp_entry.nil?
835+
tmp_entry = commit.tree[dir]
836+
else
837+
tmp_entry = rugged.lookup(tmp_entry[:oid])[dir]
838+
end
839+
end
840+
841+
tmp_entry
828842
end
829843

830-
# Returns true if any of the strings in +*paths+ begins with the
831-
# +path_to_match+ argument
832-
def path_matches?(path_to_match, *paths)
833-
paths.any? do |p|
834-
p.match(/^#{Regexp.escape(path_to_match)}/)
844+
# Returns true if +commit+ introduced changes to +path+, using
845+
# Rugged::Diff objects to make that determination. This is slower than
846+
# comparing commit trees, but lets us use Rugged::Diff#find_similar to
847+
# detect file renames.
848+
def touches_path_diff?(commit, path)
849+
diff = commit.diff(reverse: true, paths: [path],
850+
disable_pathspec_match: true)
851+
852+
return false if diff.deltas.empty?
853+
854+
# If +path+ is a filename, not a directory, then we should only have
855+
# one delta. We don't need to follow renames for directories.
856+
return true if diff.deltas.length > 1
857+
858+
# Detect renames
859+
delta = diff.deltas.first
860+
if delta.added?
861+
full_diff = commit.diff(reverse: true)
862+
full_diff.find_similar!
863+
864+
full_diff.each_delta do |full_delta|
865+
if full_delta.renamed? && path == full_delta.new_file[:path]
866+
# Look for the old path in ancestors
867+
path.replace(full_delta.old_file[:path])
868+
end
869+
end
835870
end
871+
872+
true
836873
end
837874

838875
def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz', format = nil, compress_cmd = %W(gzip))

0 commit comments

Comments
 (0)