git 1.19.1 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +5 -1
- data/AI_POLICY.md +24 -0
- data/CHANGELOG.md +689 -0
- data/CODE_OF_CONDUCT.md +25 -0
- data/CONTRIBUTING.md +1175 -97
- data/GOVERNANCE.md +106 -0
- data/LICENSE +1 -1
- data/MAINTAINERS.md +17 -4
- data/README.md +476 -320
- data/UPGRADING.md +1138 -0
- data/git.gemspec +124 -36
- data/lib/git/author.rb +39 -7
- data/lib/git/author_info.rb +66 -0
- data/lib/git/branch.rb +615 -65
- data/lib/git/branch_delete_failure.rb +34 -0
- data/lib/git/branch_delete_result.rb +66 -0
- data/lib/git/branch_info.rb +237 -0
- data/lib/git/branches.rb +167 -44
- data/lib/git/command_line/base.rb +247 -0
- data/lib/git/command_line/capturing.rb +308 -0
- data/lib/git/command_line/result.rb +88 -0
- data/lib/git/command_line/streaming.rb +236 -0
- data/lib/git/command_line.rb +52 -0
- data/lib/git/commands/add.rb +139 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +263 -0
- data/lib/git/commands/am/continue.rb +43 -0
- data/lib/git/commands/am/quit.rb +43 -0
- data/lib/git/commands/am/retry.rb +49 -0
- data/lib/git/commands/am/show_current_patch.rb +64 -0
- data/lib/git/commands/am/skip.rb +42 -0
- data/lib/git/commands/am.rb +33 -0
- data/lib/git/commands/apply.rb +242 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +145 -0
- data/lib/git/commands/arguments.rb +4521 -0
- data/lib/git/commands/base.rb +502 -0
- data/lib/git/commands/branch/copy.rb +102 -0
- data/lib/git/commands/branch/create.rb +177 -0
- data/lib/git/commands/branch/delete.rb +88 -0
- data/lib/git/commands/branch/list.rb +178 -0
- data/lib/git/commands/branch/move.rb +102 -0
- data/lib/git/commands/branch/set_upstream.rb +86 -0
- data/lib/git/commands/branch/show_current.rb +49 -0
- data/lib/git/commands/branch/unset_upstream.rb +53 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +385 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +271 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +153 -0
- data/lib/git/commands/checkout/files.rb +116 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +106 -0
- data/lib/git/commands/clean.rb +102 -0
- data/lib/git/commands/clone.rb +241 -0
- data/lib/git/commands/commit.rb +273 -0
- data/lib/git/commands/commit_tree.rb +101 -0
- data/lib/git/commands/config_option_syntax/add.rb +86 -0
- data/lib/git/commands/config_option_syntax/get.rb +121 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +118 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +95 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +96 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +119 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +111 -0
- data/lib/git/commands/config_option_syntax/list.rb +111 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +79 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +83 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +109 -0
- data/lib/git/commands/config_option_syntax/set.rb +119 -0
- data/lib/git/commands/config_option_syntax/unset.rb +92 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +94 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +156 -0
- data/lib/git/commands/diff.rb +657 -0
- data/lib/git/commands/diff_files.rb +519 -0
- data/lib/git/commands/diff_index.rb +499 -0
- data/lib/git/commands/fetch.rb +354 -0
- data/lib/git/commands/fsck.rb +138 -0
- data/lib/git/commands/gc.rb +134 -0
- data/lib/git/commands/grep.rb +339 -0
- data/lib/git/commands/init.rb +101 -0
- data/lib/git/commands/log.rb +634 -0
- data/lib/git/commands/ls_files.rb +195 -0
- data/lib/git/commands/ls_remote.rb +161 -0
- data/lib/git/commands/ls_tree.rb +135 -0
- data/lib/git/commands/maintenance/register.rb +77 -0
- data/lib/git/commands/maintenance/run.rb +109 -0
- data/lib/git/commands/maintenance/start.rb +71 -0
- data/lib/git/commands/maintenance/stop.rb +60 -0
- data/lib/git/commands/maintenance/unregister.rb +84 -0
- data/lib/git/commands/maintenance.rb +31 -0
- data/lib/git/commands/merge/abort.rb +44 -0
- data/lib/git/commands/merge/continue.rb +44 -0
- data/lib/git/commands/merge/quit.rb +46 -0
- data/lib/git/commands/merge/start.rb +250 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +91 -0
- data/lib/git/commands/mv.rb +82 -0
- data/lib/git/commands/name_rev.rb +119 -0
- data/lib/git/commands/pull.rb +382 -0
- data/lib/git/commands/push.rb +251 -0
- data/lib/git/commands/read_tree.rb +154 -0
- data/lib/git/commands/remote/add.rb +96 -0
- data/lib/git/commands/remote/get_url.rb +68 -0
- data/lib/git/commands/remote/list.rb +56 -0
- data/lib/git/commands/remote/prune.rb +63 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +76 -0
- data/lib/git/commands/remote/set_branches.rb +70 -0
- data/lib/git/commands/remote/set_head.rb +89 -0
- data/lib/git/commands/remote/set_url.rb +78 -0
- data/lib/git/commands/remote/set_url_add.rb +70 -0
- data/lib/git/commands/remote/set_url_delete.rb +71 -0
- data/lib/git/commands/remote/show.rb +77 -0
- data/lib/git/commands/remote/update.rb +79 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +281 -0
- data/lib/git/commands/reset.rb +154 -0
- data/lib/git/commands/rev_parse.rb +304 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +62 -0
- data/lib/git/commands/revert/quit.rb +47 -0
- data/lib/git/commands/revert/skip.rb +44 -0
- data/lib/git/commands/revert/start.rb +158 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +113 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +119 -0
- data/lib/git/commands/show_ref/exists.rb +80 -0
- data/lib/git/commands/show_ref/list.rb +149 -0
- data/lib/git/commands/show_ref/verify.rb +122 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +81 -0
- data/lib/git/commands/stash/branch.rb +67 -0
- data/lib/git/commands/stash/clear.rb +43 -0
- data/lib/git/commands/stash/create.rb +60 -0
- data/lib/git/commands/stash/drop.rb +73 -0
- data/lib/git/commands/stash/list.rb +43 -0
- data/lib/git/commands/stash/pop.rb +87 -0
- data/lib/git/commands/stash/push.rb +112 -0
- data/lib/git/commands/stash/show.rb +158 -0
- data/lib/git/commands/stash/store.rb +72 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +174 -0
- data/lib/git/commands/symbolic_ref/delete.rb +72 -0
- data/lib/git/commands/symbolic_ref/read.rb +99 -0
- data/lib/git/commands/symbolic_ref/update.rb +79 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +142 -0
- data/lib/git/commands/tag/delete.rb +57 -0
- data/lib/git/commands/tag/list.rb +146 -0
- data/lib/git/commands/tag/verify.rb +71 -0
- data/lib/git/commands/tag.rb +26 -0
- data/lib/git/commands/update_ref/batch.rb +145 -0
- data/lib/git/commands/update_ref/delete.rb +90 -0
- data/lib/git/commands/update_ref/update.rb +103 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +60 -0
- data/lib/git/commands/worktree/add.rb +139 -0
- data/lib/git/commands/worktree/list.rb +64 -0
- data/lib/git/commands/worktree/lock.rb +58 -0
- data/lib/git/commands/worktree/management_base.rb +51 -0
- data/lib/git/commands/worktree/move.rb +66 -0
- data/lib/git/commands/worktree/prune.rb +67 -0
- data/lib/git/commands/worktree/remove.rb +63 -0
- data/lib/git/commands/worktree/repair.rb +76 -0
- data/lib/git/commands/worktree/unlock.rb +47 -0
- data/lib/git/commands/worktree.rb +43 -0
- data/lib/git/commands/write_tree.rb +68 -0
- data/lib/git/commands.rb +88 -0
- data/lib/git/config.rb +72 -5
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +795 -0
- data/lib/git/detached_head_info.rb +57 -0
- data/lib/git/diff.rb +437 -86
- data/lib/git/diff_file_numstat_info.rb +31 -0
- data/lib/git/diff_file_patch_info.rb +136 -0
- data/lib/git/diff_file_raw_info.rb +129 -0
- data/lib/git/diff_info.rb +162 -0
- data/lib/git/diff_path_status.rb +107 -0
- data/lib/git/diff_result.rb +34 -0
- data/lib/git/diff_stats.rb +111 -0
- data/lib/git/dirstat_info.rb +102 -0
- data/lib/git/encoding_utils.rb +32 -1
- data/lib/git/errors.rb +285 -0
- data/lib/git/escaped_path.rb +57 -5
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +151 -0
- data/lib/git/execution_context.rb +559 -0
- data/lib/git/factories.rb +813 -0
- data/lib/git/file_ref.rb +77 -0
- data/lib/git/fsck_object.rb +56 -0
- data/lib/git/fsck_result.rb +132 -0
- data/lib/git/log.rb +306 -90
- data/lib/git/object.rb +563 -141
- data/lib/git/parsers/branch.rb +240 -0
- data/lib/git/parsers/cat_file.rb +111 -0
- data/lib/git/parsers/config_entry.rb +110 -0
- data/lib/git/parsers/diff.rb +792 -0
- data/lib/git/parsers/fsck.rb +144 -0
- data/lib/git/parsers/grep.rb +42 -0
- data/lib/git/parsers/ls_remote.rb +79 -0
- data/lib/git/parsers/ls_tree.rb +58 -0
- data/lib/git/parsers/remote.rb +162 -0
- data/lib/git/parsers/stash.rb +292 -0
- data/lib/git/parsers/status.rb +251 -0
- data/lib/git/parsers/tag.rb +341 -0
- data/lib/git/parsers/worktree.rb +185 -0
- data/lib/git/path_resolver.rb +206 -0
- data/lib/git/remote.rb +165 -12
- data/lib/git/remote_info.rb +203 -0
- data/lib/git/repository/branching.rb +964 -0
- data/lib/git/repository/committing.rb +246 -0
- data/lib/git/repository/context_helpers.rb +293 -0
- data/lib/git/repository/diffing.rb +785 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +410 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +451 -0
- data/lib/git/repository/object_operations.rb +1551 -0
- data/lib/git/repository/remote_operations.rb +984 -0
- data/lib/git/repository/shared_private.rb +120 -0
- data/lib/git/repository/staging.rb +587 -0
- data/lib/git/repository/stashing.rb +623 -0
- data/lib/git/repository/status_operations.rb +249 -0
- data/lib/git/repository/worktree_operations.rb +339 -0
- data/lib/git/repository.rb +484 -2
- data/lib/git/stash.rb +109 -12
- data/lib/git/stash_info.rb +102 -0
- data/lib/git/stashes.rb +169 -26
- data/lib/git/status.rb +308 -122
- data/lib/git/status_file_info.rb +258 -0
- data/lib/git/status_info.rb +189 -0
- data/lib/git/tag_delete_failure.rb +34 -0
- data/lib/git/tag_delete_result.rb +66 -0
- data/lib/git/tag_info.rb +99 -0
- data/lib/git/url.rb +15 -8
- data/lib/git/version.rb +113 -2
- data/lib/git/version_constraint.rb +85 -0
- data/lib/git/worktree.rb +150 -8
- data/lib/git/worktree_info.rb +128 -0
- data/lib/git/worktrees.rb +118 -13
- data/lib/git.rb +632 -234
- metadata +369 -54
- data/.github/stale.yml +0 -25
- data/.github/workflows/continuous_integration.yml +0 -49
- data/.gitignore +0 -10
- data/Dockerfile.changelog-rs +0 -12
- data/Gemfile +0 -5
- data/ISSUE_TEMPLATE.md +0 -15
- data/PULL_REQUEST_TEMPLATE.md +0 -9
- data/RELEASING.md +0 -70
- data/Rakefile +0 -60
- data/lib/git/base/factory.rb +0 -99
- data/lib/git/base.rb +0 -711
- data/lib/git/command_line_result.rb +0 -86
- data/lib/git/failed_error.rb +0 -53
- data/lib/git/git_execute_error.rb +0 -7
- data/lib/git/index.rb +0 -5
- data/lib/git/lib.rb +0 -1328
- data/lib/git/path.rb +0 -31
- data/lib/git/signaled_error.rb +0 -50
- data/lib/git/working_directory.rb +0 -4
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'file_ref'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
# Immutable value object representing a single file's patch information
|
|
7
|
+
#
|
|
8
|
+
# DiffFilePatchInfo encapsulates the parsed data from a unified diff for one file,
|
|
9
|
+
# including source and destination file references, the patch text, change type,
|
|
10
|
+
# and line statistics.
|
|
11
|
+
#
|
|
12
|
+
#
|
|
13
|
+
# @example A modified file patch
|
|
14
|
+
# patch_info = Git::DiffFilePatchInfo.new(
|
|
15
|
+
# src: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/foo.rb'),
|
|
16
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'def5678', path: 'lib/foo.rb'),
|
|
17
|
+
# patch: "diff --git a/lib/foo.rb b/lib/foo.rb\n...",
|
|
18
|
+
# status: :modified,
|
|
19
|
+
# similarity: nil,
|
|
20
|
+
# binary: false,
|
|
21
|
+
# insertions: 10,
|
|
22
|
+
# deletions: 5
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
# @example A new file patch (src is nil)
|
|
26
|
+
# patch_info = Git::DiffFilePatchInfo.new(
|
|
27
|
+
# src: nil,
|
|
28
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/new.rb'),
|
|
29
|
+
# patch: "diff --git a/lib/new.rb b/lib/new.rb\nnew file mode 100644\n...",
|
|
30
|
+
# status: :added,
|
|
31
|
+
# similarity: nil,
|
|
32
|
+
# binary: false,
|
|
33
|
+
# insertions: 20,
|
|
34
|
+
# deletions: 0
|
|
35
|
+
# )
|
|
36
|
+
#
|
|
37
|
+
# @!attribute [r] src
|
|
38
|
+
# @return [FileRef, nil] the source file reference, or nil for new/added files
|
|
39
|
+
#
|
|
40
|
+
# @!attribute [r] dst
|
|
41
|
+
# @return [FileRef, nil] the destination file reference, or nil for deleted files
|
|
42
|
+
#
|
|
43
|
+
# @!attribute [r] patch
|
|
44
|
+
# @return [String] the full unified diff patch text for this file
|
|
45
|
+
#
|
|
46
|
+
# @!attribute [r] status
|
|
47
|
+
# @return [Symbol] the change status (:added, :modified, :deleted, :renamed, :copied, :type_changed)
|
|
48
|
+
#
|
|
49
|
+
# @!attribute [r] similarity
|
|
50
|
+
# @return [Integer, nil] similarity percentage for renames/copies (0-100), nil otherwise
|
|
51
|
+
#
|
|
52
|
+
# @!attribute [r] binary
|
|
53
|
+
# @return [Boolean] whether this is a binary file
|
|
54
|
+
#
|
|
55
|
+
# @!attribute [r] insertions
|
|
56
|
+
# @return [Integer] number of lines inserted
|
|
57
|
+
#
|
|
58
|
+
# @!attribute [r] deletions
|
|
59
|
+
# @return [Integer] number of lines deleted
|
|
60
|
+
#
|
|
61
|
+
# @api private
|
|
62
|
+
#
|
|
63
|
+
# Work in progress; this class is internal for now and may be made public in a future release.
|
|
64
|
+
DiffFilePatchInfo = Data.define(
|
|
65
|
+
:src,
|
|
66
|
+
:dst,
|
|
67
|
+
:patch,
|
|
68
|
+
:status,
|
|
69
|
+
:similarity,
|
|
70
|
+
:binary,
|
|
71
|
+
:insertions,
|
|
72
|
+
:deletions
|
|
73
|
+
) do
|
|
74
|
+
# Get the primary file path
|
|
75
|
+
#
|
|
76
|
+
# Returns the destination path if it exists, otherwise the source path.
|
|
77
|
+
# This is the "current" or "canonical" path for the file.
|
|
78
|
+
#
|
|
79
|
+
# @return [String] the file path
|
|
80
|
+
#
|
|
81
|
+
def path
|
|
82
|
+
dst&.path || src&.path
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Get the source file path
|
|
86
|
+
#
|
|
87
|
+
# Returns the source path if it exists. Useful for renames/copies to see
|
|
88
|
+
# where the file came from.
|
|
89
|
+
#
|
|
90
|
+
# @return [String, nil] the source file path, or nil if no source (added files)
|
|
91
|
+
#
|
|
92
|
+
def src_path
|
|
93
|
+
src&.path
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Check if this is a binary file
|
|
97
|
+
#
|
|
98
|
+
# @return [Boolean] true if the file is binary
|
|
99
|
+
#
|
|
100
|
+
def binary?
|
|
101
|
+
binary
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Check if this file was renamed
|
|
105
|
+
#
|
|
106
|
+
# @return [Boolean]
|
|
107
|
+
#
|
|
108
|
+
def renamed?
|
|
109
|
+
status == :renamed
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Check if this file was copied
|
|
113
|
+
#
|
|
114
|
+
# @return [Boolean]
|
|
115
|
+
#
|
|
116
|
+
def copied?
|
|
117
|
+
status == :copied
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Check if this file was added
|
|
121
|
+
#
|
|
122
|
+
# @return [Boolean]
|
|
123
|
+
#
|
|
124
|
+
def added?
|
|
125
|
+
status == :added
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Check if this file was deleted
|
|
129
|
+
#
|
|
130
|
+
# @return [Boolean]
|
|
131
|
+
#
|
|
132
|
+
def deleted?
|
|
133
|
+
status == :deleted
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'file_ref'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
# Immutable value object representing status info for a single file from git raw diff output
|
|
7
|
+
#
|
|
8
|
+
# Contains the source and destination file references, change status,
|
|
9
|
+
# similarity percentage (for renames/copies), and line change statistics.
|
|
10
|
+
#
|
|
11
|
+
#
|
|
12
|
+
# @example A modified file
|
|
13
|
+
# info = Git::DiffFileRawInfo.new(
|
|
14
|
+
# src: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/foo.rb'),
|
|
15
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'def5678', path: 'lib/foo.rb'),
|
|
16
|
+
# status: :modified,
|
|
17
|
+
# similarity: nil,
|
|
18
|
+
# insertions: 5,
|
|
19
|
+
# deletions: 2,
|
|
20
|
+
# binary: false
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# @example A new file (src is nil)
|
|
24
|
+
# info = Git::DiffFileRawInfo.new(
|
|
25
|
+
# src: nil,
|
|
26
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/new.rb'),
|
|
27
|
+
# status: :added,
|
|
28
|
+
# similarity: nil,
|
|
29
|
+
# insertions: 10,
|
|
30
|
+
# deletions: 0,
|
|
31
|
+
# binary: false
|
|
32
|
+
# )
|
|
33
|
+
#
|
|
34
|
+
# @example A renamed file
|
|
35
|
+
# info = Git::DiffFileRawInfo.new(
|
|
36
|
+
# src: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/old.rb'),
|
|
37
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'def5678', path: 'lib/new.rb'),
|
|
38
|
+
# status: :renamed,
|
|
39
|
+
# similarity: 95,
|
|
40
|
+
# insertions: 2,
|
|
41
|
+
# deletions: 1,
|
|
42
|
+
# binary: false
|
|
43
|
+
# )
|
|
44
|
+
#
|
|
45
|
+
# @!attribute [r] src
|
|
46
|
+
# @return [FileRef, nil] the source file reference, or nil for new/added files
|
|
47
|
+
#
|
|
48
|
+
# @!attribute [r] dst
|
|
49
|
+
# @return [FileRef, nil] the destination file reference, or nil for deleted files
|
|
50
|
+
#
|
|
51
|
+
# @!attribute [r] status
|
|
52
|
+
# @return [Symbol] the change status (:added, :modified, :deleted, :renamed, :copied, :type_changed)
|
|
53
|
+
#
|
|
54
|
+
# @!attribute [r] similarity
|
|
55
|
+
# @return [Integer, nil] similarity percentage for renames/copies (0-100), nil otherwise
|
|
56
|
+
#
|
|
57
|
+
# @!attribute [r] insertions
|
|
58
|
+
# @return [Integer] number of lines inserted
|
|
59
|
+
#
|
|
60
|
+
# @!attribute [r] deletions
|
|
61
|
+
# @return [Integer] number of lines deleted
|
|
62
|
+
#
|
|
63
|
+
# @!attribute [r] binary
|
|
64
|
+
# @return [Boolean] whether this is a binary file
|
|
65
|
+
#
|
|
66
|
+
# @api private
|
|
67
|
+
#
|
|
68
|
+
# Work in progress; this class is internal for now and may be made public in a future release.
|
|
69
|
+
DiffFileRawInfo = Data.define(:src, :dst, :status, :similarity, :insertions, :deletions, :binary) do
|
|
70
|
+
# Get the primary file path
|
|
71
|
+
#
|
|
72
|
+
# Returns the destination path if it exists, otherwise the source path.
|
|
73
|
+
# This is the "current" or "canonical" path for the file.
|
|
74
|
+
#
|
|
75
|
+
# @return [String] the file path
|
|
76
|
+
#
|
|
77
|
+
def path
|
|
78
|
+
dst&.path || src&.path
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Get the source path (for renames/copies)
|
|
82
|
+
#
|
|
83
|
+
# @return [String, nil] the source path, or nil if file was added
|
|
84
|
+
#
|
|
85
|
+
def src_path
|
|
86
|
+
src&.path
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Check if this is a binary file
|
|
90
|
+
#
|
|
91
|
+
# @return [Boolean] true if the file is binary
|
|
92
|
+
#
|
|
93
|
+
def binary?
|
|
94
|
+
binary
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Check if this file was renamed
|
|
98
|
+
#
|
|
99
|
+
# @return [Boolean]
|
|
100
|
+
#
|
|
101
|
+
def renamed?
|
|
102
|
+
status == :renamed
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Check if this file was copied
|
|
106
|
+
#
|
|
107
|
+
# @return [Boolean]
|
|
108
|
+
#
|
|
109
|
+
def copied?
|
|
110
|
+
status == :copied
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Check if this file was added
|
|
114
|
+
#
|
|
115
|
+
# @return [Boolean]
|
|
116
|
+
#
|
|
117
|
+
def added?
|
|
118
|
+
status == :added
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Check if this file was deleted
|
|
122
|
+
#
|
|
123
|
+
# @return [Boolean]
|
|
124
|
+
#
|
|
125
|
+
def deleted?
|
|
126
|
+
status == :deleted
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Immutable value object representing a single file's diff information
|
|
5
|
+
#
|
|
6
|
+
# FileDiffInfo encapsulates the parsed data from a unified diff for one file,
|
|
7
|
+
# including the file path, patch text, mode changes, object identifiers, and type.
|
|
8
|
+
#
|
|
9
|
+
# This class is used by DiffInfo for the legacy diff API.
|
|
10
|
+
#
|
|
11
|
+
#
|
|
12
|
+
# @example Create a FileDiffInfo from parsed diff output
|
|
13
|
+
# diff_info = Git::FileDiffInfo.new(
|
|
14
|
+
# path: 'lib/example.rb',
|
|
15
|
+
# patch: "diff --git a/lib/example.rb b/lib/example.rb\n...",
|
|
16
|
+
# mode: '100644',
|
|
17
|
+
# src: 'abc1234',
|
|
18
|
+
# dst: 'def5678',
|
|
19
|
+
# type: 'modified',
|
|
20
|
+
# binary: false
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# @!attribute [r] path
|
|
24
|
+
# @return [String] the file path relative to the repository root
|
|
25
|
+
#
|
|
26
|
+
# @!attribute [r] patch
|
|
27
|
+
# @return [String] the full unified diff patch text for this file
|
|
28
|
+
#
|
|
29
|
+
# @!attribute [r] mode
|
|
30
|
+
# @return [String] the file mode (e.g., '100644' for regular files)
|
|
31
|
+
#
|
|
32
|
+
# @!attribute [r] src
|
|
33
|
+
# @return [String] the source blob object identifier
|
|
34
|
+
#
|
|
35
|
+
# @!attribute [r] dst
|
|
36
|
+
# @return [String] the destination blob object identifier
|
|
37
|
+
#
|
|
38
|
+
# @!attribute [r] type
|
|
39
|
+
# @return [String] the type of change: 'modified', 'new', 'deleted', 'renamed'
|
|
40
|
+
#
|
|
41
|
+
# @!attribute [r] binary
|
|
42
|
+
# @return [Boolean] whether this is a binary file
|
|
43
|
+
#
|
|
44
|
+
# @api private
|
|
45
|
+
#
|
|
46
|
+
# Work in progress; this class is internal for now and may be made public in a future release.
|
|
47
|
+
FileDiffInfo = Data.define(
|
|
48
|
+
:path,
|
|
49
|
+
:patch,
|
|
50
|
+
:mode,
|
|
51
|
+
:src,
|
|
52
|
+
:dst,
|
|
53
|
+
:type,
|
|
54
|
+
:binary
|
|
55
|
+
) do
|
|
56
|
+
# Check if this is a binary file
|
|
57
|
+
#
|
|
58
|
+
# @return [Boolean] true if the file is binary
|
|
59
|
+
#
|
|
60
|
+
def binary?
|
|
61
|
+
binary
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Immutable value object representing diff statistics and optional file patches
|
|
66
|
+
#
|
|
67
|
+
# DiffInfo encapsulates the parsed output from various git commands that produce
|
|
68
|
+
# diff statistics (like `git stash show --stat`). When patches are requested,
|
|
69
|
+
# it also includes the full patch information for each file.
|
|
70
|
+
#
|
|
71
|
+
# The stats hash structure:
|
|
72
|
+
# - `:total` - Hash with `:insertions`, `:deletions`, `:lines`, `:files` keys
|
|
73
|
+
# - `:files` - Hash mapping file paths to `{ insertions:, deletions: }` hashes
|
|
74
|
+
#
|
|
75
|
+
# @example Create a DiffInfo from parsed stats output
|
|
76
|
+
# info = Git::DiffInfo.new(
|
|
77
|
+
# stats: {
|
|
78
|
+
# total: { insertions: 10, deletions: 5, lines: 15, files: 2 },
|
|
79
|
+
# files: {
|
|
80
|
+
# 'lib/foo.rb' => { insertions: 8, deletions: 3 },
|
|
81
|
+
# 'lib/bar.rb' => { insertions: 2, deletions: 2 }
|
|
82
|
+
# }
|
|
83
|
+
# },
|
|
84
|
+
# file_patches: []
|
|
85
|
+
# )
|
|
86
|
+
#
|
|
87
|
+
# @example Access statistics
|
|
88
|
+
# info.insertions # => 10
|
|
89
|
+
# info.deletions # => 5
|
|
90
|
+
# info.lines # => 15
|
|
91
|
+
# info.file_count # => 2
|
|
92
|
+
#
|
|
93
|
+
# @api private
|
|
94
|
+
#
|
|
95
|
+
# Work in progress; this class is internal for now and may be made public in a future release.
|
|
96
|
+
#
|
|
97
|
+
# @!attribute [r] stats
|
|
98
|
+
# @return [Hash] the statistics hash with :total and :files keys
|
|
99
|
+
#
|
|
100
|
+
# @!attribute [r] file_patches
|
|
101
|
+
# @return [Array<FileDiffInfo>] array of file diff info objects (empty if patch not requested)
|
|
102
|
+
#
|
|
103
|
+
DiffInfo = Data.define(:stats, :file_patches) do
|
|
104
|
+
# Total number of lines inserted
|
|
105
|
+
#
|
|
106
|
+
# @return [Integer]
|
|
107
|
+
#
|
|
108
|
+
def insertions
|
|
109
|
+
stats[:total][:insertions]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Total number of lines deleted
|
|
113
|
+
#
|
|
114
|
+
# @return [Integer]
|
|
115
|
+
#
|
|
116
|
+
def deletions
|
|
117
|
+
stats[:total][:deletions]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Total number of lines changed (insertions + deletions)
|
|
121
|
+
#
|
|
122
|
+
# @return [Integer]
|
|
123
|
+
#
|
|
124
|
+
def lines
|
|
125
|
+
stats[:total][:lines]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Number of files changed
|
|
129
|
+
#
|
|
130
|
+
# @return [Integer]
|
|
131
|
+
#
|
|
132
|
+
def file_count
|
|
133
|
+
stats[:total][:files]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Per-file statistics hash
|
|
137
|
+
#
|
|
138
|
+
# @return [Hash<String, Hash>] mapping file paths to `{ insertions:, deletions: }` hashes
|
|
139
|
+
#
|
|
140
|
+
def file_stats
|
|
141
|
+
stats[:files]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Check if patch information is available
|
|
145
|
+
#
|
|
146
|
+
# @return [Boolean] true if file_patches were loaded
|
|
147
|
+
#
|
|
148
|
+
def patches?
|
|
149
|
+
!file_patches.empty?
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Get patch info for a specific file
|
|
153
|
+
#
|
|
154
|
+
# @param path [String] the file path
|
|
155
|
+
#
|
|
156
|
+
# @return [FileDiffInfo, nil] the diff info or nil if not found
|
|
157
|
+
#
|
|
158
|
+
def patch_for(path)
|
|
159
|
+
file_patches.find { |p| p.path == path }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# The files and their status (e.g., added, modified, deleted) between two commits
|
|
5
|
+
#
|
|
6
|
+
# @example Iterate over path statuses
|
|
7
|
+
# git = Git.open('/path/to/repo')
|
|
8
|
+
# git.diff_path_status.each { |path, status| puts "#{path}: #{status}" }
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
11
|
+
#
|
|
12
|
+
class DiffPathStatus
|
|
13
|
+
include Enumerable
|
|
14
|
+
|
|
15
|
+
# @private
|
|
16
|
+
#
|
|
17
|
+
# @param base_or_hash [Git::Repository, Hash{String => String}] either a
|
|
18
|
+
# repository object for legacy initialization or a pre-fetched name-status hash
|
|
19
|
+
#
|
|
20
|
+
# @param from [String, nil] the first commit/object to compare when using
|
|
21
|
+
# legacy initialization
|
|
22
|
+
#
|
|
23
|
+
# @param to [String, nil] the second commit/object to compare when using
|
|
24
|
+
# legacy initialization
|
|
25
|
+
#
|
|
26
|
+
# @param path_limiter [String, Pathname, Array, nil] path(s) to limit the
|
|
27
|
+
# diff when using legacy initialization
|
|
28
|
+
#
|
|
29
|
+
def initialize(base_or_hash, from = nil, to = nil, path_limiter = nil)
|
|
30
|
+
if base_or_hash.is_a?(Hash)
|
|
31
|
+
# New form: pre-fetched hash passed directly from Git::Repository::Diffing
|
|
32
|
+
@fetch_path_status = base_or_hash
|
|
33
|
+
else
|
|
34
|
+
# Legacy form: (base, from, to, path_limiter)
|
|
35
|
+
# Used by Git::Diff#path_status_provider and direct instantiation in tests.
|
|
36
|
+
initialize_legacy(base_or_hash, from, to, path_limiter)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Iterates over each file path and its status code
|
|
41
|
+
#
|
|
42
|
+
# @example Print each path and status
|
|
43
|
+
# diff_path_status.each { |path, status| puts "#{path}: #{status}" }
|
|
44
|
+
#
|
|
45
|
+
# @return [Enumerator, Hash{String => String}] an `Enumerator` when no block
|
|
46
|
+
# is given; the name-status hash when a block is given
|
|
47
|
+
#
|
|
48
|
+
# @yield [path, status] each file path with its git status code
|
|
49
|
+
#
|
|
50
|
+
# @yieldparam path [String] the file path relative to the repository root
|
|
51
|
+
#
|
|
52
|
+
# @yieldparam status [String] the git status code (e.g. `"M"`, `"A"`, `"D"`)
|
|
53
|
+
#
|
|
54
|
+
# @yieldreturn [void]
|
|
55
|
+
#
|
|
56
|
+
def each(&)
|
|
57
|
+
return to_enum(__method__) unless block_given?
|
|
58
|
+
|
|
59
|
+
fetch_path_status.each(&)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns the name-status report as a hash
|
|
63
|
+
#
|
|
64
|
+
# @example Basic usage
|
|
65
|
+
# diff_path_status.to_h #=> { "README.md" => "M", "lib/foo.rb" => "A" }
|
|
66
|
+
#
|
|
67
|
+
# @return [Hash{String => String}] a mapping of file paths to their status codes
|
|
68
|
+
#
|
|
69
|
+
def to_h
|
|
70
|
+
fetch_path_status
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# Lazily fetches and caches the path status from the git lib
|
|
76
|
+
#
|
|
77
|
+
# @return [Hash{String => String}] a mapping of file paths to status codes
|
|
78
|
+
#
|
|
79
|
+
def fetch_path_status
|
|
80
|
+
@fetch_path_status ||= @base.diff_name_status(@from, @to, path_limiter: @path_limiter).to_h
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Sets up legacy (base, from, to, path_limiter) instance state
|
|
84
|
+
#
|
|
85
|
+
# @param base [Git::Repository] the git object
|
|
86
|
+
#
|
|
87
|
+
# @param from [String] the first commit or object to compare
|
|
88
|
+
#
|
|
89
|
+
# @param to [String, nil] the second commit or object to compare
|
|
90
|
+
#
|
|
91
|
+
# @param path_limiter [String, Pathname, Array, nil] path(s) to limit the diff
|
|
92
|
+
#
|
|
93
|
+
# @return [void]
|
|
94
|
+
#
|
|
95
|
+
# @raise [ArgumentError] when `from` or `to` starts with `"-"`
|
|
96
|
+
#
|
|
97
|
+
def initialize_legacy(base, from, to, path_limiter)
|
|
98
|
+
[from, to].compact.each do |arg|
|
|
99
|
+
raise ArgumentError, "Invalid argument: '#{arg}'" if arg.start_with?('-')
|
|
100
|
+
end
|
|
101
|
+
@base = base
|
|
102
|
+
@from = from
|
|
103
|
+
@to = to
|
|
104
|
+
@path_limiter = path_limiter
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'dirstat_info'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
# Immutable result object from git diff commands
|
|
7
|
+
#
|
|
8
|
+
# Contains summary statistics and per-file information from various diff formats.
|
|
9
|
+
# The `files` array contains one of:
|
|
10
|
+
# - DiffFileNumstatInfo (from --numstat)
|
|
11
|
+
# - DiffFileRawInfo (from --raw)
|
|
12
|
+
# - DiffFilePatchInfo (from --patch)
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
#
|
|
16
|
+
# Work in progress; this class is internal for now and may be made public in a future release.
|
|
17
|
+
#
|
|
18
|
+
# @!attribute [r] files_changed
|
|
19
|
+
# @return [Integer] number of files changed (from --shortstat)
|
|
20
|
+
#
|
|
21
|
+
# @!attribute [r] total_insertions
|
|
22
|
+
# @return [Integer] total lines inserted across all files (from --shortstat)
|
|
23
|
+
#
|
|
24
|
+
# @!attribute [r] total_deletions
|
|
25
|
+
# @return [Integer] total lines deleted across all files (from --shortstat)
|
|
26
|
+
#
|
|
27
|
+
# @!attribute [r] files
|
|
28
|
+
# @return [Array<DiffFileNumstatInfo, DiffFileRawInfo, DiffFilePatchInfo>] per-file information
|
|
29
|
+
#
|
|
30
|
+
# @!attribute [r] dirstat
|
|
31
|
+
# @return [DirstatInfo, nil] directory statistics if requested, nil otherwise
|
|
32
|
+
#
|
|
33
|
+
DiffResult = Data.define(:files_changed, :total_insertions, :total_deletions, :files, :dirstat)
|
|
34
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Lazy diff statistics for a comparison between two trees
|
|
5
|
+
#
|
|
6
|
+
# Supports comparing (1) two commits, (2) a commit against the working tree,
|
|
7
|
+
# or (3) the index against the working tree.
|
|
8
|
+
#
|
|
9
|
+
# @example Get the insertion and deletion counts
|
|
10
|
+
# stats = repo.diff_stats
|
|
11
|
+
# stats.insertions #=> 3
|
|
12
|
+
# stats.deletions #=> 1
|
|
13
|
+
#
|
|
14
|
+
# @api public
|
|
15
|
+
class DiffStats
|
|
16
|
+
# Initializes diff-stats state for a tree comparison.
|
|
17
|
+
#
|
|
18
|
+
# @private
|
|
19
|
+
#
|
|
20
|
+
# @param base [Git::Repository] the git object used to fetch diff stats
|
|
21
|
+
#
|
|
22
|
+
# @param from [String] the first commit or object to compare
|
|
23
|
+
#
|
|
24
|
+
# @param to [String, nil] the second commit or object to compare
|
|
25
|
+
#
|
|
26
|
+
# @param path_limiter [String, Pathname, Array<String, Pathname>, nil]
|
|
27
|
+
# path(s) to limit the diff
|
|
28
|
+
#
|
|
29
|
+
# @return [void]
|
|
30
|
+
#
|
|
31
|
+
# @raise [ArgumentError] when `from` or `to` starts with `"-"`
|
|
32
|
+
def initialize(base, from, to, path_limiter = nil)
|
|
33
|
+
# Eagerly check for invalid arguments
|
|
34
|
+
[from, to].compact.each do |arg|
|
|
35
|
+
raise ArgumentError, "Invalid argument: '#{arg}'" if arg.start_with?('-')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@base = base
|
|
39
|
+
@from = from
|
|
40
|
+
@to = to
|
|
41
|
+
@path_limiter = path_limiter
|
|
42
|
+
@fetch_stats = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns the total number of lines deleted
|
|
46
|
+
#
|
|
47
|
+
# @example Get the deletion count
|
|
48
|
+
# stats = repo.diff_stats
|
|
49
|
+
# stats.deletions #=> 5
|
|
50
|
+
#
|
|
51
|
+
# @return [Integer] the total deletion count
|
|
52
|
+
def deletions
|
|
53
|
+
fetch_stats[:total][:deletions]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns the total number of lines inserted
|
|
57
|
+
#
|
|
58
|
+
# @example Get the insertion count
|
|
59
|
+
# stats = repo.diff_stats
|
|
60
|
+
# stats.insertions #=> 3
|
|
61
|
+
#
|
|
62
|
+
# @return [Integer] the total insertion count
|
|
63
|
+
def insertions
|
|
64
|
+
fetch_stats[:total][:insertions]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the total number of lines changed (insertions + deletions)
|
|
68
|
+
#
|
|
69
|
+
# @example Get the total changed-line count
|
|
70
|
+
# stats = repo.diff_stats
|
|
71
|
+
# stats.lines #=> 8
|
|
72
|
+
#
|
|
73
|
+
# @return [Integer] the total changed-line count
|
|
74
|
+
def lines
|
|
75
|
+
fetch_stats[:total][:lines]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns a hash of statistics for each file in the diff
|
|
79
|
+
#
|
|
80
|
+
# @example Get per-file statistics
|
|
81
|
+
# stats = repo.diff_stats
|
|
82
|
+
# stats.files #=> { "lib/foo.rb" => { insertions: 3, deletions: 1 } }
|
|
83
|
+
#
|
|
84
|
+
# @return [Hash{String=>Hash{Symbol=>Integer}}]
|
|
85
|
+
# per-file statistics keyed by file path
|
|
86
|
+
def files
|
|
87
|
+
fetch_stats[:files]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns a hash of the total statistics for the diff
|
|
91
|
+
#
|
|
92
|
+
# @example Get total statistics
|
|
93
|
+
# stats = repo.diff_stats
|
|
94
|
+
# stats.total #=> { insertions: 3, deletions: 1, lines: 4, files: 1 }
|
|
95
|
+
#
|
|
96
|
+
# @return [Hash{Symbol=>Integer}]
|
|
97
|
+
# aggregate statistics for the entire diff
|
|
98
|
+
def total
|
|
99
|
+
fetch_stats[:total]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# Lazily fetches and caches the stats from the git lib
|
|
105
|
+
#
|
|
106
|
+
# @return [Hash] the fetched stats hash
|
|
107
|
+
def fetch_stats
|
|
108
|
+
@fetch_stats ||= @base.diff_numstat(@from, @to, path_limiter: @path_limiter)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|