git 4.3.2 → 5.0.0.beta.1
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 +67 -2705
- 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/SKILL.md +586 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +260 -0
- data/.github/skills/facade-test-conventions/SKILL.md +380 -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 +7 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -40
- data/CONTRIBUTING.md +694 -53
- data/README.md +17 -5
- data/Rakefile +61 -9
- data/commitlint.test +4 -0
- data/git.gemspec +14 -8
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/base.rb +486 -410
- data/lib/git/branch.rb +380 -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 +130 -24
- data/lib/git/command_line/base.rb +245 -0
- data/lib/git/command_line/capturing.rb +249 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +194 -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 +403 -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 +364 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +210 -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 +102 -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 +52 -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 +89 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +297 -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 +78 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +59 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +56 -0
- data/lib/git/execution_context/repository.rb +147 -0
- data/lib/git/execution_context.rb +482 -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/lib.rb +1606 -1028
- data/lib/git/log.rb +15 -2
- data/lib/git/object.rb +92 -22
- data/lib/git/parsers/branch.rb +224 -0
- data/lib/git/parsers/cat_file.rb +111 -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_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 +133 -9
- data/lib/git/repository/branching.rb +572 -0
- data/lib/git/repository/committing.rb +191 -0
- data/lib/git/repository/configuring.rb +156 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/inspecting.rb +153 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/merging.rb +295 -0
- data/lib/git/repository/object_operations.rb +1101 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +753 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +390 -0
- data/lib/git/repository/stashing.rb +107 -0
- data/lib/git/repository/status_operations.rb +180 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +264 -1
- data/lib/git/stash.rb +85 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +130 -13
- data/lib/git/status.rb +224 -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 +120 -5
- data/lib/git/worktrees.rb +107 -7
- data/lib/git.rb +114 -18
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1451 -54
- 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 +349 -20
- data/lib/git/index.rb +0 -6
- 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,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Immutable value object representing stats for a single file from git numstat output
|
|
5
|
+
#
|
|
6
|
+
# @api public
|
|
7
|
+
#
|
|
8
|
+
# @!attribute [r] path
|
|
9
|
+
# @return [String] the file path (destination path for renames)
|
|
10
|
+
#
|
|
11
|
+
# @!attribute [r] src_path
|
|
12
|
+
# @return [String, nil] the source path for renamed files, nil otherwise
|
|
13
|
+
#
|
|
14
|
+
# @!attribute [r] insertions
|
|
15
|
+
# @return [Integer] number of lines inserted
|
|
16
|
+
#
|
|
17
|
+
# @!attribute [r] deletions
|
|
18
|
+
# @return [Integer] number of lines deleted
|
|
19
|
+
#
|
|
20
|
+
DiffFileNumstatInfo = Data.define(:path, :src_path, :insertions, :deletions) do
|
|
21
|
+
# Check if this file was renamed
|
|
22
|
+
#
|
|
23
|
+
# @return [Boolean] true if the file was renamed
|
|
24
|
+
#
|
|
25
|
+
def renamed?
|
|
26
|
+
!src_path.nil?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
# @api public
|
|
13
|
+
#
|
|
14
|
+
# @example A modified file patch
|
|
15
|
+
# patch_info = Git::DiffFilePatchInfo.new(
|
|
16
|
+
# src: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/foo.rb'),
|
|
17
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'def5678', path: 'lib/foo.rb'),
|
|
18
|
+
# patch: "diff --git a/lib/foo.rb b/lib/foo.rb\n...",
|
|
19
|
+
# status: :modified,
|
|
20
|
+
# similarity: nil,
|
|
21
|
+
# binary: false,
|
|
22
|
+
# insertions: 10,
|
|
23
|
+
# deletions: 5
|
|
24
|
+
# )
|
|
25
|
+
#
|
|
26
|
+
# @example A new file patch (src is nil)
|
|
27
|
+
# patch_info = Git::DiffFilePatchInfo.new(
|
|
28
|
+
# src: nil,
|
|
29
|
+
# dst: Git::FileRef.new(mode: '100644', sha: 'abc1234', path: 'lib/new.rb'),
|
|
30
|
+
# patch: "diff --git a/lib/new.rb b/lib/new.rb\nnew file mode 100644\n...",
|
|
31
|
+
# status: :added,
|
|
32
|
+
# similarity: nil,
|
|
33
|
+
# binary: false,
|
|
34
|
+
# insertions: 20,
|
|
35
|
+
# deletions: 0
|
|
36
|
+
# )
|
|
37
|
+
#
|
|
38
|
+
# @!attribute [r] src
|
|
39
|
+
# @return [FileRef, nil] the source file reference, or nil for new/added files
|
|
40
|
+
#
|
|
41
|
+
# @!attribute [r] dst
|
|
42
|
+
# @return [FileRef, nil] the destination file reference, or nil for deleted files
|
|
43
|
+
#
|
|
44
|
+
# @!attribute [r] patch
|
|
45
|
+
# @return [String] the full unified diff patch text for this file
|
|
46
|
+
#
|
|
47
|
+
# @!attribute [r] status
|
|
48
|
+
# @return [Symbol] the change status (:added, :modified, :deleted, :renamed, :copied, :type_changed)
|
|
49
|
+
#
|
|
50
|
+
# @!attribute [r] similarity
|
|
51
|
+
# @return [Integer, nil] similarity percentage for renames/copies (0-100), nil otherwise
|
|
52
|
+
#
|
|
53
|
+
# @!attribute [r] binary
|
|
54
|
+
# @return [Boolean] whether this is a binary file
|
|
55
|
+
#
|
|
56
|
+
# @!attribute [r] insertions
|
|
57
|
+
# @return [Integer] number of lines inserted
|
|
58
|
+
#
|
|
59
|
+
# @!attribute [r] deletions
|
|
60
|
+
# @return [Integer] number of lines deleted
|
|
61
|
+
#
|
|
62
|
+
DiffFilePatchInfo = Data.define(
|
|
63
|
+
:src,
|
|
64
|
+
:dst,
|
|
65
|
+
:patch,
|
|
66
|
+
:status,
|
|
67
|
+
:similarity,
|
|
68
|
+
:binary,
|
|
69
|
+
:insertions,
|
|
70
|
+
:deletions
|
|
71
|
+
) do
|
|
72
|
+
# Get the primary file path
|
|
73
|
+
#
|
|
74
|
+
# Returns the destination path if it exists, otherwise the source path.
|
|
75
|
+
# This is the "current" or "canonical" path for the file.
|
|
76
|
+
#
|
|
77
|
+
# @return [String] the file path
|
|
78
|
+
#
|
|
79
|
+
def path
|
|
80
|
+
dst&.path || src&.path
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Get the source file path
|
|
84
|
+
#
|
|
85
|
+
# Returns the source path if it exists. Useful for renames/copies to see
|
|
86
|
+
# where the file came from.
|
|
87
|
+
#
|
|
88
|
+
# @return [String, nil] the source file path, or nil if no source (added files)
|
|
89
|
+
#
|
|
90
|
+
def src_path
|
|
91
|
+
src&.path
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Check if this is a binary file
|
|
95
|
+
#
|
|
96
|
+
# @return [Boolean] true if the file is binary
|
|
97
|
+
#
|
|
98
|
+
def binary?
|
|
99
|
+
binary
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Check if this file was renamed
|
|
103
|
+
#
|
|
104
|
+
# @return [Boolean]
|
|
105
|
+
#
|
|
106
|
+
def renamed?
|
|
107
|
+
status == :renamed
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Check if this file was copied
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
#
|
|
114
|
+
def copied?
|
|
115
|
+
status == :copied
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Check if this file was added
|
|
119
|
+
#
|
|
120
|
+
# @return [Boolean]
|
|
121
|
+
#
|
|
122
|
+
def added?
|
|
123
|
+
status == :added
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Check if this file was deleted
|
|
127
|
+
#
|
|
128
|
+
# @return [Boolean]
|
|
129
|
+
#
|
|
130
|
+
def deleted?
|
|
131
|
+
status == :deleted
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -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,104 @@
|
|
|
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
|
+
# When constructed with a pre-fetched hash, returns it directly.
|
|
65
|
+
# When `@base` responds to `#diff_name_status` (e.g. {Git::Repository} or
|
|
66
|
+
# {Git::Base}, which defines it as an alias for `#diff_path_status`),
|
|
67
|
+
# delegates directly to that method. Otherwise falls back to the legacy
|
|
68
|
+
# `@base.lib.diff_path_status` call for duck-typed base objects that only
|
|
69
|
+
# expose path-status via their lib.
|
|
70
|
+
#
|
|
71
|
+
# @return [Hash{String => String}] a mapping of file paths to status codes
|
|
72
|
+
#
|
|
40
73
|
def fetch_path_status
|
|
41
|
-
@fetch_path_status ||= @base.
|
|
42
|
-
|
|
43
|
-
|
|
74
|
+
@fetch_path_status ||= if @base.respond_to?(:diff_name_status)
|
|
75
|
+
@base.diff_name_status(@from, @to, path_limiter: @path_limiter).to_h
|
|
76
|
+
else
|
|
77
|
+
@base.lib.diff_path_status(@from, @to, { path_limiter: @path_limiter })
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Sets up legacy (base, from, to, path_limiter) instance state
|
|
82
|
+
#
|
|
83
|
+
# @param base [Git::Base, Git::Repository] the git base instance
|
|
84
|
+
#
|
|
85
|
+
# @param from [String] the first commit or object to compare
|
|
86
|
+
#
|
|
87
|
+
# @param to [String, nil] the second commit or object to compare
|
|
88
|
+
#
|
|
89
|
+
# @param path_limiter [String, Pathname, Array, nil] path(s) to limit the diff
|
|
90
|
+
#
|
|
91
|
+
# @return [void]
|
|
92
|
+
#
|
|
93
|
+
# @raise [ArgumentError] when `from` or `to` starts with `"-"`
|
|
94
|
+
#
|
|
95
|
+
def initialize_legacy(base, from, to, path_limiter)
|
|
96
|
+
[from, to].compact.each do |arg|
|
|
97
|
+
raise ArgumentError, "Invalid argument: '#{arg}'" if arg.start_with?('-')
|
|
98
|
+
end
|
|
99
|
+
@base = base
|
|
100
|
+
@from = from
|
|
101
|
+
@to = to
|
|
102
|
+
@path_limiter = path_limiter
|
|
44
103
|
end
|
|
45
104
|
end
|
|
46
105
|
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
|