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.
Files changed (280) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +67 -2705
  3. data/.github/pull_request_template.md +3 -1
  4. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  5. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  6. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  7. data/.github/skills/command-implementation/SKILL.md +229 -0
  8. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  9. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  10. data/.github/skills/dependency-management/SKILL.md +72 -0
  11. data/.github/skills/development-workflow/SKILL.md +506 -0
  12. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  13. data/.github/skills/extract-facade-from-base-lib/SKILL.md +586 -0
  14. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  15. data/.github/skills/facade-implementation/SKILL.md +260 -0
  16. data/.github/skills/facade-test-conventions/SKILL.md +380 -0
  17. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  18. data/.github/skills/make-skill-template/SKILL.md +176 -0
  19. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  20. data/.github/skills/project-context/SKILL.md +313 -0
  21. data/.github/skills/pull-request-review/SKILL.md +168 -0
  22. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  23. data/.github/skills/release-management/SKILL.md +125 -0
  24. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  25. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  26. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  27. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  28. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  29. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  30. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  31. data/.github/skills/test-debugging/SKILL.md +160 -0
  32. data/.github/skills/yard-documentation/SKILL.md +793 -0
  33. data/.github/workflows/continuous_integration.yml +3 -2
  34. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  35. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  36. data/.github/workflows/release.yml +3 -4
  37. data/.gitignore +8 -0
  38. data/.husky/pre-commit +13 -0
  39. data/.release-please-manifest.json +1 -1
  40. data/.rspec +3 -0
  41. data/.rubocop.yml +7 -3
  42. data/.rubocop_todo.yml +23 -5
  43. data/.yardopts +1 -0
  44. data/CHANGELOG.md +0 -40
  45. data/CONTRIBUTING.md +694 -53
  46. data/README.md +17 -5
  47. data/Rakefile +61 -9
  48. data/commitlint.test +4 -0
  49. data/git.gemspec +14 -8
  50. data/lib/git/args_builder.rb +0 -8
  51. data/lib/git/base.rb +486 -410
  52. data/lib/git/branch.rb +380 -43
  53. data/lib/git/branch_delete_failure.rb +31 -0
  54. data/lib/git/branch_delete_result.rb +63 -0
  55. data/lib/git/branch_info.rb +178 -0
  56. data/lib/git/branches.rb +130 -24
  57. data/lib/git/command_line/base.rb +245 -0
  58. data/lib/git/command_line/capturing.rb +249 -0
  59. data/lib/git/command_line/result.rb +96 -0
  60. data/lib/git/command_line/streaming.rb +194 -0
  61. data/lib/git/command_line.rb +43 -322
  62. data/lib/git/command_line_result.rb +4 -88
  63. data/lib/git/commands/add.rb +131 -0
  64. data/lib/git/commands/am/abort.rb +43 -0
  65. data/lib/git/commands/am/apply.rb +252 -0
  66. data/lib/git/commands/am/continue.rb +43 -0
  67. data/lib/git/commands/am/quit.rb +43 -0
  68. data/lib/git/commands/am/retry.rb +47 -0
  69. data/lib/git/commands/am/show_current_patch.rb +64 -0
  70. data/lib/git/commands/am/skip.rb +42 -0
  71. data/lib/git/commands/am.rb +33 -0
  72. data/lib/git/commands/apply.rb +237 -0
  73. data/lib/git/commands/archive/list_formats.rb +46 -0
  74. data/lib/git/commands/archive.rb +140 -0
  75. data/lib/git/commands/arguments.rb +3510 -0
  76. data/lib/git/commands/base.rb +403 -0
  77. data/lib/git/commands/branch/copy.rb +94 -0
  78. data/lib/git/commands/branch/create.rb +173 -0
  79. data/lib/git/commands/branch/delete.rb +80 -0
  80. data/lib/git/commands/branch/list.rb +162 -0
  81. data/lib/git/commands/branch/move.rb +94 -0
  82. data/lib/git/commands/branch/set_upstream.rb +86 -0
  83. data/lib/git/commands/branch/show_current.rb +49 -0
  84. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  85. data/lib/git/commands/branch.rb +34 -0
  86. data/lib/git/commands/cat_file/batch.rb +364 -0
  87. data/lib/git/commands/cat_file/filtered.rb +105 -0
  88. data/lib/git/commands/cat_file/raw.rb +210 -0
  89. data/lib/git/commands/cat_file.rb +49 -0
  90. data/lib/git/commands/checkout/branch.rb +151 -0
  91. data/lib/git/commands/checkout/files.rb +115 -0
  92. data/lib/git/commands/checkout.rb +38 -0
  93. data/lib/git/commands/checkout_index.rb +105 -0
  94. data/lib/git/commands/clean.rb +100 -0
  95. data/lib/git/commands/clone.rb +240 -0
  96. data/lib/git/commands/commit.rb +272 -0
  97. data/lib/git/commands/commit_tree.rb +100 -0
  98. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  99. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  100. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  101. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  102. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  103. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  104. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
  105. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  106. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  107. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  108. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  109. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  110. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  111. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  112. data/lib/git/commands/config_option_syntax.rb +56 -0
  113. data/lib/git/commands/describe.rb +155 -0
  114. data/lib/git/commands/diff.rb +656 -0
  115. data/lib/git/commands/diff_files.rb +518 -0
  116. data/lib/git/commands/diff_index.rb +496 -0
  117. data/lib/git/commands/fetch.rb +352 -0
  118. data/lib/git/commands/fsck.rb +136 -0
  119. data/lib/git/commands/gc.rb +132 -0
  120. data/lib/git/commands/grep.rb +338 -0
  121. data/lib/git/commands/init.rb +99 -0
  122. data/lib/git/commands/log.rb +632 -0
  123. data/lib/git/commands/ls_files.rb +191 -0
  124. data/lib/git/commands/ls_remote.rb +155 -0
  125. data/lib/git/commands/ls_tree.rb +131 -0
  126. data/lib/git/commands/maintenance/register.rb +75 -0
  127. data/lib/git/commands/maintenance/run.rb +104 -0
  128. data/lib/git/commands/maintenance/start.rb +66 -0
  129. data/lib/git/commands/maintenance/stop.rb +55 -0
  130. data/lib/git/commands/maintenance/unregister.rb +79 -0
  131. data/lib/git/commands/maintenance.rb +31 -0
  132. data/lib/git/commands/merge/abort.rb +44 -0
  133. data/lib/git/commands/merge/continue.rb +44 -0
  134. data/lib/git/commands/merge/quit.rb +46 -0
  135. data/lib/git/commands/merge/start.rb +245 -0
  136. data/lib/git/commands/merge.rb +28 -0
  137. data/lib/git/commands/merge_base.rb +86 -0
  138. data/lib/git/commands/mv.rb +77 -0
  139. data/lib/git/commands/name_rev.rb +114 -0
  140. data/lib/git/commands/pull.rb +377 -0
  141. data/lib/git/commands/push.rb +246 -0
  142. data/lib/git/commands/read_tree.rb +149 -0
  143. data/lib/git/commands/remote/add.rb +91 -0
  144. data/lib/git/commands/remote/get_url.rb +66 -0
  145. data/lib/git/commands/remote/list.rb +54 -0
  146. data/lib/git/commands/remote/prune.rb +61 -0
  147. data/lib/git/commands/remote/remove.rb +52 -0
  148. data/lib/git/commands/remote/rename.rb +69 -0
  149. data/lib/git/commands/remote/set_branches.rb +63 -0
  150. data/lib/git/commands/remote/set_head.rb +82 -0
  151. data/lib/git/commands/remote/set_url.rb +71 -0
  152. data/lib/git/commands/remote/set_url_add.rb +61 -0
  153. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  154. data/lib/git/commands/remote/show.rb +71 -0
  155. data/lib/git/commands/remote/update.rb +72 -0
  156. data/lib/git/commands/remote.rb +42 -0
  157. data/lib/git/commands/repack.rb +277 -0
  158. data/lib/git/commands/reset.rb +147 -0
  159. data/lib/git/commands/rev_parse.rb +297 -0
  160. data/lib/git/commands/revert/abort.rb +45 -0
  161. data/lib/git/commands/revert/continue.rb +57 -0
  162. data/lib/git/commands/revert/quit.rb +47 -0
  163. data/lib/git/commands/revert/skip.rb +44 -0
  164. data/lib/git/commands/revert/start.rb +153 -0
  165. data/lib/git/commands/revert.rb +29 -0
  166. data/lib/git/commands/rm.rb +114 -0
  167. data/lib/git/commands/show.rb +632 -0
  168. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  169. data/lib/git/commands/show_ref/exists.rb +78 -0
  170. data/lib/git/commands/show_ref/list.rb +145 -0
  171. data/lib/git/commands/show_ref/verify.rb +120 -0
  172. data/lib/git/commands/show_ref.rb +42 -0
  173. data/lib/git/commands/stash/apply.rb +75 -0
  174. data/lib/git/commands/stash/branch.rb +65 -0
  175. data/lib/git/commands/stash/clear.rb +41 -0
  176. data/lib/git/commands/stash/create.rb +58 -0
  177. data/lib/git/commands/stash/drop.rb +67 -0
  178. data/lib/git/commands/stash/list.rb +39 -0
  179. data/lib/git/commands/stash/pop.rb +78 -0
  180. data/lib/git/commands/stash/push.rb +103 -0
  181. data/lib/git/commands/stash/show.rb +149 -0
  182. data/lib/git/commands/stash/store.rb +63 -0
  183. data/lib/git/commands/stash.rb +38 -0
  184. data/lib/git/commands/status.rb +169 -0
  185. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  186. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  187. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  188. data/lib/git/commands/symbolic_ref.rb +38 -0
  189. data/lib/git/commands/tag/create.rb +139 -0
  190. data/lib/git/commands/tag/delete.rb +55 -0
  191. data/lib/git/commands/tag/list.rb +143 -0
  192. data/lib/git/commands/tag/verify.rb +71 -0
  193. data/lib/git/commands/tag.rb +26 -0
  194. data/lib/git/commands/update_ref/batch.rb +140 -0
  195. data/lib/git/commands/update_ref/delete.rb +92 -0
  196. data/lib/git/commands/update_ref/update.rb +106 -0
  197. data/lib/git/commands/update_ref.rb +42 -0
  198. data/lib/git/commands/version.rb +52 -0
  199. data/lib/git/commands/worktree/add.rb +140 -0
  200. data/lib/git/commands/worktree/list.rb +64 -0
  201. data/lib/git/commands/worktree/lock.rb +58 -0
  202. data/lib/git/commands/worktree/management_base.rb +51 -0
  203. data/lib/git/commands/worktree/move.rb +66 -0
  204. data/lib/git/commands/worktree/prune.rb +67 -0
  205. data/lib/git/commands/worktree/remove.rb +63 -0
  206. data/lib/git/commands/worktree/repair.rb +76 -0
  207. data/lib/git/commands/worktree/unlock.rb +47 -0
  208. data/lib/git/commands/worktree.rb +43 -0
  209. data/lib/git/commands/write_tree.rb +68 -0
  210. data/lib/git/commands.rb +89 -0
  211. data/lib/git/detached_head_info.rb +54 -0
  212. data/lib/git/diff.rb +297 -7
  213. data/lib/git/diff_file_numstat_info.rb +29 -0
  214. data/lib/git/diff_file_patch_info.rb +134 -0
  215. data/lib/git/diff_file_raw_info.rb +127 -0
  216. data/lib/git/diff_info.rb +169 -0
  217. data/lib/git/diff_path_status.rb +78 -19
  218. data/lib/git/diff_result.rb +32 -0
  219. data/lib/git/diff_stats.rb +59 -14
  220. data/lib/git/dirstat_info.rb +86 -0
  221. data/lib/git/errors.rb +65 -2
  222. data/lib/git/execution_context/global.rb +56 -0
  223. data/lib/git/execution_context/repository.rb +147 -0
  224. data/lib/git/execution_context.rb +482 -0
  225. data/lib/git/file_ref.rb +74 -0
  226. data/lib/git/fsck_object.rb +9 -9
  227. data/lib/git/fsck_result.rb +1 -1
  228. data/lib/git/lib.rb +1606 -1028
  229. data/lib/git/log.rb +15 -2
  230. data/lib/git/object.rb +92 -22
  231. data/lib/git/parsers/branch.rb +224 -0
  232. data/lib/git/parsers/cat_file.rb +111 -0
  233. data/lib/git/parsers/diff.rb +585 -0
  234. data/lib/git/parsers/fsck.rb +133 -0
  235. data/lib/git/parsers/grep.rb +42 -0
  236. data/lib/git/parsers/ls_tree.rb +58 -0
  237. data/lib/git/parsers/stash.rb +208 -0
  238. data/lib/git/parsers/tag.rb +257 -0
  239. data/lib/git/remote.rb +133 -9
  240. data/lib/git/repository/branching.rb +572 -0
  241. data/lib/git/repository/committing.rb +191 -0
  242. data/lib/git/repository/configuring.rb +156 -0
  243. data/lib/git/repository/diffing.rb +775 -0
  244. data/lib/git/repository/inspecting.rb +153 -0
  245. data/lib/git/repository/logging.rb +247 -0
  246. data/lib/git/repository/merging.rb +295 -0
  247. data/lib/git/repository/object_operations.rb +1101 -0
  248. data/lib/git/repository/path_resolver.rb +207 -0
  249. data/lib/git/repository/remote_operations.rb +753 -0
  250. data/lib/git/repository/shared_private.rb +51 -0
  251. data/lib/git/repository/staging.rb +390 -0
  252. data/lib/git/repository/stashing.rb +107 -0
  253. data/lib/git/repository/status_operations.rb +180 -0
  254. data/lib/git/repository/worktree_operations.rb +159 -0
  255. data/lib/git/repository.rb +264 -1
  256. data/lib/git/stash.rb +85 -4
  257. data/lib/git/stash_info.rb +104 -0
  258. data/lib/git/stashes.rb +130 -13
  259. data/lib/git/status.rb +224 -18
  260. data/lib/git/tag_delete_failure.rb +31 -0
  261. data/lib/git/tag_delete_result.rb +63 -0
  262. data/lib/git/tag_info.rb +105 -0
  263. data/lib/git/version.rb +109 -2
  264. data/lib/git/version_constraint.rb +81 -0
  265. data/lib/git/worktree.rb +120 -5
  266. data/lib/git/worktrees.rb +107 -7
  267. data/lib/git.rb +114 -18
  268. data/redesign/1_architecture_existing.md +54 -18
  269. data/redesign/2_architecture_redesign.md +365 -46
  270. data/redesign/3_architecture_implementation.md +1451 -54
  271. data/tasks/gem_tasks.rake +4 -0
  272. data/tasks/npm_tasks.rake +7 -0
  273. data/tasks/rspec.rake +48 -0
  274. data/tasks/test.rake +13 -1
  275. data/tasks/yard.rake +34 -7
  276. metadata +349 -20
  277. data/lib/git/index.rb +0 -6
  278. data/lib/git/path.rb +0 -38
  279. data/lib/git/working_directory.rb +0 -6
  280. /data/{release-please-config.json → .release-please-config.json} +0 -0
