class Gitlab::Git::Diff

Attributes

a_mode[RW]

Diff properties

b_mode[RW]

Diff properties

deleted_file[RW]

Stats properties

diff[RW]

Diff properties

new_file[RW]

Stats properties

new_path[RW]

Diff properties

old_path[RW]

Diff properties

renamed_file[RW]

Stats properties

too_large[RW]

Public Class Methods

between(repo, head, base, options = {}, *paths) click to toggle source
# File lib/gitlab_git/diff.rb, line 17
def between(repo, head, base, options = {}, *paths)
  # Only show what is new in the source branch compared to the target branch, not the other way around.
  # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
  # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
  common_commit = repo.merge_base_commit(head, base)

  options ||= {}
  break_rewrites = options[:break_rewrites]
  actual_options = filter_diff_options(options)
  repo.diff(common_commit, head, actual_options, *paths)
end
filter_diff_options(options, default_options = {}) click to toggle source

Return a copy of the options hash containing only keys that can be passed to Rugged. Allowed options are:

:max_size ::
  An integer specifying the maximum byte size of a file before a it
  will be treated as binary. The default value is 512MB.

:context_lines ::
  The number of unchanged lines that define the boundary of a hunk
  (and to display before and after the actual changes). The default is
  3.

:interhunk_lines ::
  The maximum number of unchanged lines between hunk boundaries before
  the hunks will be merged into a one. The default is 0.

:old_prefix ::
  The virtual "directory" to prefix to old filenames in hunk headers.
  The default is "a".

:new_prefix ::
  The virtual "directory" to prefix to new filenames in hunk headers.
  The default is "b".

:reverse ::
  If true, the sides of the diff will be reversed.

:force_text ::
  If true, all files will be treated as text, disabling binary
  attributes & detection.

:ignore_whitespace ::
  If true, all whitespace will be ignored.

:ignore_whitespace_change ::
  If true, changes in amount of whitespace will be ignored.

:ignore_whitespace_eol ::
  If true, whitespace at end of line will be ignored.

:ignore_submodules ::
  if true, submodules will be excluded from the diff completely.

:patience ::
  If true, the "patience diff" algorithm will be used (currenlty
  unimplemented).

:include_ignored ::
  If true, ignored files will be included in the diff.

:include_untracked ::
 If true, untracked files will be included in the diff.

:include_unmodified ::
  If true, unmodified files will be included in the diff.

:recurse_untracked_dirs ::
  Even if +:include_untracked+ is true, untracked directories will
  only be marked with a single entry in the diff. If this flag is set
  to true, all files under ignored directories will be included in the
  diff, too.

:disable_pathspec_match ::
  If true, the given +*paths+ will be applied as exact matches,
  instead of as fnmatch patterns.

:deltas_are_icase ::
  If true, filename comparisons will be made with case-insensitivity.

:include_untracked_content ::
  if true, untracked content will be contained in the the diff patch
  text.

:skip_binary_check ::
  If true, diff deltas will be generated without spending time on
  binary detection. This is useful to improve performance in cases
  where the actual file content difference is not needed.

:include_typechange ::
  If true, type changes for files will not be interpreted as deletion
  of the "old file" and addition of the "new file", but will generate
  typechange records.

:include_typechange_trees ::
  Even if +:include_typechange+ is true, blob -> tree changes will
  still usually be handled as a deletion of the blob. If this flag is
  set to true, blob -> tree changes will be marked as typechanges.

:ignore_filemode ::
  If true, file mode changes will be ignored.

:recurse_ignored_dirs ::
  Even if +:include_ignored+ is true, ignored directories will only be
  marked with a single entry in the diff. If this flag is set to true,
  all files under ignored directories will be included in the diff,
  too.
