git 4.3.2 → 5.0.0.beta.2
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/.github/copilot-instructions.md +73 -2705
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
- data/.github/pull_request_template.md +3 -1
- data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
- data/.github/skills/command-implementation/REFERENCE.md +993 -0
- data/.github/skills/command-implementation/SKILL.md +229 -0
- data/.github/skills/command-test-conventions/SKILL.md +660 -0
- data/.github/skills/command-yard-documentation/SKILL.md +426 -0
- data/.github/skills/dependency-management/SKILL.md +72 -0
- data/.github/skills/development-workflow/SKILL.md +506 -0
- data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
- data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +274 -0
- data/.github/skills/facade-test-conventions/SKILL.md +394 -0
- data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
- data/.github/skills/make-skill-template/SKILL.md +176 -0
- data/.github/skills/pr-readiness-review/SKILL.md +185 -0
- data/.github/skills/project-context/SKILL.md +313 -0
- data/.github/skills/pull-request-review/SKILL.md +168 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
- data/.github/skills/release-management/SKILL.md +125 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
- data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
- data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
- data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
- data/.github/skills/reviewing-skills/SKILL.md +189 -0
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
- data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
- data/.github/skills/test-debugging/SKILL.md +160 -0
- data/.github/skills/yard-documentation/SKILL.md +793 -0
- data/.github/workflows/continuous_integration.yml +3 -2
- data/.github/workflows/enforce_conventional_commits.yml +1 -1
- data/.github/workflows/experimental_continuous_integration.yml +2 -2
- data/.github/workflows/release.yml +3 -4
- data/.gitignore +8 -0
- data/.husky/pre-commit +13 -0
- data/.release-please-manifest.json +1 -1
- data/.rspec +3 -0
- data/.rubocop.yml +12 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -40
- data/CONTRIBUTING.md +694 -53
- data/README.md +67 -15
- data/Rakefile +61 -9
- data/UPGRADING.md +141 -0
- data/commitlint.test +4 -0
- data/git.gemspec +18 -7
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/branch.rb +369 -43
- data/lib/git/branch_delete_failure.rb +31 -0
- data/lib/git/branch_delete_result.rb +63 -0
- data/lib/git/branch_info.rb +178 -0
- data/lib/git/branches.rb +122 -24
- data/lib/git/command_line/base.rb +255 -0
- data/lib/git/command_line/capturing.rb +251 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +196 -0
- data/lib/git/command_line.rb +43 -322
- data/lib/git/command_line_result.rb +4 -88
- data/lib/git/commands/add.rb +131 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +252 -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 +47 -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 +237 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +140 -0
- data/lib/git/commands/arguments.rb +3510 -0
- data/lib/git/commands/base.rb +404 -0
- data/lib/git/commands/branch/copy.rb +94 -0
- data/lib/git/commands/branch/create.rb +173 -0
- data/lib/git/commands/branch/delete.rb +80 -0
- data/lib/git/commands/branch/list.rb +162 -0
- data/lib/git/commands/branch/move.rb +94 -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 +57 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +369 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +216 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +151 -0
- data/lib/git/commands/checkout/files.rb +115 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +105 -0
- data/lib/git/commands/clean.rb +100 -0
- data/lib/git/commands/clone.rb +240 -0
- data/lib/git/commands/commit.rb +272 -0
- data/lib/git/commands/commit_tree.rb +100 -0
- data/lib/git/commands/config_option_syntax/add.rb +83 -0
- data/lib/git/commands/config_option_syntax/get.rb +117 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
- data/lib/git/commands/config_option_syntax/list.rb +107 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
- data/lib/git/commands/config_option_syntax/set.rb +114 -0
- data/lib/git/commands/config_option_syntax/unset.rb +89 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +155 -0
- data/lib/git/commands/diff.rb +656 -0
- data/lib/git/commands/diff_files.rb +518 -0
- data/lib/git/commands/diff_index.rb +496 -0
- data/lib/git/commands/fetch.rb +352 -0
- data/lib/git/commands/fsck.rb +136 -0
- data/lib/git/commands/gc.rb +132 -0
- data/lib/git/commands/grep.rb +338 -0
- data/lib/git/commands/init.rb +99 -0
- data/lib/git/commands/log.rb +632 -0
- data/lib/git/commands/ls_files.rb +191 -0
- data/lib/git/commands/ls_remote.rb +155 -0
- data/lib/git/commands/ls_tree.rb +131 -0
- data/lib/git/commands/maintenance/register.rb +75 -0
- data/lib/git/commands/maintenance/run.rb +104 -0
- data/lib/git/commands/maintenance/start.rb +66 -0
- data/lib/git/commands/maintenance/stop.rb +55 -0
- data/lib/git/commands/maintenance/unregister.rb +79 -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 +245 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +86 -0
- data/lib/git/commands/mv.rb +77 -0
- data/lib/git/commands/name_rev.rb +114 -0
- data/lib/git/commands/pull.rb +377 -0
- data/lib/git/commands/push.rb +246 -0
- data/lib/git/commands/read_tree.rb +149 -0
- data/lib/git/commands/remote/add.rb +91 -0
- data/lib/git/commands/remote/get_url.rb +66 -0
- data/lib/git/commands/remote/list.rb +54 -0
- data/lib/git/commands/remote/prune.rb +61 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +69 -0
- data/lib/git/commands/remote/set_branches.rb +63 -0
- data/lib/git/commands/remote/set_head.rb +82 -0
- data/lib/git/commands/remote/set_url.rb +71 -0
- data/lib/git/commands/remote/set_url_add.rb +61 -0
- data/lib/git/commands/remote/set_url_delete.rb +64 -0
- data/lib/git/commands/remote/show.rb +71 -0
- data/lib/git/commands/remote/update.rb +72 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +277 -0
- data/lib/git/commands/reset.rb +147 -0
- data/lib/git/commands/rev_parse.rb +297 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +57 -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 +153 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +114 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
- data/lib/git/commands/show_ref/exists.rb +78 -0
- data/lib/git/commands/show_ref/list.rb +145 -0
- data/lib/git/commands/show_ref/verify.rb +120 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +75 -0
- data/lib/git/commands/stash/branch.rb +65 -0
- data/lib/git/commands/stash/clear.rb +41 -0
- data/lib/git/commands/stash/create.rb +58 -0
- data/lib/git/commands/stash/drop.rb +67 -0
- data/lib/git/commands/stash/list.rb +39 -0
- data/lib/git/commands/stash/pop.rb +78 -0
- data/lib/git/commands/stash/push.rb +103 -0
- data/lib/git/commands/stash/show.rb +149 -0
- data/lib/git/commands/stash/store.rb +63 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +169 -0
- data/lib/git/commands/symbolic_ref/delete.rb +68 -0
- data/lib/git/commands/symbolic_ref/read.rb +95 -0
- data/lib/git/commands/symbolic_ref/update.rb +76 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +139 -0
- data/lib/git/commands/tag/delete.rb +55 -0
- data/lib/git/commands/tag/list.rb +143 -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 +140 -0
- data/lib/git/commands/update_ref/delete.rb +92 -0
- data/lib/git/commands/update_ref/update.rb +106 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +57 -0
- data/lib/git/commands/worktree/add.rb +140 -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 +87 -0
- data/lib/git/config.rb +17 -0
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +665 -0
- data/lib/git/deprecation.rb +9 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +293 -7
- data/lib/git/diff_file_numstat_info.rb +29 -0
- data/lib/git/diff_file_patch_info.rb +134 -0
- data/lib/git/diff_file_raw_info.rb +127 -0
- data/lib/git/diff_info.rb +169 -0
- data/lib/git/diff_path_status.rb +67 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +51 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +31 -0
- data/lib/git/execution_context/repository.rb +136 -0
- data/lib/git/execution_context.rb +501 -0
- data/lib/git/file_ref.rb +74 -0
- data/lib/git/fsck_object.rb +9 -9
- data/lib/git/fsck_result.rb +1 -1
- data/lib/git/log.rb +9 -2
- data/lib/git/object.rb +90 -27
- data/lib/git/parsers/branch.rb +224 -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 +585 -0
- data/lib/git/parsers/fsck.rb +133 -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/stash.rb +208 -0
- data/lib/git/parsers/tag.rb +257 -0
- data/lib/git/remote.rb +120 -9
- data/lib/git/repository/branching.rb +743 -0
- data/lib/git/repository/committing.rb +187 -0
- data/lib/git/repository/configuring.rb +351 -0
- data/lib/git/repository/context_helpers.rb +264 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/factories.rb +682 -0
- data/lib/git/repository/inspecting.rb +252 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +357 -0
- data/lib/git/repository/object_operations.rb +1199 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +898 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +554 -0
- data/lib/git/repository/stashing.rb +143 -0
- data/lib/git/repository/status_operations.rb +201 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +203 -1
- data/lib/git/stash.rb +78 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +125 -13
- data/lib/git/status.rb +215 -18
- data/lib/git/tag_delete_failure.rb +31 -0
- data/lib/git/tag_delete_result.rb +63 -0
- data/lib/git/tag_info.rb +105 -0
- data/lib/git/version.rb +109 -2
- data/lib/git/version_constraint.rb +81 -0
- data/lib/git/worktree.rb +108 -6
- data/lib/git/worktrees.rb +94 -7
- data/lib/git.rb +260 -61
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1497 -63
- data/redesign/Phase 4 - Step A.md +360 -0
- data/redesign/beta_release.md +107 -0
- data/redesign/c1c2_audit.md +566 -0
- data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
- data/redesign/config_design.rb +501 -0
- data/tasks/gem_tasks.rake +4 -0
- data/tasks/npm_tasks.rake +7 -0
- data/tasks/rspec.rake +48 -0
- data/tasks/test.rake +13 -1
- data/tasks/yard.rake +34 -7
- metadata +365 -22
- data/lib/git/base.rb +0 -1128
- data/lib/git/index.rb +0 -6
- data/lib/git/lib.rb +0 -2277
- data/lib/git/path.rb +0 -38
- data/lib/git/working_directory.rb +0 -6
- /data/{release-please-config.json → .release-please-config.json} +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
# @api public
|
|
12
|
+
#
|
|
13
|
+
# @example A modified file
|
|
14
|
+
# info = Git::DiffFileRawInfo.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
|
+
# status: :modified,
|
|
18
|
+
# similarity: nil,
|
|
19
|
+
# insertions: 5,
|
|
20
|
+
# deletions: 2,
|
|
21
|
+
# binary: false
|
|
22
|
+
# )
|
|
23
|
+
#
|
|
24
|
+
# @example A new file (src is nil)
|
|
25
|
+
# info = Git::DiffFileRawInfo.new(
|
|
26
|
+
# src: nil,
|
|
27
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/new.rb'),
|
|
28
|
+
# status: :added,
|
|
29
|
+
# similarity: nil,
|
|
30
|
+
# insertions: 10,
|
|
31
|
+
# deletions: 0,
|
|
32
|
+
# binary: false
|
|
33
|
+
# )
|
|
34
|
+
#
|
|
35
|
+
# @example A renamed file
|
|
36
|
+
# info = Git::DiffFileRawInfo.new(
|
|
37
|
+
# src: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/old.rb'),
|
|
38
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'def5678', path: 'lib/new.rb'),
|
|
39
|
+
# status: :renamed,
|
|
40
|
+
# similarity: 95,
|
|
41
|
+
# insertions: 2,
|
|
42
|
+
# deletions: 1,
|
|
43
|
+
# binary: false
|
|
44
|
+
# )
|
|
45
|
+
#
|
|
46
|
+
# @!attribute [r] src
|
|
47
|
+
# @return [FileRef, nil] the source file reference, or nil for new/added files
|
|
48
|
+
#
|
|
49
|
+
# @!attribute [r] dst
|
|
50
|
+
# @return [FileRef, nil] the destination file reference, or nil for deleted files
|
|
51
|
+
#
|
|
52
|
+
# @!attribute [r] status
|
|
53
|
+
# @return [Symbol] the change status (:added, :modified, :deleted, :renamed, :copied, :type_changed)
|
|
54
|
+
#
|
|
55
|
+
# @!attribute [r] similarity
|
|
56
|
+
# @return [Integer, nil] similarity percentage for renames/copies (0-100), nil otherwise
|
|
57
|
+
#
|
|
58
|
+
# @!attribute [r] insertions
|
|
59
|
+
# @return [Integer] number of lines inserted
|
|
60
|
+
#
|
|
61
|
+
# @!attribute [r] deletions
|
|
62
|
+
# @return [Integer] number of lines deleted
|
|
63
|
+
#
|
|
64
|
+
# @!attribute [r] binary
|
|
65
|
+
# @return [Boolean] whether this is a binary file
|
|
66
|
+
#
|
|
67
|
+
DiffFileRawInfo = Data.define(:src, :dst, :status, :similarity, :insertions, :deletions, :binary) do
|
|
68
|
+
# Get the primary file path
|
|
69
|
+
#
|
|
70
|
+
# Returns the destination path if it exists, otherwise the source path.
|
|
71
|
+
# This is the "current" or "canonical" path for the file.
|
|
72
|
+
#
|
|
73
|
+
# @return [String] the file path
|
|
74
|
+
#
|
|
75
|
+
def path
|
|
76
|
+
dst&.path || src&.path
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Get the source path (for renames/copies)
|
|
80
|
+
#
|
|
81
|
+
# @return [String, nil] the source path, or nil if file was added
|
|
82
|
+
#
|
|
83
|
+
def src_path
|
|
84
|
+
src&.path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Check if this is a binary file
|
|
88
|
+
#
|
|
89
|
+
# @return [Boolean] true if the file is binary
|
|
90
|
+
#
|
|
91
|
+
def binary?
|
|
92
|
+
binary
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Check if this file was renamed
|
|
96
|
+
#
|
|
97
|
+
# @return [Boolean]
|
|
98
|
+
#
|
|
99
|
+
def renamed?
|
|
100
|
+
status == :renamed
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Check if this file was copied
|
|
104
|
+
#
|
|
105
|
+
# @return [Boolean]
|
|
106
|
+
#
|
|
107
|
+
def copied?
|
|
108
|
+
status == :copied
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Check if this file was added
|
|
112
|
+
#
|
|
113
|
+
# @return [Boolean]
|
|
114
|
+
#
|
|
115
|
+
def added?
|
|
116
|
+
status == :added
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Check if this file was deleted
|
|
120
|
+
#
|
|
121
|
+
# @return [Boolean]
|
|
122
|
+
#
|
|
123
|
+
def deleted?
|
|
124
|
+
status == :deleted
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
# @api public
|
|
12
|
+
#
|
|
13
|
+
# @example Create a FileDiffInfo from parsed diff output
|
|
14
|
+
# diff_info = Git::FileDiffInfo.new(
|
|
15
|
+
# path: 'lib/example.rb',
|
|
16
|
+
# patch: "diff --git a/lib/example.rb b/lib/example.rb\n...",
|
|
17
|
+
# mode: '100644',
|
|
18
|
+
# src: 'abc1234',
|
|
19
|
+
# dst: 'def5678',
|
|
20
|
+
# type: 'modified',
|
|
21
|
+
# binary: false
|
|
22
|
+
# )
|
|
23
|
+
#
|
|
24
|
+
# @!attribute [r] path
|
|
25
|
+
# @return [String] the file path relative to the repository root
|
|
26
|
+
#
|
|
27
|
+
# @!attribute [r] patch
|
|
28
|
+
# @return [String] the full unified diff patch text for this file
|
|
29
|
+
#
|
|
30
|
+
# @!attribute [r] mode
|
|
31
|
+
# @return [String] the file mode (e.g., '100644' for regular files)
|
|
32
|
+
#
|
|
33
|
+
# @!attribute [r] src
|
|
34
|
+
# @return [String] the source blob object identifier
|
|
35
|
+
#
|
|
36
|
+
# @!attribute [r] dst
|
|
37
|
+
# @return [String] the destination blob object identifier
|
|
38
|
+
#
|
|
39
|
+
# @!attribute [r] type
|
|
40
|
+
# @return [String] the type of change: 'modified', 'new', 'deleted', 'renamed'
|
|
41
|
+
#
|
|
42
|
+
# @!attribute [r] binary
|
|
43
|
+
# @return [Boolean] whether this is a binary file
|
|
44
|
+
#
|
|
45
|
+
FileDiffInfo = Data.define(
|
|
46
|
+
:path,
|
|
47
|
+
:patch,
|
|
48
|
+
:mode,
|
|
49
|
+
:src,
|
|
50
|
+
:dst,
|
|
51
|
+
:type,
|
|
52
|
+
:binary
|
|
53
|
+
) do
|
|
54
|
+
# Check if this is a binary file
|
|
55
|
+
#
|
|
56
|
+
# @return [Boolean] true if the file is binary
|
|
57
|
+
#
|
|
58
|
+
def binary?
|
|
59
|
+
binary
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Immutable value object representing diff statistics and optional file patches
|
|
64
|
+
#
|
|
65
|
+
# DiffInfo encapsulates the parsed output from various git commands that produce
|
|
66
|
+
# diff statistics (like `git stash show --stat`). When patches are requested,
|
|
67
|
+
# it also includes the full patch information for each file.
|
|
68
|
+
#
|
|
69
|
+
# The stats hash structure:
|
|
70
|
+
# - `:total` - Hash with `:insertions`, `:deletions`, `:lines`, `:files` keys
|
|
71
|
+
# - `:files` - Hash mapping file paths to `{ insertions:, deletions: }` hashes
|
|
72
|
+
#
|
|
73
|
+
# @api public
|
|
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
|
+
# @!attribute [r] stats
|
|
94
|
+
# @return [Hash] the statistics hash with :total and :files keys
|
|
95
|
+
#
|
|
96
|
+
# @!attribute [r] file_patches
|
|
97
|
+
# @return [Array<FileDiffInfo>] array of file diff info objects (empty if patch not requested)
|
|
98
|
+
#
|
|
99
|
+
DiffInfo = Data.define(:stats, :file_patches) do
|
|
100
|
+
# @!method insertions
|
|
101
|
+
# @return [Integer] total number of lines inserted
|
|
102
|
+
|
|
103
|
+
# @!method deletions
|
|
104
|
+
# @return [Integer] total number of lines deleted
|
|
105
|
+
|
|
106
|
+
# @!method lines
|
|
107
|
+
# @return [Integer] total number of lines changed (insertions + deletions)
|
|
108
|
+
|
|
109
|
+
# @!method file_count
|
|
110
|
+
# @return [Integer] number of files changed
|
|
111
|
+
|
|
112
|
+
# Total number of lines inserted
|
|
113
|
+
#
|
|
114
|
+
# @return [Integer]
|
|
115
|
+
#
|
|
116
|
+
def insertions
|
|
117
|
+
stats[:total][:insertions]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Total number of lines deleted
|
|
121
|
+
#
|
|
122
|
+
# @return [Integer]
|
|
123
|
+
#
|
|
124
|
+
def deletions
|
|
125
|
+
stats[:total][:deletions]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Total number of lines changed (insertions + deletions)
|
|
129
|
+
#
|
|
130
|
+
# @return [Integer]
|
|
131
|
+
#
|
|
132
|
+
def lines
|
|
133
|
+
stats[:total][:lines]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Number of files changed
|
|
137
|
+
#
|
|
138
|
+
# @return [Integer]
|
|
139
|
+
#
|
|
140
|
+
def file_count
|
|
141
|
+
stats[:total][:files]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Per-file statistics hash
|
|
145
|
+
#
|
|
146
|
+
# @return [Hash<String, Hash>] mapping file paths to `{ insertions:, deletions: }` hashes
|
|
147
|
+
#
|
|
148
|
+
def file_stats
|
|
149
|
+
stats[:files]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Check if patch information is available
|
|
153
|
+
#
|
|
154
|
+
# @return [Boolean] true if file_patches were loaded
|
|
155
|
+
#
|
|
156
|
+
def patches?
|
|
157
|
+
!file_patches.empty?
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Get patch info for a specific file
|
|
161
|
+
#
|
|
162
|
+
# @param path [String] the file path
|
|
163
|
+
# @return [FileDiffInfo, nil] the diff info or nil if not found
|
|
164
|
+
#
|
|
165
|
+
def patch_for(path)
|
|
166
|
+
file_patches.find { |p| p.path == path }
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
data/lib/git/diff_path_status.rb
CHANGED
|
@@ -2,45 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
module Git
|
|
4
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
|
+
#
|
|
5
12
|
class DiffPathStatus
|
|
6
13
|
include Enumerable
|
|
7
14
|
|
|
8
15
|
# @private
|
|
9
|
-
def initialize(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
def initialize(base_or_hash, from = nil, to = nil, path_limiter = nil)
|
|
17
|
+
if base_or_hash.is_a?(Hash)
|
|
18
|
+
# New form: pre-fetched hash passed directly from Git::Repository::Diffing
|
|
19
|
+
@fetch_path_status = base_or_hash
|
|
20
|
+
else
|
|
21
|
+
# Legacy form: (base, from, to, path_limiter)
|
|
22
|
+
# Used by Git::Diff#path_status_provider and direct instantiation in tests.
|
|
23
|
+
initialize_legacy(base_or_hash, from, to, path_limiter)
|
|
13
24
|
end
|
|
14
|
-
|
|
15
|
-
@base = base
|
|
16
|
-
@from = from
|
|
17
|
-
@to = to
|
|
18
|
-
@path_limiter = path_limiter
|
|
19
|
-
@path_status = nil
|
|
20
25
|
end
|
|
21
26
|
|
|
22
|
-
# Iterates over each file
|
|
27
|
+
# Iterates over each file path and its status code
|
|
28
|
+
#
|
|
29
|
+
# @example Print each path and status
|
|
30
|
+
# diff_path_status.each { |path, status| puts "#{path}: #{status}" }
|
|
31
|
+
#
|
|
32
|
+
# @yield [path, status] each file path with its git status code
|
|
33
|
+
#
|
|
34
|
+
# @yieldparam path [String] the file path relative to the repository root
|
|
35
|
+
#
|
|
36
|
+
# @yieldparam status [String] the git status code (e.g. `"M"`, `"A"`, `"D"`)
|
|
37
|
+
#
|
|
38
|
+
# @yieldreturn [void]
|
|
39
|
+
#
|
|
40
|
+
# @return [Enumerator, Hash{String => String}] an `Enumerator` when no block
|
|
41
|
+
# is given; the name-status hash when a block is given
|
|
23
42
|
#
|
|
24
|
-
# @yield [path, status]
|
|
25
43
|
def each(&)
|
|
44
|
+
return to_enum(__method__) unless block_given?
|
|
45
|
+
|
|
26
46
|
fetch_path_status.each(&)
|
|
27
47
|
end
|
|
28
48
|
|
|
29
|
-
# Returns the name-status report as a
|
|
49
|
+
# Returns the name-status report as a hash
|
|
50
|
+
#
|
|
51
|
+
# @example Basic usage
|
|
52
|
+
# diff_path_status.to_h #=> { "README.md" => "M", "lib/foo.rb" => "A" }
|
|
53
|
+
#
|
|
54
|
+
# @return [Hash{String => String}] a mapping of file paths to their status codes
|
|
30
55
|
#
|
|
31
|
-
# @return [Hash<String, String>] A hash where keys are file paths
|
|
32
|
-
# and values are their status codes.
|
|
33
56
|
def to_h
|
|
34
57
|
fetch_path_status
|
|
35
58
|
end
|
|
36
59
|
|
|
37
60
|
private
|
|
38
61
|
|
|
39
|
-
# Lazily fetches and caches the path status from the git lib
|
|
62
|
+
# Lazily fetches and caches the path status from the git lib
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash{String => String}] a mapping of file paths to status codes
|
|
65
|
+
#
|
|
40
66
|
def fetch_path_status
|
|
41
|
-
@fetch_path_status ||= @base.
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
@fetch_path_status ||= @base.diff_name_status(@from, @to, path_limiter: @path_limiter).to_h
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Sets up legacy (base, from, to, path_limiter) instance state
|
|
71
|
+
#
|
|
72
|
+
# @param base [Git::Repository] the git object
|
|
73
|
+
#
|
|
74
|
+
# @param from [String] the first commit or object to compare
|
|
75
|
+
#
|
|
76
|
+
# @param to [String, nil] the second commit or object to compare
|
|
77
|
+
#
|
|
78
|
+
# @param path_limiter [String, Pathname, Array, nil] path(s) to limit the diff
|
|
79
|
+
#
|
|
80
|
+
# @return [void]
|
|
81
|
+
#
|
|
82
|
+
# @raise [ArgumentError] when `from` or `to` starts with `"-"`
|
|
83
|
+
#
|
|
84
|
+
def initialize_legacy(base, from, to, path_limiter)
|
|
85
|
+
[from, to].compact.each do |arg|
|
|
86
|
+
raise ArgumentError, "Invalid argument: '#{arg}'" if arg.start_with?('-')
|
|
87
|
+
end
|
|
88
|
+
@base = base
|
|
89
|
+
@from = from
|
|
90
|
+
@to = to
|
|
91
|
+
@path_limiter = path_limiter
|
|
44
92
|
end
|
|
45
93
|
end
|
|
46
94
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
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 public
|
|
15
|
+
#
|
|
16
|
+
# @!attribute [r] files_changed
|
|
17
|
+
# @return [Integer] number of files changed (from --shortstat)
|
|
18
|
+
#
|
|
19
|
+
# @!attribute [r] total_insertions
|
|
20
|
+
# @return [Integer] total lines inserted across all files (from --shortstat)
|
|
21
|
+
#
|
|
22
|
+
# @!attribute [r] total_deletions
|
|
23
|
+
# @return [Integer] total lines deleted across all files (from --shortstat)
|
|
24
|
+
#
|
|
25
|
+
# @!attribute [r] files
|
|
26
|
+
# @return [Array<DiffFileNumstatInfo, DiffFileRawInfo, DiffFilePatchInfo>] per-file information
|
|
27
|
+
#
|
|
28
|
+
# @!attribute [r] dirstat
|
|
29
|
+
# @return [DirstatInfo, nil] directory statistics if requested, nil otherwise
|
|
30
|
+
#
|
|
31
|
+
DiffResult = Data.define(:files_changed, :total_insertions, :total_deletions, :files, :dirstat)
|
|
32
|
+
end
|
data/lib/git/diff_stats.rb
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Git
|
|
4
|
-
#
|
|
5
|
-
#
|
|
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
|
|
6
15
|
class DiffStats
|
|
7
16
|
# @private
|
|
8
17
|
def initialize(base, from, to, path_limiter = nil)
|
|
@@ -15,45 +24,73 @@ module Git
|
|
|
15
24
|
@from = from
|
|
16
25
|
@to = to
|
|
17
26
|
@path_limiter = path_limiter
|
|
18
|
-
@
|
|
27
|
+
@fetch_stats = nil
|
|
19
28
|
end
|
|
20
29
|
|
|
21
|
-
# Returns the total number of lines deleted
|
|
30
|
+
# Returns the total number of lines deleted
|
|
31
|
+
#
|
|
32
|
+
# @example Get the deletion count
|
|
33
|
+
# stats = repo.diff_stats
|
|
34
|
+
# stats.deletions #=> 5
|
|
35
|
+
#
|
|
36
|
+
# @return [Integer] the total deletion count
|
|
22
37
|
def deletions
|
|
23
38
|
fetch_stats[:total][:deletions]
|
|
24
39
|
end
|
|
25
40
|
|
|
26
|
-
# Returns the total number of lines inserted
|
|
41
|
+
# Returns the total number of lines inserted
|
|
42
|
+
#
|
|
43
|
+
# @example Get the insertion count
|
|
44
|
+
# stats = repo.diff_stats
|
|
45
|
+
# stats.insertions #=> 3
|
|
46
|
+
#
|
|
47
|
+
# @return [Integer] the total insertion count
|
|
27
48
|
def insertions
|
|
28
49
|
fetch_stats[:total][:insertions]
|
|
29
50
|
end
|
|
30
51
|
|
|
31
|
-
# Returns the total number of lines changed (insertions + deletions)
|
|
52
|
+
# Returns the total number of lines changed (insertions + deletions)
|
|
53
|
+
#
|
|
54
|
+
# @example Get the total changed-line count
|
|
55
|
+
# stats = repo.diff_stats
|
|
56
|
+
# stats.lines #=> 8
|
|
57
|
+
#
|
|
58
|
+
# @return [Integer] the total changed-line count
|
|
32
59
|
def lines
|
|
33
60
|
fetch_stats[:total][:lines]
|
|
34
61
|
end
|
|
35
62
|
|
|
36
|
-
# Returns a hash of statistics for each file in the diff
|
|
63
|
+
# Returns a hash of statistics for each file in the diff
|
|
64
|
+
#
|
|
65
|
+
# @example Get per-file statistics
|
|
66
|
+
# stats = repo.diff_stats
|
|
67
|
+
# stats.files #=> { "lib/foo.rb" => { insertions: 3, deletions: 1 } }
|
|
37
68
|
#
|
|
38
|
-
# @return [Hash
|
|
69
|
+
# @return [Hash{String=>Hash{Symbol=>Integer}}]
|
|
70
|
+
# per-file statistics keyed by file path
|
|
39
71
|
def files
|
|
40
72
|
fetch_stats[:files]
|
|
41
73
|
end
|
|
42
74
|
|
|
43
|
-
# Returns a hash of the total statistics for the diff
|
|
75
|
+
# Returns a hash of the total statistics for the diff
|
|
44
76
|
#
|
|
45
|
-
# @
|
|
77
|
+
# @example Get total statistics
|
|
78
|
+
# stats = repo.diff_stats
|
|
79
|
+
# stats.total #=> { insertions: 3, deletions: 1, lines: 4, files: 1 }
|
|
80
|
+
#
|
|
81
|
+
# @return [Hash{Symbol=>Integer}]
|
|
82
|
+
# aggregate statistics for the entire diff
|
|
46
83
|
def total
|
|
47
84
|
fetch_stats[:total]
|
|
48
85
|
end
|
|
49
86
|
|
|
50
87
|
private
|
|
51
88
|
|
|
52
|
-
# Lazily fetches and caches the stats from the git lib
|
|
89
|
+
# Lazily fetches and caches the stats from the git lib
|
|
90
|
+
#
|
|
91
|
+
# @return [Hash] the fetched stats hash
|
|
53
92
|
def fetch_stats
|
|
54
|
-
@fetch_stats ||= @base.
|
|
55
|
-
@from, @to, { path_limiter: @path_limiter }
|
|
56
|
-
)
|
|
93
|
+
@fetch_stats ||= @base.diff_numstat(@from, @to, path_limiter: @path_limiter)
|
|
57
94
|
end
|
|
58
95
|
end
|
|
59
96
|
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Immutable value object representing a single directory's contribution to a diff
|
|
5
|
+
#
|
|
6
|
+
# @api public
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# info = Git::DirstatEntry.new(directory: 'lib/commands/', percentage: 45.2)
|
|
10
|
+
# info.directory #=> "lib/commands/"
|
|
11
|
+
# info.percentage #=> 45.2
|
|
12
|
+
#
|
|
13
|
+
# @!attribute [r] directory
|
|
14
|
+
# @return [String] the directory path (always ends with '/')
|
|
15
|
+
#
|
|
16
|
+
# @!attribute [r] percentage
|
|
17
|
+
# @return [Float] the percentage of changes in this directory (0.0-100.0)
|
|
18
|
+
#
|
|
19
|
+
DirstatEntry = Data.define(:directory, :percentage)
|
|
20
|
+
|
|
21
|
+
# Immutable result object from git --dirstat output
|
|
22
|
+
#
|
|
23
|
+
# Contains the list of directories and their contribution percentages to the diff.
|
|
24
|
+
#
|
|
25
|
+
# @api public
|
|
26
|
+
#
|
|
27
|
+
# @example
|
|
28
|
+
# dirstat = Git::DirstatInfo.new(
|
|
29
|
+
# entries: [
|
|
30
|
+
# Git::DirstatEntry.new(directory: 'lib/commands/', percentage: 45.2),
|
|
31
|
+
# Git::DirstatEntry.new(directory: 'spec/unit/', percentage: 30.1)
|
|
32
|
+
# ]
|
|
33
|
+
# )
|
|
34
|
+
# dirstat.entries.first.directory #=> "lib/commands/"
|
|
35
|
+
# dirstat['lib/commands/'] #=> 45.2
|
|
36
|
+
# dirstat.to_h #=> { "lib/commands/" => 45.2, "spec/unit/" => 30.1 }
|
|
37
|
+
#
|
|
38
|
+
# @!attribute [r] entries
|
|
39
|
+
# @return [Array<DirstatEntry>] directory statistics in order from git output
|
|
40
|
+
#
|
|
41
|
+
DirstatInfo = Data.define(:entries) do
|
|
42
|
+
# Look up percentage by directory path
|
|
43
|
+
#
|
|
44
|
+
# @param directory [String] the directory path
|
|
45
|
+
# @return [Float, nil] the percentage or nil if not found
|
|
46
|
+
#
|
|
47
|
+
def [](directory)
|
|
48
|
+
entries.find { |e| e.directory == directory }&.percentage
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Convert to a Hash mapping directory to percentage
|
|
52
|
+
#
|
|
53
|
+
# @return [Hash<String, Float>]
|
|
54
|
+
#
|
|
55
|
+
def to_h
|
|
56
|
+
entries.to_h { |e| [e.directory, e.percentage] }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Number of directories in the dirstat
|
|
60
|
+
#
|
|
61
|
+
# @return [Integer]
|
|
62
|
+
#
|
|
63
|
+
def size
|
|
64
|
+
entries.size
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check if dirstat is empty
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
#
|
|
71
|
+
def empty?
|
|
72
|
+
entries.empty?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Iterate over entries
|
|
76
|
+
#
|
|
77
|
+
# @yield [DirstatEntry] each entry
|
|
78
|
+
# @return [Enumerator] if no block given
|
|
79
|
+
#
|
|
80
|
+
def each(&block)
|
|
81
|
+
entries.each(&block)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
include Enumerable
|
|
85
|
+
end
|
|
86
|
+
end
|