data/lib/git/stash.rb CHANGED
@@ -1,26 +1,107 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'git/base'
4
+
3
5
  module Git
4
- # A stash in a Git repository
6
+ # Represents a single stash entry in a Git repository
7
+ #
8
+ # @example Create a stash and inspect the result
9
+ # stash = Git::Stash.new(repo, 'WIP: feature work')
10
+ # stash.message #=> "WIP: feature work"
11
+ # stash.saved? #=> true
12
+ #
13
+ # @api public
14
+ #
5
15
  class Stash
6
- def initialize(base, message, save: false)
16
+ # Initialize a Stash object
17
+ #
18
+ # When `existing` is `false` (the default), immediately calls {#save} to push
19
+ # the current working-directory state onto the stash stack.
20
+ #
21
+ # @param base [Git::Repository, Git::Base] the git repository
22
+ #
23
+ # @param message [String] the stash message
24
+ #
25
+ # @param existing [Boolean] (false) when `true`, wraps an existing stash entry
26
+ # without pushing any changes
27
+ #
28
+ # @return [void]
29
+ #
30
+ # @example Create a new stash entry
31
+ # stash = Git::Stash.new(repo, 'WIP: feature work')
32
+ # stash.saved? #=> true
33
+ #
34
+ # @example Reference an existing stash without pushing
35
+ # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
36
+ # stash.saved? #=> nil
37
+ #
38
+ def initialize(base, message, existing: false)
7
39
  @base = base
