git 4.4.5 → 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 (282) 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 -67
  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 -1
  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 -98
  45. data/CONTRIBUTING.md +694 -53
  46. data/LICENSE +1 -1
  47. data/README.md +17 -17
  48. data/Rakefile +61 -9
  49. data/commitlint.test +4 -0
  50. data/git.gemspec +15 -9
  51. data/lib/git/args_builder.rb +0 -8
  52. data/lib/git/base.rb +488 -424
  53. data/lib/git/branch.rb +117 -59
  54. data/lib/git/branch_delete_failure.rb +31 -0
  55. data/lib/git/branch_delete_result.rb +63 -0
  56. data/lib/git/branch_info.rb +178 -0
  57. data/lib/git/branches.rb +130 -24
  58. data/lib/git/command_line/base.rb +245 -0
  59. data/lib/git/command_line/capturing.rb +249 -0
  60. data/lib/git/command_line/result.rb +96 -0
  61. data/lib/git/command_line/streaming.rb +194 -0
  62. data/lib/git/command_line.rb +43 -322
  63. data/lib/git/command_line_result.rb +4 -88
  64. data/lib/git/commands/add.rb +131 -0
  65. data/lib/git/commands/am/abort.rb +43 -0
  66. data/lib/git/commands/am/apply.rb +252 -0
  67. data/lib/git/commands/am/continue.rb +43 -0
  68. data/lib/git/commands/am/quit.rb +43 -0
  69. data/lib/git/commands/am/retry.rb +47 -0
  70. data/lib/git/commands/am/show_current_patch.rb +64 -0
  71. data/lib/git/commands/am/skip.rb +42 -0
  72. data/lib/git/commands/am.rb +33 -0
  73. data/lib/git/commands/apply.rb +237 -0
  74. data/lib/git/commands/archive/list_formats.rb +46 -0
  75. data/lib/git/commands/archive.rb +140 -0
  76. data/lib/git/commands/arguments.rb +3510 -0
  77. data/lib/git/commands/base.rb +403 -0
  78. data/lib/git/commands/branch/copy.rb +94 -0
  79. data/lib/git/commands/branch/create.rb +173 -0
  80. data/lib/git/commands/branch/delete.rb +80 -0
  81. data/lib/git/commands/branch/list.rb +162 -0
  82. data/lib/git/commands/branch/move.rb +94 -0
  83. data/lib/git/commands/branch/set_upstream.rb +86 -0
  84. data/lib/git/commands/branch/show_current.rb +49 -0
  85. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  86. data/lib/git/commands/branch.rb +34 -0
  87. data/lib/git/commands/cat_file/batch.rb +364 -0
  88. data/lib/git/commands/cat_file/filtered.rb +105 -0
  89. data/lib/git/commands/cat_file/raw.rb +210 -0
  90. data/lib/git/commands/cat_file.rb +49 -0
  91. data/lib/git/commands/checkout/branch.rb +151 -0
  92. data/lib/git/commands/checkout/files.rb +115 -0
  93. data/lib/git/commands/checkout.rb +38 -0
  94. data/lib/git/commands/checkout_index.rb +105 -0
  95. data/lib/git/commands/clean.rb +100 -0
  96. data/lib/git/commands/clone.rb +240 -0
  97. data/lib/git/commands/commit.rb +272 -0
  98. data/lib/git/commands/commit_tree.rb +100 -0
  99. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  100. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  101. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  102. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  103. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  104. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  105. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
  106. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  107. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  108. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  109. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  110. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  111. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  112. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  113. data/lib/git/commands/config_option_syntax.rb +56 -0
  114. data/lib/git/commands/describe.rb +155 -0
  115. data/lib/git/commands/diff.rb +656 -0
  116. data/lib/git/commands/diff_files.rb +518 -0
  117. data/lib/git/commands/diff_index.rb +496 -0
  118. data/lib/git/commands/fetch.rb +352 -0
  119. data/lib/git/commands/fsck.rb +136 -0
  120. data/lib/git/commands/gc.rb +132 -0
  121. data/lib/git/commands/grep.rb +338 -0
  122. data/lib/git/commands/init.rb +99 -0
  123. data/lib/git/commands/log.rb +632 -0
  124. data/lib/git/commands/ls_files.rb +191 -0
  125. data/lib/git/commands/ls_remote.rb +155 -0
  126. data/lib/git/commands/ls_tree.rb +131 -0
  127. data/lib/git/commands/maintenance/register.rb +75 -0
  128. data/lib/git/commands/maintenance/run.rb +104 -0
  129. data/lib/git/commands/maintenance/start.rb +66 -0
  130. data/lib/git/commands/maintenance/stop.rb +55 -0
  131. data/lib/git/commands/maintenance/unregister.rb +79 -0
  132. data/lib/git/commands/maintenance.rb +31 -0
  133. data/lib/git/commands/merge/abort.rb +44 -0
  134. data/lib/git/commands/merge/continue.rb +44 -0
  135. data/lib/git/commands/merge/quit.rb +46 -0
  136. data/lib/git/commands/merge/start.rb +245 -0
  137. data/lib/git/commands/merge.rb +28 -0
  138. data/lib/git/commands/merge_base.rb +86 -0
  139. data/lib/git/commands/mv.rb +77 -0
  140. data/lib/git/commands/name_rev.rb +114 -0
  141. data/lib/git/commands/pull.rb +377 -0
  142. data/lib/git/commands/push.rb +246 -0
  143. data/lib/git/commands/read_tree.rb +149 -0
  144. data/lib/git/commands/remote/add.rb +91 -0
  145. data/lib/git/commands/remote/get_url.rb +66 -0
  146. data/lib/git/commands/remote/list.rb +54 -0
  147. data/lib/git/commands/remote/prune.rb +61 -0
  148. data/lib/git/commands/remote/remove.rb +52 -0
  149. data/lib/git/commands/remote/rename.rb +69 -0
  150. data/lib/git/commands/remote/set_branches.rb +63 -0
  151. data/lib/git/commands/remote/set_head.rb +82 -0
  152. data/lib/git/commands/remote/set_url.rb +71 -0
  153. data/lib/git/commands/remote/set_url_add.rb +61 -0
  154. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  155. data/lib/git/commands/remote/show.rb +71 -0
  156. data/lib/git/commands/remote/update.rb +72 -0
  157. data/lib/git/commands/remote.rb +42 -0
  158. data/lib/git/commands/repack.rb +277 -0
  159. data/lib/git/commands/reset.rb +147 -0
  160. data/lib/git/commands/rev_parse.rb +297 -0
  161. data/lib/git/commands/revert/abort.rb +45 -0
  162. data/lib/git/commands/revert/continue.rb +57 -0
  163. data/lib/git/commands/revert/quit.rb +47 -0
  164. data/lib/git/commands/revert/skip.rb +44 -0
  165. data/lib/git/commands/revert/start.rb +153 -0
  166. data/lib/git/commands/revert.rb +29 -0
  167. data/lib/git/commands/rm.rb +114 -0
  168. data/lib/git/commands/show.rb +632 -0
  169. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  170. data/lib/git/commands/show_ref/exists.rb +78 -0
  171. data/lib/git/commands/show_ref/list.rb +145 -0
  172. data/lib/git/commands/show_ref/verify.rb +120 -0
  173. data/lib/git/commands/show_ref.rb +42 -0
  174. data/lib/git/commands/stash/apply.rb +75 -0
  175. data/lib/git/commands/stash/branch.rb +65 -0
  176. data/lib/git/commands/stash/clear.rb +41 -0
  177. data/lib/git/commands/stash/create.rb +58 -0
  178. data/lib/git/commands/stash/drop.rb +67 -0
  179. data/lib/git/commands/stash/list.rb +39 -0
  180. data/lib/git/commands/stash/pop.rb +78 -0
  181. data/lib/git/commands/stash/push.rb +103 -0
  182. data/lib/git/commands/stash/show.rb +149 -0
  183. data/lib/git/commands/stash/store.rb +63 -0
  184. data/lib/git/commands/stash.rb +38 -0
  185. data/lib/git/commands/status.rb +169 -0
  186. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  187. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  188. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  189. data/lib/git/commands/symbolic_ref.rb +38 -0
  190. data/lib/git/commands/tag/create.rb +139 -0
  191. data/lib/git/commands/tag/delete.rb +55 -0
  192. data/lib/git/commands/tag/list.rb +143 -0
  193. data/lib/git/commands/tag/verify.rb +71 -0
  194. data/lib/git/commands/tag.rb +26 -0
  195. data/lib/git/commands/update_ref/batch.rb +140 -0
  196. data/lib/git/commands/update_ref/delete.rb +92 -0
  197. data/lib/git/commands/update_ref/update.rb +106 -0
  198. data/lib/git/commands/update_ref.rb +42 -0
  199. data/lib/git/commands/version.rb +52 -0
  200. data/lib/git/commands/worktree/add.rb +140 -0
  201. data/lib/git/commands/worktree/list.rb +64 -0
  202. data/lib/git/commands/worktree/lock.rb +58 -0
  203. data/lib/git/commands/worktree/management_base.rb +51 -0
  204. data/lib/git/commands/worktree/move.rb +66 -0
  205. data/lib/git/commands/worktree/prune.rb +67 -0
  206. data/lib/git/commands/worktree/remove.rb +63 -0
  207. data/lib/git/commands/worktree/repair.rb +76 -0
  208. data/lib/git/commands/worktree/unlock.rb +47 -0
  209. data/lib/git/commands/worktree.rb +43 -0
  210. data/lib/git/commands/write_tree.rb +68 -0
  211. data/lib/git/commands.rb +89 -0
  212. data/lib/git/detached_head_info.rb +54 -0
  213. data/lib/git/diff.rb +297 -7
  214. data/lib/git/diff_file_numstat_info.rb +29 -0
  215. data/lib/git/diff_file_patch_info.rb +134 -0
  216. data/lib/git/diff_file_raw_info.rb +127 -0
  217. data/lib/git/diff_info.rb +169 -0
  218. data/lib/git/diff_path_status.rb +78 -19
  219. data/lib/git/diff_result.rb +32 -0
  220. data/lib/git/diff_stats.rb +59 -14
  221. data/lib/git/dirstat_info.rb +86 -0
  222. data/lib/git/errors.rb +65 -2
  223. data/lib/git/execution_context/global.rb +56 -0
  224. data/lib/git/execution_context/repository.rb +147 -0
  225. data/lib/git/execution_context.rb +482 -0
  226. data/lib/git/file_ref.rb +74 -0
  227. data/lib/git/fsck_object.rb +9 -9
  228. data/lib/git/fsck_result.rb +1 -1
  229. data/lib/git/lib.rb +1606 -1084
  230. data/lib/git/log.rb +15 -2
  231. data/lib/git/object.rb +92 -22
  232. data/lib/git/parsers/branch.rb +224 -0
  233. data/lib/git/parsers/cat_file.rb +111 -0
  234. data/lib/git/parsers/diff.rb +585 -0
  235. data/lib/git/parsers/fsck.rb +133 -0
  236. data/lib/git/parsers/grep.rb +42 -0
  237. data/lib/git/parsers/ls_tree.rb +58 -0
  238. data/lib/git/parsers/stash.rb +208 -0
  239. data/lib/git/parsers/tag.rb +257 -0
  240. data/lib/git/remote.rb +133 -9
  241. data/lib/git/repository/branching.rb +572 -0
  242. data/lib/git/repository/committing.rb +191 -0
  243. data/lib/git/repository/configuring.rb +156 -0
  244. data/lib/git/repository/diffing.rb +775 -0
  245. data/lib/git/repository/inspecting.rb +153 -0
  246. data/lib/git/repository/logging.rb +247 -0
  247. data/lib/git/repository/merging.rb +295 -0
  248. data/lib/git/repository/object_operations.rb +1101 -0
  249. data/lib/git/repository/path_resolver.rb +207 -0
  250. data/lib/git/repository/remote_operations.rb +753 -0
  251. data/lib/git/repository/shared_private.rb +51 -0
  252. data/lib/git/repository/staging.rb +390 -0
  253. data/lib/git/repository/stashing.rb +107 -0
  254. data/lib/git/repository/status_operations.rb +180 -0
  255. data/lib/git/repository/worktree_operations.rb +159 -0
  256. data/lib/git/repository.rb +264 -1
  257. data/lib/git/stash.rb +85 -4
  258. data/lib/git/stash_info.rb +104 -0
  259. data/lib/git/stashes.rb +130 -13
  260. data/lib/git/status.rb +226 -18
  261. data/lib/git/tag_delete_failure.rb +31 -0
  262. data/lib/git/tag_delete_result.rb +63 -0
  263. data/lib/git/tag_info.rb +105 -0
  264. data/lib/git/version.rb +109 -2
  265. data/lib/git/version_constraint.rb +81 -0
  266. data/lib/git/worktree.rb +120 -5
  267. data/lib/git/worktrees.rb +107 -7
  268. data/lib/git.rb +118 -69
  269. data/redesign/1_architecture_existing.md +54 -18
  270. data/redesign/2_architecture_redesign.md +365 -46
  271. data/redesign/3_architecture_implementation.md +1451 -54
  272. data/tasks/gem_tasks.rake +4 -0
  273. data/tasks/npm_tasks.rake +7 -0
  274. data/tasks/rspec.rake +48 -0
  275. data/tasks/rubocop.rake +2 -9
  276. data/tasks/test.rake +13 -1
  277. data/tasks/yard.rake +34 -7
  278. metadata +351 -22
  279. data/lib/git/index.rb +0 -6
  280. data/lib/git/path.rb +0 -38
  281. data/lib/git/working_directory.rb +0 -6
  282. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ # Represents a git version constraint with minimum and upper bound versions
