module Git::Parsers::Diff
Parser for git diff output in various formats
Handles parsing of –numstat, –shortstat, –dirstat, –raw, and –patch output. This parser is used by stash show, diff, show, and log commands.
@note Combined/merge diffs (e.g., from ‘git diff –cc` or `git show <merge>`) are not
supported. These have a different format with multiple +/- columns per parent.
## Design Note: Namespace Organization
This parser creates and returns {Git::DiffResult} and {Git::DiffFile*Info} objects, which live at the top-level ‘Git::` namespace rather than within `Git::Parsers::`. This is intentional:
-
**Parsers are infrastructure** - marked ‘@api private`, users shouldn’t interact with them directly
-
**Info/Result classes are public API** - returned by commands and used throughout the codebase
-
**Info classes are domain entities** - represent git diff data
-
**Result classes are operation outcomes** - represent command results, not parsing details
Keeping Info/Result classes at ‘Git::` improves discoverability and correctly reflects their role as public types rather than parser internals.
@api private
Constants
- BRACE_RENAME_PATTERN
-
Brace-expanded rename format from git numstat -M output
- NULL_MODE
-
Null mode for non-existent files
- NULL_SHA
-
Null SHA for non-existent files
- RENAME_PATTERN
-
Rename format patterns from git numstat -M output:
old_name.rb => new_name.rb \\{old_dir => new_dir}/file.rb dir/\\{old_name.rb => new_name.rb} - STATUS_MAP
-
Statusletter to symbol mapping for –raw output
Public Instance Methods
Source
# File lib/git/parsers/diff.rb, line 76 def build_result(files:, shortstat:, dirstat:) Git::DiffResult.new( files_changed: shortstat[:files_changed], total_insertions: shortstat[:insertions], total_deletions: shortstat[:deletions], files: files, dirstat: dirstat ) end
Build a DiffResult from parsed components
@param files [Array] array of file info objects
@param shortstat [Hash] parsed shortstat data
@param dirstat [Git::DirstatInfo, nil] parsed dirstat data
@return [Git::DiffResult]
Source
# File lib/git/parsers/diff.rb, line 90 def empty_result Git::DiffResult.new( files_changed: 0, total_insertions: 0, total_deletions: 0, files: [], dirstat: nil ) end
Build an empty DiffResult
@return [Git::DiffResult]
Source
# File lib/git/parsers/diff.rb, line 127 def parse_dirstat(lines) entries = lines.filter_map do |line| next unless (match = line.match(/^\s*([\d.]+)%\s+(.+)$/)) Git::DirstatEntry.new(percentage: match[1].to_f, directory: match[2]) end Git::DirstatInfo.new(entries: entries) end
Parse dirstat lines into DirstatInfo
@example
parse_dirstat([" 50.0% lib/", " 50.0% spec/"]) # => #<Git::DirstatInfo entries: [...]>
@param lines [Array<String>] dirstat output lines
@return [Git::DirstatInfo]
Source
# File lib/git/parsers/diff.rb, line 107 def parse_shortstat(line) return { files_changed: 0, insertions: 0, deletions: 0 } if line.nil? { files_changed: line.match(/(\d+)\s+files?\s+changed/)&.[](1).to_i, insertions: line.match(/(\d+)\s+insertions?\(\+\)/)&.[](1).to_i, deletions: line.match(/(\d+)\s+deletions?\(-\)/)&.[](1).to_i } end
Parse shortstat line into components
@example
parse_shortstat(" 3 files changed, 10 insertions(+), 5 deletions(-)") # => { files_changed: 3, insertions: 10, deletions: 5 }
@param line [String, nil] the shortstat line
@return [Hash] { files_changed:, insertions:, deletions: }
Source
# File lib/git/parsers/diff.rb, line 142 def parse_stat_value(value) value == '-' ? 0 : value.to_i end
Parse a stat value (handles ‘-’ for binary files)
@param value [String] the stat value string
@return [Integer] the numeric value (0 for binary files)
Source
# File lib/git/parsers/diff.rb, line 152 def unescape_path(path) return path unless path&.start_with?('"') && path.end_with?('"') Git::EscapedPath.new(path[1..-2]).unescape end
Unescape quoted path from git output
@param path [String] potentially quoted path
@return [String] unescaped path