8
40
  @message = message
9
- self.save unless save
41
+ save unless existing
10
42
  end
11
43
 
44
+ # Saves the current working-directory state to the stash stack
45
+ #
46
+ # @return [Boolean] `true` if changes were stashed, `false` if there were no
47
+ # local changes to save
48
+ #
49
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
50
+ #
51
+ # @example Save changes to the stash stack
52
+ # stash = Git::Stash.new(repo, 'WIP', existing: true)
53
+ # stash.save #=> true
54
+ #
12
55
  def save
13
- @saved = @base.lib.stash_save(@message)
56
+ @saved = stash_repository.stash_save(@message)
14
57
  end
15
58
 
59
+ # Returns whether the stash was saved successfully
60
+ #
61
+ # @return [Boolean, nil] `true` if changes were stashed, `false` if there were no
62
+ # local changes, `nil` if {#save} has not been called (e.g. `existing: true`)
63
+ #
64
+ # @example Check if changes were stashed
65
+ # stash = Git::Stash.new(repo, 'WIP: feature work')
66
+ # stash.saved? #=> true
67
+ #
16
68
  def saved?
17
69
  @saved
18
70
  end
19
71
 
72
+ # Returns the stash description
73
+ #
74
+ # @return [String] the stash message
75
+ #
76
+ # @example Read the stash message
77
+ # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
78
+ # stash.message #=> "WIP: feature work"
79
+ #
20
80
  attr_reader :message