5
+ #
6
+ # Used by {Git::Commands::Base.requires_git_version} to declare version requirements
7
+ # and by {Git::VersionError} to report constraint violations.
8
+ #
9
+ # @example Minimum version only
10
+ # constraint = Git::VersionConstraint.new(min: Git::Version.parse('2.30.0'))
11
+ # constraint.too_old?(Git::Version.parse('2.28.0')) #=> true
12
+ # constraint.too_new?(Git::Version.parse('2.28.0')) #=> false
13
+ #
14
+ # @example Upper bound only
15
+ # constraint = Git::VersionConstraint.new(before: Git::Version.parse('2.50.0'))
16
+ # constraint.too_old?(Git::Version.parse('2.51.0')) #=> false
17
+ # constraint.too_new?(Git::Version.parse('2.51.0')) #=> true
18
+ #
19
+ # @example Both bounds
20
+ # constraint = Git::VersionConstraint.new(
21
+ # min: Git::Version.parse('2.30.0'),
22
+ # before: Git::Version.parse('2.50.0')
23
+ # )
24
+ # constraint.satisfied_by?(Git::Version.parse('2.40.0')) #=> true
25
+ #
26
+ # @api public
27
+ #
28
+ VersionConstraint = Data.define(:min, :before) do
29
+ # @param min [Git::Version, nil] minimum version (inclusive)
30
+ # @param before [Git::Version, nil] upper bound version (exclusive)
31
+ def initialize(min: nil, before: nil)
32
+ super
33
+ end
34
+
35
+ # Check if the given version is too old (below the minimum)
36
+ #
37
+ # @param version [Git::Version] the version to check
38
+ #
39
+ # @return [Boolean] true if version is below the minimum, false otherwise
40
+ #
41
+ def too_old?(version)
42
+ return false unless min
43
+
44
+ version < min
45
+ end
46
+
47
+ # Check if the given version is too new (at or past the upper bound)
48
+ #
49
+ # @param version [Git::Version] the version to check
50
+ #
51
+ # @return [Boolean] true if version is at or past the upper bound, false otherwise
52
+ #
53
+ def too_new?(version)
54
+ return false unless before
55
+
56
+ version >= before
57
+ end
58
+
59
+ # Check if the given version satisfies this constraint
60
+ #
61
+ # @param version [Git::Version] the version to check
62
+ #
63
+ # @return [Boolean] true if the version satisfies the constraint
64
+ #
65
+ def satisfied_by?(version)
66
+ !too_old?(version) && !too_new?(version)
67
+ end
68
+
69
+ # Return a human-readable representation of this constraint
70
+ #
71
+ # @return [String] the constraint in git version range form
72
+ #
73
+ def to_s
74
+ return ">= #{min}, < #{before}" if min && before
75
+ return ">= #{min}" if min
76
+ return "< #{before}" if before
77
+
78
+ 'any version'
79
+ end
80
+ end
81
+ end
data/lib/git/worktree.rb CHANGED
@@ -1,12 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'git/path'
3
+ require 'git/base'
4
4
 
