lib/gitlab_git/repository.rb in gitlab_git-7.0.0.rc8 vs lib/gitlab_git/repository.rb in gitlab_git-7.0.0.rc9

- old
+ new

@@ -359,17 +359,19 @@ # # Ex. # repo.branch_names_contains('master') # def branches_contains(commit) - sha = rugged.rev_parse_oid(commit) + commit_obj = rugged.rev_parse(commit) + parent = commit_obj.parents.first unless commit_obj.parents.empty? walker = Rugged::Walker.new(rugged) rugged.branches.select do |branch| walker.push(branch.target_id) - result = walker.any? { |c| c.oid == sha } + walker.hide(parent) if parent + result = walker.any? { |c| c.oid == commit_obj.oid } walker.reset result end end @@ -792,46 +794,83 @@ # Returns true if the given commit affects the given path. If the # +follow+ option is true and the file specified by +path+ was renamed, # then the path value is set to the old path. def commit_touches_path?(commit, path, follow) - if commit.parents.empty? - diff = commit.diff + if follow + touches_path_diff?(commit, path) else - diff = commit.parents[0].diff(commit) - diff.find_similar! if follow + touches_path_tree?(commit, path) end + end - # Check the commit's deltas to see if it touches the :path - # argument - diff.each_delta do |d| - if path_matches?(path, d.old_file[:path], d.new_file[:path]) - if should_follow?(follow, d, path) - # Look for the old path in ancestors - path.replace(d.old_file[:path]) - end + # Returns true if +commit+ introduced changes to +path+, using commit + # trees to make that determination. + def touches_path_tree?(commit, path) + parent = commit.parents[0] + entry = tree_entry(commit, path) - return true - end + if parent.nil? + # This is the root commit, return true if it has +path+ in its tree + return entry != nil end - false + parent_entry = tree_entry(parent, path) + + if entry.nil? && parent_entry.nil? + false + elsif entry.nil? || parent_entry.nil? + true + else + entry[:oid] != parent_entry[:oid] + end end - # Used by the #commit_touches_path method to determine whether the - # specified file has been renamed and should be followed in ancestor - # commits. Returns true if +follow_option+ is true, the file is renamed - # in this commit, and the new file's path matches the path option. - def should_follow?(follow_option, delta, path) - follow_option && delta.renamed? && path == delta.new_file[:path] + # Find the entry for +path+ in the tree for +commit+ + def tree_entry(commit, path) + pathname = Pathname.new(path) + tmp_entry = nil + + pathname.each_filename do |dir| + if tmp_entry.nil? + tmp_entry = commit.tree[dir] + else + tmp_entry = rugged.lookup(tmp_entry[:oid])[dir] + end + end + + tmp_entry end - # Returns true if any of the strings in +*paths+ begins with the - # +path_to_match+ argument - def path_matches?(path_to_match, *paths) - paths.any? do |p| - p.match(/^#{Regexp.escape(path_to_match)}/) + # Returns true if +commit+ introduced changes to +path+, using + # Rugged::Diff objects to make that determination. This is slower than + # comparing commit trees, but lets us use Rugged::Diff#find_similar to + # detect file renames. + def touches_path_diff?(commit, path) + diff = commit.diff(reverse: true, paths: [path], + disable_pathspec_match: true) + + return false if diff.deltas.empty? + + # If +path+ is a filename, not a directory, then we should only have + # one delta. We don't need to follow renames for directories. + return true if diff.deltas.length > 1 + + # Detect renames + delta = diff.deltas.first + if delta.added? + full_diff = commit.diff(reverse: true) + full_diff.find_similar! + + full_diff.each_delta do |full_delta| + if full_delta.renamed? && path == full_delta.new_file[:path] + # Look for the old path in ancestors + path.replace(full_delta.old_file[:path]) + end + end end + + true end def archive_to_file(treeish = 'master', prefix = nil, filename = 'archive.tar.gz', format = nil, compress_cmd = %W(gzip)) git_archive_cmd = %W(git --git-dir=#{path} archive) git_archive_cmd << "--prefix=#{prefix}" if prefix