21
81
 
82
+ # Returns the stash description as a string
83
+ #
84
+ # @return [String] the stash message
85
+ #
86
+ # @example Convert stash to string
87
+ # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
88
+ # stash.to_s #=> "WIP: feature work"
89
+ #
22
90
  def to_s
23
91
  message
24
92
  end
93
+
94
+ private
95
+
96
+ # Returns the facade interface for stash operations
97
+ #
98
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy).
99
+ # The `is_a?` guard will be removed when {Git::Base} is deleted in Phase 4.
100
+ #
101
+ # @return [Git::Repository]
102
+ #
103
+ def stash_repository
104
+ @base.is_a?(Git::Base) ? @base.facade_repository : @base
105
+ end
25
106
  end
26
107
  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,173 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'git/base'
4
+
3
5
  module Git
4
- # object that holds all the available stashes
6
+ # Collection of stash entries for a Git repository
7
+ #
8
+ # @example Iterate over stash entries
9
+ # git.stashes.each { |s| puts s.message }
10
+ #
11
+ # @example Check and apply a stash
12
+ # git.stashes.size #=> 2
13
+ # git.stashes.apply
14
+ #
15
+ # @api public
16
+ #
5
17
  class Stashes
6
18
  include Enumerable
7
19
 
20
+ # Initialize the stashes collection
21
+ #
22
+ # Loads all existing stash entries from the repository at construction time.
23
+ #
24
+ # @param base [Git::Repository, Git::Base] the git repository
25
+ #
26
+ # @return [void]
27
+ #
28
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
29
+ #
30
+ # @example Load stashes for a repository
31
+ # stashes = Git::Stashes.new(repo)
32
+ # stashes.size #=> 2
33
+ #
8
34
  def initialize(base)