5
5
  module Git
6
6
  # A worktree in a Git repository
7
+ #
8
+ # Represents a single linked or main worktree. Constructed by
9
+ # {Git::Repository::WorktreeOperations#worktree} or populated by
10
+ # {Git::Worktrees}.
11
+ #
12
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy form)
13
+ # as the `base` argument. The `is_a?(Git::Base)` guard routes git operations
14
+ # through the facade repository and will be removed when {Git::Base} is
15
+ # deleted in Phase 4.
16
+ #
17
+ # @example Add and remove a linked worktree
18
+ # worktree = repo.worktree('/path/to/new-worktree')
19
+ # worktree.add
20
+ # worktree.remove
21
+ #
22
+ # @api public
23
+ #
7
24
  class Worktree
8
- attr_accessor :full, :dir
25
+ # Full worktree descriptor including the optional commitish
26
+ #
27
+ # @return [String] the filesystem path, space-separated with the commitish
28
+ # when one was given at construction time
29
+ #
30
+ attr_accessor :full
9
31
 
32
+ # Filesystem path of this worktree
33
+ #
34
+ # @return [String] the filesystem path of the worktree directory
35
+ #
36
+ attr_accessor :dir
37
+
38
+ # Creates a new Worktree object
39
+ #
40
+ # @param base [Git::Base, Git::Repository] the repository that owns this
41
+ # worktree
42
+ #
43
+ # @param dir [String] filesystem path of the worktree
44
+ #
45
+ # @param gcommit [String, nil] commitish associated with the worktree;
46
+ # when non-nil it is appended to {#full}
47
+ #
48
+ # @return [void]
49
+ #
10
50
  def initialize(base, dir, gcommit = nil)
