lib/gitlab_git/repository.rb in gitlab_git-7.0.0.rc10 vs lib/gitlab_git/repository.rb in gitlab_git-7.0.0.rc11

- old
+ new

@@ -263,21 +263,21 @@ end # Return an array of Diff objects that represent the diff # between +from+ and +to+. def diff(from, to, *paths) - rugged.diff(from, to, paths: paths).patches.map do |p| + rugged.diff(from, to, paths: paths).each_patch.map do |p| Gitlab::Git::Diff.new(p) end end # Return the diff between +from+ and +to+ in a single patch string. def diff_text(from, to, *paths) # NOTE: It would be simpler to use the Rugged::Diff#patch method, but # that formats the diff text differently than Rugged::Patch#to_s for # changes to binary files. - rugged.diff(from, to, paths: paths).patches.map do |p| + rugged.diff(from, to, paths: paths).each_patch.map do |p| p.to_s end.join("\n") end # Returns commits collection @@ -734,15 +734,15 @@ def parse_gitmodules(commit, content) results = {} current = "" content.split("\n").each do |txt| - if txt.match(/^\[/) + if txt.match(/^\s*\[/) current = txt.match(/(?<=").*(?=")/)[0] results[current] = {} else - match_data = txt.match(/(\w+) = (.*)/) + match_data = txt.match(/(\w+)\s*=\s*(.*)/) results[current][match_data[1]] = match_data[2] if match_data[1] == "path" results[current]["id"] = blob_content(commit, match_data[2]) end @@ -776,11 +776,11 @@ # Skip merge commits next if c.parents.length > 1 end if !current_path || - commit_touches_path?(c, current_path, options[:follow]) + commit_touches_path?(c, current_path, options[:follow], walker) # This is a commit we care about, unless we haven't skipped enough # yet skipped += 1 commits.push(c) if skipped > offset @@ -790,40 +790,47 @@ walker.reset commits end - # 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 follow - touches_path_diff?(commit, path) - else - touches_path_tree?(commit, path) - end - 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] + # trees to make that determination. Uses the history simplification + # rules that `git log` uses by default, where a commit is omitted if it + # is TREESAME to any parent. + # + # 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, walker) entry = tree_entry(commit, path) - if parent.nil? + if commit.parents.empty? # This is the root commit, return true if it has +path+ in its tree return entry != nil end - parent_entry = tree_entry(parent, path) + num_treesame = 0 + commit.parents.each do |parent| + parent_entry = tree_entry(parent, path) - if entry.nil? && parent_entry.nil? - false - elsif entry.nil? || parent_entry.nil? + # Only follow the first TREESAME parent for merge commits + if num_treesame > 0 + walker.hide(parent) + next + end + + if entry.nil? && parent_entry.nil? + num_treesame += 1 + elsif entry && parent_entry && entry[:oid] == parent_entry[:oid] + num_treesame += 1 + end + end + + case num_treesame + when 0 + detect_rename(commit, commit.parents.first, path) if follow true - else - entry[:oid] != parent_entry[:oid] + else false end end # Find the entry for +path+ in the tree for +commit+ def tree_entry(commit, path) @@ -839,38 +846,30 @@ end tmp_entry end - # 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) + # Compare +commit+ and +parent+ for +path+. If +path+ is a file and was + # renamed in +commit+, then set +path+ to the old filename. + def detect_rename(commit, parent, path) + diff = parent.diff(commit, 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 + return nil if diff.each_delta.count > 1 - # Detect renames - delta = diff.deltas.first + delta = diff.each_delta.first if delta.added? - full_diff = commit.diff(reverse: true) + full_diff = parent.diff(commit) 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