# File lib/gitlab_git/diff.rb, line 125
def filter_diff_options(options, default_options = {})
  allowed_options = [:max_size, :context_lines, :interhunk_lines,
                     :old_prefix, :new_prefix, :reverse, :force_text,
                     :ignore_whitespace, :ignore_whitespace_change,
                     :ignore_whitespace_eol, :ignore_submodules,
                     :patience, :include_ignored, :include_untracked,
                     :include_unmodified, :recurse_untracked_dirs,
                     :disable_pathspec_match, :deltas_are_icase,
                     :include_untracked_content, :skip_binary_check,
                     :include_typechange, :include_typechange_trees,
                     :ignore_filemode, :recurse_ignored_dirs, :paths,
                     :max_files, :max_lines, :all_diffs]

  if default_options
    actual_defaults = default_options.dup
    actual_defaults.keep_if do |key|
      allowed_options.include?(key)
    end
  else
    actual_defaults = {}
  end

  if options
    filtered_opts = options.dup
    filtered_opts.keep_if do |key|
      allowed_options.include?(key)
    end
    filtered_opts = actual_defaults.merge(filtered_opts)
  else
    filtered_opts = actual_defaults
  end

  filtered_opts
end
new(raw_diff) click to toggle source
# File lib/gitlab_git/diff.rb, line 161
def initialize(raw_diff)
  raise "Nil as raw diff passed" unless raw_diff

  if raw_diff.is_a?(Hash)
    init_from_hash(raw_diff)
  elsif raw_diff.is_a?(Rugged::Patch)
    init_from_rugged(raw_diff)
  else
    raise "Invalid raw diff type: #{raw_diff.class}"
  end
end

Public Instance Methods

line_count() click to toggle source
# File lib/gitlab_git/diff.rb, line 193
def line_count
  @line_count ||= Util.count_lines(@diff)
end
prune_large_diff!() click to toggle source
# File lib/gitlab_git/diff.rb, line 205
def prune_large_diff!
  @diff = ''
  @line_count = 0
  @too_large = true
end
serialize_keys() click to toggle source
# File lib/gitlab_git/diff.rb, line 173
def serialize_keys
  @serialize_keys ||= %(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large)
end
submodule?() click to toggle source
# File lib/gitlab_git/diff.rb, line 189
def submodule?
  a_mode == '160000' || b_mode == '160000'
end
to_hash() click to toggle source
# File lib/gitlab_git/diff.rb, line 177
def to_hash
  hash = {}

  keys = serialize_keys

  keys.each do |key|
    hash[key] = send(key)
  end

  hash
end
too_large?() click to toggle source
# File lib/gitlab_git/diff.rb, line 197
def too_large?
  if @too_large.nil?
    @too_large = @diff.bytesize >= 102400 # 100 KB
  else
    @too_large
  end
end

Private Instance Methods

init_from_hash(hash) click to toggle source
# File lib/gitlab_git/diff.rb, line 226
def init_from_hash(hash)
  raw_diff = hash.symbolize_keys

  serialize_keys.each do |key|
    send(:"#{key}=", raw_diff[key.to_sym])
  end
end
init_from_rugged(rugged) click to toggle source
# File lib/gitlab_git/diff.rb, line 213
def init_from_rugged(rugged)
  @diff = encode!(strip_diff_headers(rugged.to_s))

  d = rugged.delta
  @new_path = encode!(d.new_file[:path])
  @old_path = encode!(d.old_file[:path])
  @a_mode = d.old_file[:mode].to_s(8)
  @b_mode = d.new_file[:mode].to_s(8)
  @new_file = d.added?
  @renamed_file = d.renamed?
  @deleted_file = d.deleted?
end
strip_diff_headers(diff_text) click to toggle source

Strip out the information at the beginning of the patch's text to match Grit's output

# File lib/gitlab_git/diff.rb, line 236
def strip_diff_headers(diff_text)
  # Delete everything up to the first line that starts with '---' or
  # 'Binary'
  diff_text.sub!(/\A.*?^(---|Binary)/m, '\1')

  if diff_text.start_with?('---', 'Binary')
    diff_text
  else
    # If the diff_text did not contain a line starting with '---' or
    # 'Binary', return the empty string. No idea why; we are just
    # preserving behavior from before the refactor.
    ''
  end
end