11
51
  @full = dir
12
52
  @full += " #{gcommit}" unless gcommit.nil?
@@ -15,25 +55,100 @@ module Git
15
55
  @gcommit = gcommit
16
56
  end
17
57
 
58
+ # Returns the commit (or commitish string) associated with this worktree
59
+ #
60
+ # When a commitish string was supplied at construction time (e.g. by
61
+ # {Git::Worktrees} which passes the raw SHA from `git worktree list`), that
62
+ # string is returned as-is. Otherwise the value is lazily resolved on first
63
+ # call via `worktree_repository.gcommit(@full)` and the result is memoized.
64
+ #
65
+ # @example When resolved lazily (no commitish at construction)
66
+ # worktree = repo.worktree('/path/to/wt')
67
+ # worktree.gcommit # => #<Git::Object::Commit ...>
68
+ #
69
+ # @example When the commitish was given at construction
70
+ # worktree = repo.worktrees['/path/to/wt']
71
+ # worktree.gcommit # => "4bef5ab8c9..." (raw SHA string)
72
+ #
73
+ # @return [Git::Object::Commit, String] a commit object when lazily
74
+ # resolved, or the raw commitish string when pre-set at construction
75
+ #
76
+ # @raise [Git::FailedError] if git must resolve the commit and exits with a
77
+ # non-zero exit status
78
+ #
18
79
  def gcommit