9
35
  @stashes = []
10
-
11
36
  @base = base
12
37
 
13
- @base.lib.stashes_all.each do |indexed_message|
14
- _index, message = indexed_message
15
- @stashes.unshift(Git::Stash.new(@base, message, save: true))
38
+ stash_repository.stashes_all.each do |stash|
39
+ message = stash[1]
40
+ @stashes.unshift(Git::Stash.new(@base, message, existing: true))
16
41
  end
17
42
  end
18
43
 
44
+ # Returns all stash entries as an array of index and message pairs
45
+ #
46
+ # Entries are listed in oldest-first order matching {Git::Repository#stashes_all}.
47
+ #
48
+ # @example List all stash entries
49
+ # git.stashes.all #=> [[0, "testing-stash-all"], [1, "another-stash"]]
19
50
  #
20
- # Returns an multi-dimensional Array of elements that have been stash saved.
21
- # Array is based on position and name. See Example
51
+ # @return [Array<Array(Integer, String)>] array of `[index, message]` pairs where
52
+ # index 0 is the oldest stash
53
+ #
54
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
22
55
  #
23
- # @example Returns Array of items that have been stashed
24
- # .all - [0, "testing-stash-all"]]
25
- # @return [Array]
26
56
  def all
27
- @base.lib.stashes_all
57
+ stash_repository.stashes_all
28
58
  end
