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
data/lib/git/repository.rb
CHANGED
|
@@ -1,6 +1,208 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'find'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
require 'git/configuring'
|
|
7
|
+
require 'git/deprecation'
|
|
8
|
+
require 'git/execution_context/repository'
|
|
9
|
+
require 'git/repository/branching'
|
|
10
|
+
require 'git/repository/context_helpers'
|
|
11
|
+
require 'git/repository/committing'
|
|
12
|
+
require 'git/repository/configuring'
|
|
13
|
+
require 'git/repository/diffing'
|
|
14
|
+
require 'git/repository/factories'
|
|
15
|
+
require 'git/repository/inspecting'
|
|
16
|
+
require 'git/repository/logging'
|
|
17
|
+
require 'git/repository/maintenance'
|
|
18
|
+
require 'git/repository/merging'
|
|
19
|
+
require 'git/repository/object_operations'
|
|
20
|
+
require 'git/repository/remote_operations'
|
|
21
|
+
require 'git/repository/staging'
|
|
22
|
+
require 'git/repository/stashing'
|
|
23
|
+
require 'git/repository/status_operations'
|
|
24
|
+
require 'git/repository/worktree_operations'
|
|
25
|
+
|
|
3
26
|
module Git
|
|
4
|
-
|
|
27
|
+
# The main public interface for interacting with a Git repository
|
|
28
|
+
#
|
|
29
|
+
# `Git::Repository` is the **orchestration layer** for all git operations. It acts
|
|
30
|
+
# as the glue between the user-facing API and the underlying components, but
|
|
31
|
+
# contains minimal domain logic itself. For each operation it:
|
|
32
|
+
#
|
|
33
|
+
# 1. **Pre-processes arguments** — transforms user-provided values into forms
|
|
34
|
+
# suitable for the command layer (e.g. path expansion, option normalization,
|
|
35
|
+
# Ruby-idiomatic defaults, deprecation handling, input validation).
|
|
36
|
+
# 2. **Calls commands** — invokes one or more `Git::Commands::*` classes via the
|
|
37
|
+
# injected `Git::ExecutionContext::Repository`.
|
|
38
|
+
# 3. **Builds rich return values** — passes raw command output through
|
|
39
|
+
# `Git::Parsers::*` classes and result-class factory methods to assemble the
|
|
40
|
+
# meaningful Ruby objects the caller expects.
|
|
41
|
+
#
|
|
42
|
+
# Some operations are genuinely one-line delegators when no pre/post-processing is
|
|
43
|
+
# needed (e.g. `add`, `reset`), but many are short orchestration sequences that
|
|
44
|
+
# coordinate argument preparation, one or more command calls, and result assembly.
|
|
45
|
+
#
|
|
46
|
+
# Facade methods are organized into focused modules under `lib/git/repository/`
|
|
47
|
+
# (e.g. {Git::Repository::Staging}) and included into this class.
|
|
48
|
+
#
|
|
49
|
+
# @api public
|
|
50
|
+
#
|
|
51
|
+
class Repository
|
|
52
|
+
extend Git::Repository::Factories
|
|
53
|
+
|
|
54
|
+
include Git::Configuring
|
|
55
|
+
include Git::Repository::Branching
|
|
56
|
+
include Git::Repository::ContextHelpers
|
|
57
|
+
include Git::Repository::Committing
|
|
58
|
+
include Git::Repository::Configuring
|
|
59
|
+
include Git::Repository::Diffing
|
|
60
|
+
include Git::Repository::Inspecting
|
|
61
|
+
include Git::Repository::Logging
|
|
62
|
+
include Git::Repository::Maintenance
|
|
63
|
+
include Git::Repository::Merging
|
|
64
|
+
include Git::Repository::ObjectOperations
|
|
65
|
+
include Git::Repository::RemoteOperations
|
|
66
|
+
include Git::Repository::Staging
|
|
67
|
+
include Git::Repository::Stashing
|
|
68
|
+
include Git::Repository::StatusOperations
|
|
69
|
+
include Git::Repository::WorktreeOperations
|
|
70
|
+
|
|
71
|
+
# @return [Git::ExecutionContext::Repository] the execution context used to run
|
|
72
|
+
# git commands for this repository
|
|
73
|
+
# @api private
|
|
74
|
+
attr_reader :execution_context
|
|
75
|
+
|
|
76
|
+
# @param execution_context [Git::ExecutionContext::Repository] the context used
|
|
77
|
+
# to run git commands for this repository; must not be nil
|
|
78
|
+
#
|
|
79
|
+
# @raise [ArgumentError] if `execution_context` is nil
|
|
80
|
+
#
|
|
81
|
+
def initialize(execution_context:)
|
|
82
|
+
raise ArgumentError, 'execution_context must not be nil' if execution_context.nil?
|
|
83
|
+
|
|
84
|
+
@execution_context = execution_context
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns the root of the working tree, or `nil` for a bare repository
|
|
88
|
+
#
|
|
89
|
+
# @example Get the working directory path
|
|
90
|
+
# repository.dir #=> #<Pathname:/path/to/repo>
|
|
91
|
+
#
|
|
92
|
+
# @return [Pathname, nil] the working directory path, or `nil` when bare
|
|
93
|
+
#
|
|
94
|
+
def dir
|
|
95
|
+
working_dir = execution_context.git_work_dir
|
|
96
|
+
working_dir && Pathname.new(working_dir)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns the repository (`.git`) directory
|
|
100
|
+
#
|
|
101
|
+
# @example Get the repository directory path
|
|
102
|
+
# repository.repo #=> #<Pathname:/path/to/repo/.git>
|
|
103
|
+
#
|
|
104
|
+
# @return [Pathname, nil] the repository directory path
|
|
105
|
+
#
|
|
106
|
+
def repo
|
|
107
|
+
repository = execution_context.git_dir
|
|
108
|
+
repository && Pathname.new(repository)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Returns the git index file
|
|
112
|
+
#
|
|
113
|
+
# @example Get the index file path
|
|
114
|
+
# repository.index #=> #<Pathname:/path/to/repo/.git/index>
|
|
115
|
+
#
|
|
116
|
+
# @return [Pathname, nil] the index file path
|
|
117
|
+
#
|
|
118
|
+
def index
|
|
119
|
+
index_file = execution_context.git_index_file
|
|
120
|
+
index_file && Pathname.new(index_file)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Returns `self` after emitting a deprecation warning.
|
|
124
|
+
#
|
|
125
|
+
# Legacy callers that used `git.lib.some_method` can migrate to calling the
|
|
126
|
+
# facade method directly on the repository object. This shim will be removed
|
|
127
|
+
# in v6.0.0.
|
|
128
|
+
#
|
|
129
|
+
# @return [self]
|
|
130
|
+
#
|
|
131
|
+
# @api private
|
|
132
|
+
#
|
|
133
|
+
def lib
|
|
134
|
+
Git::Deprecation.warn(
|
|
135
|
+
'Git::Repository#lib is deprecated and will be removed in v6.0.0. ' \
|
|
136
|
+
'Use the repository object directly.'
|
|
137
|
+
)
|
|
138
|
+
self
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @return [String, nil] the git directory path
|
|
142
|
+
#
|
|
143
|
+
# @api private
|
|
144
|
+
def git_dir = execution_context.git_dir
|
|
145
|
+
|
|
146
|
+
# @return [String, nil] the working directory path
|
|
147
|
+
#
|
|
148
|
+
# @api private
|
|
149
|
+
def git_work_dir = execution_context.git_work_dir
|
|
150
|
+
|
|
151
|
+
# @return [String, nil] the index file path
|
|
152
|
+
#
|
|
153
|
+
# @api private
|
|
154
|
+
def git_index_file = execution_context.git_index_file
|
|
155
|
+
|
|
156
|
+
# @return [Git::Version] the installed git version
|
|
157
|
+
#
|
|
158
|
+
# @api private
|
|
159
|
+
def git_version(timeout: nil) = execution_context.git_version(timeout: timeout)
|
|
160
|
+
|
|
161
|
+
# @return [String, nil] the SSH wrapper path
|
|
162
|
+
#
|
|
163
|
+
# @api private
|
|
164
|
+
def git_ssh = execution_context.git_ssh
|
|
165
|
+
|
|
166
|
+
# @return [String, :use_global_config] the path to the git binary
|
|
167
|
+
#
|
|
168
|
+
# @api private
|
|
169
|
+
def binary_path = execution_context.binary_path
|
|
170
|
+
|
|
171
|
+
# Returns the size of the repository directory in bytes
|
|
172
|
+
#
|
|
173
|
+
# Sums the sizes of every regular file under the repository (`.git`)
|
|
174
|
+
# directory in a single traversal. Symbolic links are not followed, so files
|
|
175
|
+
# that physically live outside the repository (reached through a symlinked
|
|
176
|
+
# directory) are never counted. Files that disappear mid-traversal are
|
|
177
|
+
# silently skipped.
|
|
178
|
+
#
|
|
179
|
+
# @example Get the repository size in bytes
|
|
180
|
+
# repository.repo_size #=> 12345
|
|
181
|
+
#
|
|
182
|
+
# @return [Integer] the total size in bytes of the repository directory
|
|
183
|
+
#
|
|
184
|
+
def repo_size
|
|
185
|
+
repository = repo
|
|
186
|
+
return 0 unless repository&.directory?
|
|
187
|
+
|
|
188
|
+
total = 0
|
|
189
|
+
Find.find(repository.to_s) do |path|
|
|
190
|
+
stat = File.lstat(path)
|
|
191
|
+
total += stat.size if stat.file?
|
|
192
|
+
rescue Errno::ENOENT
|
|
193
|
+
next
|
|
194
|
+
end
|
|
195
|
+
total
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
private
|
|
199
|
+
|
|
200
|
+
# All git config scopes are valid in a repository context
|
|
201
|
+
#
|
|
202
|
+
# @return [void]
|
|
203
|
+
#
|
|
204
|
+
def assert_valid_scope!(**)
|
|
205
|
+
nil
|
|
206
|
+
end
|
|
5
207
|
end
|
|
6
208
|
end
|
data/lib/git/stash.rb
CHANGED
|
@@ -1,26 +1,100 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Git
|
|
4
|
-
#
|
|
4
|
+
# Represents a single stash entry in a Git repository
|
|
5
|
+
#
|
|
6
|
+
# @example Create a stash and inspect the result
|
|
7
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work')
|
|
8
|
+
# stash.message #=> "WIP: feature work"
|
|
9
|
+
# stash.saved? #=> true
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
#
|
|
5
13
|
class Stash
|
|
6
|
-
|
|
14
|
+
# Initialize a Stash object
|
|
15
|
+
#
|
|
16
|
+
# When `existing` is `false` (the default), immediately calls {#save} to push
|
|
17
|
+
# the current working-directory state onto the stash stack.
|
|
18
|
+
#
|
|
19
|
+
# @param base [Git::Repository] the git repository
|
|
20
|
+
#
|
|
21
|
+
# @param message [String] the stash message
|
|
22
|
+
#
|
|
23
|
+
# @param existing [Boolean] (false) when `true`, wraps an existing stash entry
|
|
24
|
+
# without pushing any changes
|
|
25
|
+
#
|
|
26
|
+
# @return [void]
|
|
27
|
+
#
|
|
28
|
+
# @example Create a new stash entry
|
|
29
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work')
|
|
30
|
+
# stash.saved? #=> true
|
|
31
|
+
#
|
|
32
|
+
# @example Reference an existing stash without pushing
|
|
33
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
|
|
34
|
+
# stash.saved? #=> nil
|
|
35
|
+
#
|
|
36
|
+
def initialize(base, message, existing: false)
|
|
7
37
|
@base = base
|
|
8
38
|
@message = message
|
|
9
|
-
|
|
39
|
+
save unless existing
|
|
10
40
|
end
|
|
11
41
|
|
|
42
|
+
# Saves the current working-directory state to the stash stack
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean] `true` if changes were stashed, `false` if there were no
|
|
45
|
+
# local changes to save
|
|
46
|
+
#
|
|
47
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
48
|
+
#
|
|
49
|
+
# @example Save changes to the stash stack
|
|
50
|
+
# stash = Git::Stash.new(repo, 'WIP', existing: true)
|
|
51
|
+
# stash.save #=> true
|
|
52
|
+
#
|
|
12
53
|
def save
|
|
13
|
-
@saved =
|
|
54
|
+
@saved = stash_repository.stash_save(@message)
|
|
14
55
|
end
|
|
15
56
|
|
|
57
|
+
# Returns whether the stash was saved successfully
|
|
58
|
+
#
|
|
59
|
+
# @return [Boolean, nil] `true` if changes were stashed, `false` if there were no
|
|
60
|
+
# local changes, `nil` if {#save} has not been called (e.g. `existing: true`)
|
|
61
|
+
#
|
|
62
|
+
# @example Check if changes were stashed
|
|
63
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work')
|
|
64
|
+
# stash.saved? #=> true
|
|
65
|
+
#
|
|
16
66
|
def saved?
|
|
17
67
|
@saved
|
|
18
68
|
end
|
|
19
69
|
|
|
70
|
+
# Returns the stash description
|
|
71
|
+
#
|
|
72
|
+
# @return [String] the stash message
|
|
73
|
+
#
|
|
74
|
+
# @example Read the stash message
|
|
75
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
|
|
76
|
+
# stash.message #=> "WIP: feature work"
|
|
77
|
+
#
|
|
20
78
|
attr_reader :message
|
|
21
79
|
|
|
80
|
+
# Returns the stash description as a string
|
|
81
|
+
#
|
|
82
|
+
# @return [String] the stash message
|
|
83
|
+
#
|
|
84
|
+
# @example Convert stash to string
|
|
85
|
+
# stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
|
|
86
|
+
# stash.to_s #=> "WIP: feature work"
|
|
87
|
+
#
|
|
22
88
|
def to_s
|
|
23
89
|
message
|
|
24
90
|
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
# @return [Git::Repository]
|
|
95
|
+
#
|
|
96
|
+
def stash_repository
|
|
97
|
+
@base
|
|
98
|
+
end
|
|
25
99
|
end
|
|
26
100
|
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Git
|
|
4
|
+
# Immutable value object representing stash entry information
|
|
5
|
+
#
|
|
6
|
+
# StashInfo encapsulates the parsed data from `git stash list` output.
|
|
7
|
+
# Each entry contains comprehensive information about the stash including
|
|
8
|
+
# its index, reference name, commit SHA, branch, message, author/committer
|
|
9
|
+
# details, and timestamps.
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
#
|
|
13
|
+
# @example Create a StashInfo from parsed stash list output
|
|
14
|
+
# info = Git::StashInfo.new(
|
|
15
|
+
# index: 0,
|
|
16
|
+
# name: 'stash@{0}',
|
|
17
|
+
# oid: 'abc123def456789...',
|
|
18
|
+
# short_oid: 'abc123d',
|
|
19
|
+
# branch: 'main',
|
|
20
|
+
# message: 'WIP on main: abc123 Initial commit',
|
|
21
|
+
# author_name: 'Jane Doe',
|
|
22
|
+
# author_email: 'jane@example.com',
|
|
23
|
+
# author_date: '2026-01-24T10:30:00-08:00',
|
|
24
|
+
# committer_name: 'Jane Doe',
|
|
25
|
+
# committer_email: 'jane@example.com',
|
|
26
|
+
# committer_date: '2026-01-24T10:30:00-08:00'
|
|
27
|
+
# )
|
|
28
|
+
#
|
|
29
|
+
# info.index # => 0
|
|
30
|
+
# info.name # => 'stash@{0}'
|
|
31
|
+
# info.oid # => 'abc123def456789...'
|
|
32
|
+
# info.short_oid # => 'abc123d'
|
|
33
|
+
# info.branch # => 'main'
|
|
34
|
+
# info.message # => 'WIP on main: abc123 Initial commit'
|
|
35
|
+
# info.author_name # => 'Jane Doe'
|
|
36
|
+
# info.author_email # => 'jane@example.com'
|
|
37
|
+
# info.author_date # => '2026-01-24T10:30:00-08:00'
|
|
38
|
+
# info.committer_name # => 'Jane Doe'
|
|
39
|
+
# info.committer_email # => 'jane@example.com'
|
|
40
|
+
# info.committer_date # => '2026-01-24T10:30:00-08:00'
|
|
41
|
+
#
|
|
42
|
+
# @!attribute [r] index
|
|
43
|
+
# @return [Integer] the stash index (0, 1, 2, ...)
|
|
44
|
+
#
|
|
45
|
+
# @!attribute [r] name
|
|
46
|
+
# @return [String] the stash reference name (e.g., 'stash@\\{0\\}')
|
|
47
|
+
#
|
|
48
|
+
# @!attribute [r] oid
|
|
49
|
+
# @return [String] the full 40-character object identifier of the stash
|
|
50
|
+
#
|
|
51
|
+
# @!attribute [r] short_oid
|
|
52
|
+
# @return [String] the abbreviated object identifier (typically 7 characters)
|
|
53
|
+
#
|
|
54
|
+
# @!attribute [r] branch
|
|
55
|
+
# @return [String, nil] the branch name where the stash was created,
|
|
56
|
+
# or nil for custom stash messages
|
|
57
|
+
#
|
|
58
|
+
# @!attribute [r] message
|
|
59
|
+
# @return [String] the stash message (e.g., 'WIP on main: abc123 commit msg')
|
|
60
|
+
#
|
|
61
|
+
# @!attribute [r] author_name
|
|
62
|
+
# @return [String] the name of the stash author
|
|
63
|
+
#
|
|
64
|
+
# @!attribute [r] author_email
|
|
65
|
+
# @return [String] the email of the stash author
|
|
66
|
+
#
|
|
67
|
+
# @!attribute [r] author_date
|
|
68
|
+
# @return [String] the author date in ISO 8601 format
|
|
69
|
+
#
|
|
70
|
+
# @!attribute [r] committer_name
|
|
71
|
+
# @return [String] the name of the stash committer
|
|
72
|
+
#
|
|
73
|
+
# @!attribute [r] committer_email
|
|
74
|
+
# @return [String] the email of the stash committer
|
|
75
|
+
#
|
|
76
|
+
# @!attribute [r] committer_date
|
|
77
|
+
# @return [String] the committer date in ISO 8601 format
|
|
78
|
+
#
|
|
79
|
+
StashInfo = Data.define(
|
|
80
|
+
:index,
|
|
81
|
+
:name,
|
|
82
|
+
:oid,
|
|
83
|
+
:short_oid,
|
|
84
|
+
:branch,
|
|
85
|
+
:message,
|
|
86
|
+
:author_name,
|
|
87
|
+
:author_email,
|
|
88
|
+
:author_date,
|
|
89
|
+
:committer_name,
|
|
90
|
+
:committer_email,
|
|
91
|
+
:committer_date
|
|
92
|
+
) do
|
|
93
|
+
# Returns the stash reference name
|
|
94
|
+
#
|
|
95
|
+
# @return [String] the stash name (e.g., 'stash@\\{0}')
|
|
96
|
+
#
|
|
97
|
+
# @example
|
|
98
|
+
# info.to_s # => 'stash@{0}'
|
|
99
|
+
#
|
|
100
|
+
def to_s
|
|
101
|
+
name
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/git/stashes.rb
CHANGED
|
@@ -1,56 +1,168 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Git
|
|
4
|
-
#
|
|
4
|
+
# Collection of stash entries for a Git repository
|
|
5
|
+
#
|
|
6
|
+
# @example Iterate over stash entries
|
|
7
|
+
# git.stashes.each { |s| puts s.message }
|
|
8
|
+
#
|
|
9
|
+
# @example Check and apply a stash
|
|
10
|
+
# git.stashes.size #=> 2
|
|
11
|
+
# git.stashes.apply
|
|
12
|
+
#
|
|
13
|
+
# @api public
|
|
14
|
+
#
|
|
5
15
|
class Stashes
|
|
6
16
|
include Enumerable
|
|
7
17
|
|
|
18
|
+
# Initialize the stashes collection
|
|
19
|
+
#
|
|
20
|
+
# Loads all existing stash entries from the repository at construction time.
|
|
21
|
+
#
|
|
22
|
+
# @param base [Git::Repository] the git repository
|
|
23
|
+
#
|
|
24
|
+
# @return [void]
|
|
25
|
+
#
|
|
26
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
27
|
+
#
|
|
28
|
+
# @example Load stashes for a repository
|
|
29
|
+
# stashes = Git::Stashes.new(repo)
|
|
30
|
+
# stashes.size #=> 2
|
|
31
|
+
#
|
|
8
32
|
def initialize(base)
|
|
9
33
|
@stashes = []
|
|
10
|
-
|
|
11
34
|
@base = base
|
|
12
35
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@stashes.unshift(Git::Stash.new(@base, message,
|
|
36
|
+
stash_repository.stashes_all.each do |stash|
|
|
37
|
+
message = stash[1]
|
|
38
|
+
@stashes.unshift(Git::Stash.new(@base, message, existing: true))
|
|
16
39
|
end
|
|
17
40
|
end
|
|
18
41
|
|
|
42
|
+
# Returns all stash entries as an array of index and message pairs
|
|
43
|
+
#
|
|
44
|
+
# Entries are listed in oldest-first order matching {Git::Repository#stashes_all}.
|
|
45
|
+
#
|
|
46
|
+
# @example List all stash entries
|
|
47
|
+
# git.stashes.all #=> [[0, "testing-stash-all"], [1, "another-stash"]]
|
|
19
48
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
49
|
+
# @return [Array<Array(Integer, String)>] array of `[index, message]` pairs where
|
|
50
|
+
# index 0 is the oldest stash
|
|
51
|
+
#
|
|
52
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
22
53
|
#
|
|
23
|
-
# @example Returns Array of items that have been stashed
|
|
24
|
-
# .all - [0, "testing-stash-all"]]
|
|
25
|
-
# @return [Array]
|
|
26
54
|
def all
|
|
27
|
-
|
|
55
|
+
stash_repository.stashes_all
|
|
28
56
|
end
|
|
29
57
|
|
|
58
|
+
# Saves the current working-directory state to a new stash entry
|
|
59
|
+
#
|
|
60
|
+
# @param message [String] the stash message
|
|
61
|
+
#
|
|
62
|
+
# @return [void]
|
|
63
|
+
#
|
|
64
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
65
|
+
#
|
|
66
|
+
# @example Save current changes to the stash
|
|
67
|
+
# git.stashes.save('WIP: feature work')
|
|
68
|
+
# git.stashes.size #=> 1
|
|
69
|
+
#
|
|
30
70
|
def save(message)
|
|
31
71
|
s = Git::Stash.new(@base, message)
|
|
32
72
|
@stashes.unshift(s) if s.saved?
|
|
33
73
|
end
|
|
34
74
|
|
|
75
|
+
# Applies a stash entry to the working directory
|
|
76
|
+
#
|
|
77
|
+
# @param index [Integer, nil] the stash index to apply (default: latest)
|
|
78
|
+
#
|
|
79
|
+
# @return [String] the output from the git stash apply command
|
|
80
|
+
#
|
|
81
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
82
|
+
#
|
|
83
|
+
# @example Apply the most recent stash
|
|
84
|
+
# git.stashes.apply
|
|
85
|
+
#
|
|
86
|
+
# @example Apply a specific stash by index
|
|
87
|
+
# git.stashes.apply(1)
|
|
88
|
+
#
|
|
35
89
|
def apply(index = nil)
|
|
36
|
-
|
|
90
|
+
stash_repository.stash_apply(index)
|
|
37
91
|
end
|
|
38
92
|
|
|
93
|
+
# Removes all stash entries
|
|
94
|
+
#
|
|
95
|
+
# @return [void]
|
|
96
|
+
#
|
|
97
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
98
|
+
#
|
|
99
|
+
# @example Clear all stashes
|
|
100
|
+
# git.stashes.clear
|
|
101
|
+
# git.stashes.size #=> 0
|
|
102
|
+
#
|
|
39
103
|
def clear
|
|
40
|
-
|
|
104
|
+
stash_repository.stash_clear
|
|
41
105
|
@stashes = []
|
|
106
|
+
nil
|
|
42
107
|
end
|
|
43
108
|
|
|
109
|
+
# Returns the number of stash entries
|
|
110
|
+
#
|
|
111
|
+
# @return [Integer] the number of stashes
|
|
112
|
+
#
|
|
113
|
+
# @example Check how many stashes exist
|
|
114
|
+
# git.stashes.size #=> 2
|
|
115
|
+
#
|
|
44
116
|
def size
|
|
45
117
|
@stashes.size
|
|
46
118
|
end
|
|
47
119
|
|
|
120
|
+
# Iterates over each stash entry in newest-first order
|
|
121
|
+
#
|
|
122
|
+
# @example Iterate over stashes
|
|
123
|
+
# git.stashes.each { |s| puts s.message }
|
|
124
|
+
#
|
|
125
|
+
# @overload each
|
|
126
|
+
#
|
|
127
|
+
# @return [Enumerator<Git::Stash>] an enumerator over stash entries
|
|
128
|
+
#
|
|
129
|
+
# @overload each(&block)
|
|
130
|
+
#
|
|
131
|
+
# @yield [stash] each stash entry
|
|
132
|
+
#
|
|
133
|
+
# @yieldparam stash [Git::Stash] the current stash entry
|
|
134
|
+
#
|
|
135
|
+
# @yieldreturn [void]
|
|
136
|
+
#
|
|
137
|
+
# @return [Array<Git::Stash>] the stash entries
|
|
138
|
+
#
|
|
48
139
|
def each(&)
|
|
49
140
|
@stashes.each(&)
|
|
50
141
|
end
|
|
51
142
|
|
|
143
|
+
# Returns the stash entry at the given index
|
|
144
|
+
#
|
|
145
|
+
# Stashes are stored in newest-first order; index 0 is the most recent stash.
|
|
146
|
+
#
|
|
147
|
+
# @param index [Integer, #to_i] the stash index (0 = most recent)
|
|
148
|
+
#
|
|
149
|
+
# @return [Git::Stash, nil] the stash entry, or `nil` if the index is out of bounds
|
|
150
|
+
#
|
|
151
|
+
# @example Access the most recent stash
|
|
152
|
+
# git.stashes[0].message #=> "WIP: feature work"
|
|
153
|
+
#
|
|
52
154
|
def [](index)
|
|
53
155
|
@stashes[index.to_i]
|
|
54
156
|
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
# Returns the facade interface for stash operations
|
|
161
|
+
#
|
|
162
|
+
# @return [Git::Repository]
|
|
163
|
+
#
|
|
164
|
+
def stash_repository
|
|
165
|
+
@base
|
|
166
|
+
end
|
|
55
167
|
end
|
|
56
168
|
end
|