19
- @gcommit ||= @base.gcommit(@full)
80
+ @gcommit ||= worktree_repository.gcommit(@full)
20
81
  @gcommit
21
82
  end
22
83
 
84
+ # Creates this worktree on disk
85
+ #
86
+ # Runs `git worktree add` for {#dir}, optionally at the commitish passed
87
+ # at construction time.
88
+ #
89
+ # @example Add a worktree
90
+ # worktree = repo.worktree('/path/to/new-worktree')
91
+ # worktree.add
92
+ #
93
+ # @return [String] stdout from the git command
94
+ #
95
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
96
+ #
23
97
  def add
24
- @base.lib.worktree_add(@dir, @gcommit)
98
+ worktree_repository.worktree_add(@dir, @gcommit)
25
99
  end
26
100
 
101
+ # Removes this worktree from disk
102
+ #
103
+ # Runs `git worktree remove` for {#dir}.
104
+ #
105
+ # @example Remove a worktree
106
+ # worktree.remove
107
+ #
108
+ # @return [String] stdout from the git command (typically empty)
109
+ #
110
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
111
+ #
27
112
  def remove
28
- @base.lib.worktree_remove(@dir)
113
+ worktree_repository.worktree_remove(@dir)
29
114
  end
30
115
 
116
+ # Returns an array containing the full worktree descriptor
117
+ #
118
+ # @example Get the descriptor array
119
+ # worktree.to_a # => ["/path/to/worktree"]
120
+ #
121
+ # @return [Array<String>] array containing the full worktree descriptor
122
+ #
31
123
  def to_a