29
59
 
60
+ # Saves the current working-directory state to a new stash entry
61
+ #
62
+ # @param message [String] the stash message
63
+ #
64
+ # @return [void]
65
+ #
66
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
67
+ #
68
+ # @example Save current changes to the stash
69
+ # git.stashes.save('WIP: feature work')
70
+ # git.stashes.size #=> 1
71
+ #
30
72
  def save(message)
31
73
  s = Git::Stash.new(@base, message)
32
74
  @stashes.unshift(s) if s.saved?
33
75
  end
34
76
 
77
+ # Applies a stash entry to the working directory
78
+ #
79
+ # @param index [Integer, nil] the stash index to apply (default: latest)
80
+ #
81
+ # @return [String] the output from the git stash apply command
82
+ #
83
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
84
+ #
85
+ # @example Apply the most recent stash
86
+ # git.stashes.apply
87
+ #
88
+ # @example Apply a specific stash by index
89
+ # git.stashes.apply(1)
90
+ #
35
91
  def apply(index = nil)
36
- @base.lib.stash_apply(index)
92
+ stash_repository.stash_apply(index)
37
93
  end
38
94
 
95
+ # Removes all stash entries
96
+ #
97
+ # @return [void]
98
+ #
99
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
100
+ #
101
+ # @example Clear all stashes
102
+ # git.stashes.clear
103
+ # git.stashes.size #=> 0
104
+ #
39
105
  def clear
40
- @base.lib.stash_clear
106
+ stash_repository.stash_clear
41
107
  @stashes = []
108
+ nil
42
109
  end
43
110
 
111
+ # Returns the number of stash entries
112
+ #
113
+ # @return [Integer] the number of stashes
114
+ #
115
+ # @example Check how many stashes exist
116
+ # git.stashes.size #=> 2
117
+ #
44
118
  def size
45
119
  @stashes.size
46
120
  end
47
121
 
122
+ # Iterates over each stash entry in newest-first order
123
+ #
124
+ # @example Iterate over stashes
125
+ # git.stashes.each { |s| puts s.message }
126
+ #
127
+ # @overload each
128
+ #
129
+ # @return [Enumerator<Git::Stash>] an enumerator over stash entries
130
+ #
131
+ # @overload each(&block)
132
+ #
133
+ # @yield [stash] each stash entry
134
+ #
135
+ # @yieldparam stash [Git::Stash] the current stash entry
136
+ #
137
+ # @yieldreturn [void]
138
+ #
139
+ # @return [Array<Git::Stash>] the stash entries
140
+ #
48
141
  def each(&)
49
142
  @stashes.each(&)
50
143
  end
51
144
 
145
+ # Returns the stash entry at the given index
146
+ #
147
+ # Stashes are stored in newest-first order; index 0 is the most recent stash.
148
+ #
149
+ # @param index [Integer, #to_i] the stash index (0 = most recent)
150
+ #
151
+ # @return [Git::Stash, nil] the stash entry, or `nil` if the index is out of bounds
152
+ #
153
+ # @example Access the most recent stash
154
+ # git.stashes[0].message #=> "WIP: feature work"
155
+ #
52
156
  def [](index)
53
157
  @stashes[index.to_i]
54
158
  end
159
+
160
+ private
161
+
162
+ # Returns the facade interface for stash operations
163
+ #
164
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy).
165
+ # The `is_a?` guard will be removed when {Git::Base} is deleted in Phase 4.
166
+ #
167
+ # @return [Git::Repository]
168
+ #
169
+ def stash_repository
170
+ @base.is_a?(Git::Base) ? @base.facade_repository : @base
171
+ end
55
172
  end
56
173
  end