32
124
  [@full]
33
125
  end
34
126
 
127
+ # Returns the full worktree descriptor as a string
128
+ #
129
+ # @example Get the descriptor string
130
+ # worktree.to_s # => "/path/to/worktree"
131
+ #
132
+ # @return [String] the full worktree descriptor (path and optional commitish)
133
+ #
35
134
  def to_s
36
135
  @full
37
136
  end
137
+
138
+ private
139
+
140
+ # Resolves the {Git::Repository} for worktree operations
141
+ #
142
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy).
143
+ # The `is_a?(Git::Base)` guard will be removed when {Git::Base} is deleted
144
+ # in Phase 4.
145
+ #
146
+ # @return [Git::Repository] the repository used for worktree operations
147
+ #
148
+ # @api private
149
+ #
150
+ def worktree_repository
151
+ @base.is_a?(Git::Base) ? @base.facade_repository : @base
152
+ end
38
153
  end
39
154
  end
data/lib/git/worktrees.rb CHANGED
@@ -1,47 +1,147 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'git/base'
4
+
3
5
  module Git
4
- # object that holds all the available worktrees
6
+ # Collection of all Git worktrees in a repository
7
+ #
8
+ # Wraps every linked and main worktree and provides enumeration and
9
+ # path-based lookup.
10
+ #
11
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy
12
+ # form) as the `base` argument. The `is_a?(Git::Base)` guard routes git
13
+ # operations through the facade repository and will be removed when
14
+ # {Git::Base} is deleted in Phase 4.
15
+ #
16
+ # @example Enumerate all worktrees
17
+ # worktrees = repo.worktrees
18
+ # worktrees.each { |wt| puts wt.dir }
19
+ #
20
+ # @api public
21
+ #
5
22
  class Worktrees
6
23
  include Enumerable
7
24
 
25
+ # Creates a new Worktrees collection populated from the given repository
26
+ #
27
+ # @param base [Git::Base, Git::Repository] the repository to enumerate
28
+ # worktrees from
29
+ #
30
+ # @return [void]
31
+ #
32
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
33
+ #
8
34
  def initialize(base)
9
35
  @worktrees = {}
10
36
 
11
37
  @base = base
12
38
 
13
- # Array contains [dir, git_hash]
14
- @base.lib.worktrees_all.each do |w|
39
+ worktree_repository.worktrees_all.each do |w|
15
40
  @worktrees[w[0]] = Git::Worktree.new(@base, w[0], w[1])
16
41
  end
17
42
  end
18
43
 
19
- # array like methods
20
-
44
+ # Returns the number of worktrees in the collection
45
+ #
46
+ # @example Count all worktrees
47
+ # repo.worktrees.size # => 2
48
+ #
49
+ # @return [Integer] the total number of worktrees
50
+ #
21
51
  def size
22
52
  @worktrees.size
23
53
  end
24
54
 
55
+ # Iterates over every worktree in the collection
56
+ #
57
+ # @overload each
58
+ #
59
+ # @example Get an enumerator over all worktrees
60
+ # enum = repo.worktrees.each
61
+ #
62
+ # @return [Enumerator<Git::Worktree>] an enumerator over all worktrees
63
+ #
64
+ # @overload each(&block)
65
+ #
66
+ # @example Print every worktree path
67
+ # repo.worktrees.each { |wt| puts wt.dir }
68
+ #
69
+ # @return [Array<Git::Worktree>] the full list of worktrees
70
+ #
71
+ # @yield [worktree] passes each worktree to the block
72
+ #
73
+ # @yieldparam worktree [Git::Worktree] a worktree in the repository
74
+ #
75
+ # @yieldreturn [void]
76
+ #
25
77
  def each(&)
26
78
  @worktrees.values.each(&)
27
79
  end
28
80
 
81
+ # Returns the worktree with the given path
82
+ #
83
+ # Supports lookup by the filesystem path of the worktree directory or by
84
+ # the full worktree descriptor (path and optional commitish).
85
+ #
86
+ # @example Look up a worktree by path
87
+ # repo.worktrees['/path/to/linked-worktree']
88
+ #
89
+ # @param worktree_name [#to_s] the path (or full descriptor) of the
90
+ # worktree to retrieve
91
+ #
92
+ # @return [Git::Worktree, nil] the matching worktree, or `nil` if not found
93
+ #
29
94
  def [](worktree_name)
30
95
  @worktrees.values.each_with_object(@worktrees) do |worktree, worktrees|
31
96
  worktrees[worktree.full] ||= worktree
32
97
  end[worktree_name.to_s]
33
98
  end
34
99
 
100
+ # Returns a string listing all worktrees, one per line
101
+ #
102
+ # @example Display all worktrees
103
+ # puts repo.worktrees.to_s
104
+ #
105
+ # @return [String] a newline-separated listing of worktree descriptors
106
+ #
35
107
  def to_s
36
- out = ''
108
+ out = +''
37
109
  @worktrees.each_value do |b|
38
110
  out << b.to_s << "\n"
39
111
  end
40
112
  out
41
113
  end
42
114
 
115
+ # Removes stale administrative files for worktrees that no longer exist
116
+ #
117
+ # Runs `git worktree prune` to clean up any lingering worktree metadata
118
+ # for linked worktrees whose directories have been deleted.
119
+ #
120
+ # @example Prune stale worktree metadata
121
+ # repo.worktrees.prune
122
+ #
123
+ # @return [String] stdout from the git command (typically empty)
124
+ #
125
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
126
+ #
43
127
  def prune
44
- @base.lib.worktree_prune
128
+ worktree_repository.worktree_prune
129
+ end
130
+
131
+ private
132
+
133
+ # Resolves the {Git::Repository} for this collection of worktrees
134
+ #
135
+ # Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy).
136
+ # The `is_a?(Git::Base)` guard will be removed when {Git::Base} is deleted
137
+ # in Phase 4.
138
+ #
139
+ # @return [Git::Repository] the repository used to enumerate worktrees
140
+ #
141
+ # @api private
142
+ #
143
+ def worktree_repository
144
+ @base.is_a?(Git::Base) ? @base.facade_repository : @base
45
145
  end
46
146
  end
47
147
  end