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.
Files changed (297) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +73 -2705
  3. data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
  4. data/.github/pull_request_template.md +3 -1
  5. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  6. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  7. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  8. data/.github/skills/command-implementation/SKILL.md +229 -0
  9. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  10. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  11. data/.github/skills/dependency-management/SKILL.md +72 -0
  12. data/.github/skills/development-workflow/SKILL.md +506 -0
  13. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  14. data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
  15. data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
  16. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  17. data/.github/skills/facade-implementation/SKILL.md +274 -0
  18. data/.github/skills/facade-test-conventions/SKILL.md +394 -0
  19. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  20. data/.github/skills/make-skill-template/SKILL.md +176 -0
  21. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  22. data/.github/skills/project-context/SKILL.md +313 -0
  23. data/.github/skills/pull-request-review/SKILL.md +168 -0
  24. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  25. data/.github/skills/release-management/SKILL.md +125 -0
  26. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  27. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  28. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  29. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  30. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  31. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  32. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  33. data/.github/skills/test-debugging/SKILL.md +160 -0
  34. data/.github/skills/yard-documentation/SKILL.md +793 -0
  35. data/.github/workflows/continuous_integration.yml +3 -2
  36. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  37. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  38. data/.github/workflows/release.yml +3 -4
  39. data/.gitignore +8 -0
  40. data/.husky/pre-commit +13 -0
  41. data/.release-please-manifest.json +1 -1
  42. data/.rspec +3 -0
  43. data/.rubocop.yml +12 -3
  44. data/.rubocop_todo.yml +23 -5
  45. data/.yardopts +1 -0
  46. data/CHANGELOG.md +0 -40
  47. data/CONTRIBUTING.md +694 -53
  48. data/README.md +67 -15
  49. data/Rakefile +61 -9
  50. data/UPGRADING.md +141 -0
  51. data/commitlint.test +4 -0
  52. data/git.gemspec +18 -7
  53. data/lib/git/args_builder.rb +0 -8
  54. data/lib/git/branch.rb +369 -43
  55. data/lib/git/branch_delete_failure.rb +31 -0
  56. data/lib/git/branch_delete_result.rb +63 -0
  57. data/lib/git/branch_info.rb +178 -0
  58. data/lib/git/branches.rb +122 -24
  59. data/lib/git/command_line/base.rb +255 -0
  60. data/lib/git/command_line/capturing.rb +251 -0
  61. data/lib/git/command_line/result.rb +96 -0
  62. data/lib/git/command_line/streaming.rb +196 -0
  63. data/lib/git/command_line.rb +43 -322
  64. data/lib/git/command_line_result.rb +4 -88
  65. data/lib/git/commands/add.rb +131 -0
  66. data/lib/git/commands/am/abort.rb +43 -0
  67. data/lib/git/commands/am/apply.rb +252 -0
  68. data/lib/git/commands/am/continue.rb +43 -0
  69. data/lib/git/commands/am/quit.rb +43 -0
  70. data/lib/git/commands/am/retry.rb +47 -0
  71. data/lib/git/commands/am/show_current_patch.rb +64 -0
  72. data/lib/git/commands/am/skip.rb +42 -0
  73. data/lib/git/commands/am.rb +33 -0
  74. data/lib/git/commands/apply.rb +237 -0
  75. data/lib/git/commands/archive/list_formats.rb +46 -0
  76. data/lib/git/commands/archive.rb +140 -0
  77. data/lib/git/commands/arguments.rb +3510 -0
  78. data/lib/git/commands/base.rb +404 -0
  79. data/lib/git/commands/branch/copy.rb +94 -0
  80. data/lib/git/commands/branch/create.rb +173 -0
  81. data/lib/git/commands/branch/delete.rb +80 -0
  82. data/lib/git/commands/branch/list.rb +162 -0
  83. data/lib/git/commands/branch/move.rb +94 -0
  84. data/lib/git/commands/branch/set_upstream.rb +86 -0
  85. data/lib/git/commands/branch/show_current.rb +49 -0
  86. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  87. data/lib/git/commands/branch.rb +34 -0
  88. data/lib/git/commands/cat_file/batch.rb +369 -0
  89. data/lib/git/commands/cat_file/filtered.rb +105 -0
  90. data/lib/git/commands/cat_file/raw.rb +216 -0
  91. data/lib/git/commands/cat_file.rb +49 -0
  92. data/lib/git/commands/checkout/branch.rb +151 -0
  93. data/lib/git/commands/checkout/files.rb +115 -0
  94. data/lib/git/commands/checkout.rb +38 -0
  95. data/lib/git/commands/checkout_index.rb +105 -0
  96. data/lib/git/commands/clean.rb +100 -0
  97. data/lib/git/commands/clone.rb +240 -0
  98. data/lib/git/commands/commit.rb +272 -0
  99. data/lib/git/commands/commit_tree.rb +100 -0
  100. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  101. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  102. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  103. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  104. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  105. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  106. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
  107. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  108. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  109. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  110. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  111. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  112. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  113. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  114. data/lib/git/commands/config_option_syntax.rb +56 -0
  115. data/lib/git/commands/describe.rb +155 -0
  116. data/lib/git/commands/diff.rb +656 -0
  117. data/lib/git/commands/diff_files.rb +518 -0
  118. data/lib/git/commands/diff_index.rb +496 -0
  119. data/lib/git/commands/fetch.rb +352 -0
  120. data/lib/git/commands/fsck.rb +136 -0
  121. data/lib/git/commands/gc.rb +132 -0
  122. data/lib/git/commands/grep.rb +338 -0
  123. data/lib/git/commands/init.rb +99 -0
  124. data/lib/git/commands/log.rb +632 -0
  125. data/lib/git/commands/ls_files.rb +191 -0
  126. data/lib/git/commands/ls_remote.rb +155 -0
  127. data/lib/git/commands/ls_tree.rb +131 -0
  128. data/lib/git/commands/maintenance/register.rb +75 -0
  129. data/lib/git/commands/maintenance/run.rb +104 -0
  130. data/lib/git/commands/maintenance/start.rb +66 -0
  131. data/lib/git/commands/maintenance/stop.rb +55 -0
  132. data/lib/git/commands/maintenance/unregister.rb +79 -0
  133. data/lib/git/commands/maintenance.rb +31 -0
  134. data/lib/git/commands/merge/abort.rb +44 -0
  135. data/lib/git/commands/merge/continue.rb +44 -0
  136. data/lib/git/commands/merge/quit.rb +46 -0
  137. data/lib/git/commands/merge/start.rb +245 -0
  138. data/lib/git/commands/merge.rb +28 -0
  139. data/lib/git/commands/merge_base.rb +86 -0
  140. data/lib/git/commands/mv.rb +77 -0
  141. data/lib/git/commands/name_rev.rb +114 -0
  142. data/lib/git/commands/pull.rb +377 -0
  143. data/lib/git/commands/push.rb +246 -0
  144. data/lib/git/commands/read_tree.rb +149 -0
  145. data/lib/git/commands/remote/add.rb +91 -0
  146. data/lib/git/commands/remote/get_url.rb +66 -0
  147. data/lib/git/commands/remote/list.rb +54 -0
  148. data/lib/git/commands/remote/prune.rb +61 -0
  149. data/lib/git/commands/remote/remove.rb +52 -0
  150. data/lib/git/commands/remote/rename.rb +69 -0
  151. data/lib/git/commands/remote/set_branches.rb +63 -0
  152. data/lib/git/commands/remote/set_head.rb +82 -0
  153. data/lib/git/commands/remote/set_url.rb +71 -0
  154. data/lib/git/commands/remote/set_url_add.rb +61 -0
  155. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  156. data/lib/git/commands/remote/show.rb +71 -0
  157. data/lib/git/commands/remote/update.rb +72 -0
  158. data/lib/git/commands/remote.rb +42 -0
  159. data/lib/git/commands/repack.rb +277 -0
  160. data/lib/git/commands/reset.rb +147 -0
  161. data/lib/git/commands/rev_parse.rb +297 -0
  162. data/lib/git/commands/revert/abort.rb +45 -0
  163. data/lib/git/commands/revert/continue.rb +57 -0
  164. data/lib/git/commands/revert/quit.rb +47 -0
  165. data/lib/git/commands/revert/skip.rb +44 -0
  166. data/lib/git/commands/revert/start.rb +153 -0
  167. data/lib/git/commands/revert.rb +29 -0
  168. data/lib/git/commands/rm.rb +114 -0
  169. data/lib/git/commands/show.rb +632 -0
  170. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  171. data/lib/git/commands/show_ref/exists.rb +78 -0
  172. data/lib/git/commands/show_ref/list.rb +145 -0
  173. data/lib/git/commands/show_ref/verify.rb +120 -0
  174. data/lib/git/commands/show_ref.rb +42 -0
  175. data/lib/git/commands/stash/apply.rb +75 -0
  176. data/lib/git/commands/stash/branch.rb +65 -0
  177. data/lib/git/commands/stash/clear.rb +41 -0
  178. data/lib/git/commands/stash/create.rb +58 -0
  179. data/lib/git/commands/stash/drop.rb +67 -0
  180. data/lib/git/commands/stash/list.rb +39 -0
  181. data/lib/git/commands/stash/pop.rb +78 -0
  182. data/lib/git/commands/stash/push.rb +103 -0
  183. data/lib/git/commands/stash/show.rb +149 -0
  184. data/lib/git/commands/stash/store.rb +63 -0
  185. data/lib/git/commands/stash.rb +38 -0
  186. data/lib/git/commands/status.rb +169 -0
  187. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  188. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  189. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  190. data/lib/git/commands/symbolic_ref.rb +38 -0
  191. data/lib/git/commands/tag/create.rb +139 -0
  192. data/lib/git/commands/tag/delete.rb +55 -0
  193. data/lib/git/commands/tag/list.rb +143 -0
  194. data/lib/git/commands/tag/verify.rb +71 -0
  195. data/lib/git/commands/tag.rb +26 -0
  196. data/lib/git/commands/update_ref/batch.rb +140 -0
  197. data/lib/git/commands/update_ref/delete.rb +92 -0
  198. data/lib/git/commands/update_ref/update.rb +106 -0
  199. data/lib/git/commands/update_ref.rb +42 -0
  200. data/lib/git/commands/version.rb +57 -0
  201. data/lib/git/commands/worktree/add.rb +140 -0
  202. data/lib/git/commands/worktree/list.rb +64 -0
  203. data/lib/git/commands/worktree/lock.rb +58 -0
  204. data/lib/git/commands/worktree/management_base.rb +51 -0
  205. data/lib/git/commands/worktree/move.rb +66 -0
  206. data/lib/git/commands/worktree/prune.rb +67 -0
  207. data/lib/git/commands/worktree/remove.rb +63 -0
  208. data/lib/git/commands/worktree/repair.rb +76 -0
  209. data/lib/git/commands/worktree/unlock.rb +47 -0
  210. data/lib/git/commands/worktree.rb +43 -0
  211. data/lib/git/commands/write_tree.rb +68 -0
  212. data/lib/git/commands.rb +87 -0
  213. data/lib/git/config.rb +17 -0
  214. data/lib/git/config_entry_info.rb +106 -0
  215. data/lib/git/configuring.rb +665 -0
  216. data/lib/git/deprecation.rb +9 -0
  217. data/lib/git/detached_head_info.rb +54 -0
  218. data/lib/git/diff.rb +293 -7
  219. data/lib/git/diff_file_numstat_info.rb +29 -0
  220. data/lib/git/diff_file_patch_info.rb +134 -0
  221. data/lib/git/diff_file_raw_info.rb +127 -0
  222. data/lib/git/diff_info.rb +169 -0
  223. data/lib/git/diff_path_status.rb +67 -19
  224. data/lib/git/diff_result.rb +32 -0
  225. data/lib/git/diff_stats.rb +51 -14
  226. data/lib/git/dirstat_info.rb +86 -0
  227. data/lib/git/errors.rb +65 -2
  228. data/lib/git/execution_context/global.rb +31 -0
  229. data/lib/git/execution_context/repository.rb +136 -0
  230. data/lib/git/execution_context.rb +501 -0
  231. data/lib/git/file_ref.rb +74 -0
  232. data/lib/git/fsck_object.rb +9 -9
  233. data/lib/git/fsck_result.rb +1 -1
  234. data/lib/git/log.rb +9 -2
  235. data/lib/git/object.rb +90 -27
  236. data/lib/git/parsers/branch.rb +224 -0
  237. data/lib/git/parsers/cat_file.rb +111 -0
  238. data/lib/git/parsers/config_entry.rb +110 -0
  239. data/lib/git/parsers/diff.rb +585 -0
  240. data/lib/git/parsers/fsck.rb +133 -0
  241. data/lib/git/parsers/grep.rb +42 -0
  242. data/lib/git/parsers/ls_remote.rb +79 -0
  243. data/lib/git/parsers/ls_tree.rb +58 -0
  244. data/lib/git/parsers/stash.rb +208 -0
  245. data/lib/git/parsers/tag.rb +257 -0
  246. data/lib/git/remote.rb +120 -9
  247. data/lib/git/repository/branching.rb +743 -0
  248. data/lib/git/repository/committing.rb +187 -0
  249. data/lib/git/repository/configuring.rb +351 -0
  250. data/lib/git/repository/context_helpers.rb +264 -0
  251. data/lib/git/repository/diffing.rb +775 -0
  252. data/lib/git/repository/factories.rb +682 -0
  253. data/lib/git/repository/inspecting.rb +252 -0
  254. data/lib/git/repository/logging.rb +247 -0
  255. data/lib/git/repository/maintenance.rb +65 -0
  256. data/lib/git/repository/merging.rb +357 -0
  257. data/lib/git/repository/object_operations.rb +1199 -0
  258. data/lib/git/repository/path_resolver.rb +207 -0
  259. data/lib/git/repository/remote_operations.rb +898 -0
  260. data/lib/git/repository/shared_private.rb +51 -0
  261. data/lib/git/repository/staging.rb +554 -0
  262. data/lib/git/repository/stashing.rb +143 -0
  263. data/lib/git/repository/status_operations.rb +201 -0
  264. data/lib/git/repository/worktree_operations.rb +159 -0
  265. data/lib/git/repository.rb +203 -1
  266. data/lib/git/stash.rb +78 -4
  267. data/lib/git/stash_info.rb +104 -0
  268. data/lib/git/stashes.rb +125 -13
  269. data/lib/git/status.rb +215 -18
  270. data/lib/git/tag_delete_failure.rb +31 -0
  271. data/lib/git/tag_delete_result.rb +63 -0
  272. data/lib/git/tag_info.rb +105 -0
  273. data/lib/git/version.rb +109 -2
  274. data/lib/git/version_constraint.rb +81 -0
  275. data/lib/git/worktree.rb +108 -6
  276. data/lib/git/worktrees.rb +94 -7
  277. data/lib/git.rb +260 -61
  278. data/redesign/1_architecture_existing.md +54 -18
  279. data/redesign/2_architecture_redesign.md +365 -46
  280. data/redesign/3_architecture_implementation.md +1497 -63
  281. data/redesign/Phase 4 - Step A.md +360 -0
  282. data/redesign/beta_release.md +107 -0
  283. data/redesign/c1c2_audit.md +566 -0
  284. data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
  285. data/redesign/config_design.rb +501 -0
  286. data/tasks/gem_tasks.rake +4 -0
  287. data/tasks/npm_tasks.rake +7 -0
  288. data/tasks/rspec.rake +48 -0
  289. data/tasks/test.rake +13 -1
  290. data/tasks/yard.rake +34 -7
  291. metadata +365 -22
  292. data/lib/git/base.rb +0 -1128
  293. data/lib/git/index.rb +0 -6
  294. data/lib/git/lib.rb +0 -2277
  295. data/lib/git/path.rb +0 -38
  296. data/lib/git/working_directory.rb +0 -6
  297. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -0,0 +1,743 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+ require 'git/branch'
5
+ require 'git/branch_info'
6
+ require 'git/branches'
7
+ require 'git/commands/branch/create'
8
+ require 'git/commands/branch/delete'
9
+ require 'git/commands/branch/list'
10
+ require 'git/commands/branch/show_current'
11
+ require 'git/commands/checkout/branch'
12
+ require 'git/commands/checkout/files'
13
+ require 'git/commands/checkout_index'
14
+ require 'git/commands/rev_parse'
15
+ require 'git/commands/update_ref/update'
16
+ require 'git/commands/symbolic_ref/update'
17
+ require 'git/parsers/branch'
18
+ require 'git/repository/shared_private'
19
+
20
+ module Git
21
+ class Repository
22
+ # Facade methods for branching operations: creating, checking out, querying,
23
+ # deleting, and updating branches
24
+ #
25
+ # Included by {Git::Repository}.
26
+ #
27
+ # @api public
28
+ #
29
+ module Branching # rubocop:disable Metrics/ModuleLength
30
+ # Represents the state of HEAD in a repository
31
+ #
32
+ # @!attribute [r] state
33
+ # @return [Symbol] one of `:active`, `:unborn`, or `:detached`
34
+ #
35
+ # @!attribute [r] name
36
+ # @return [String] the branch name, or `'HEAD'` when detached
37
+ #
38
+ HeadState = Data.define(:state, :name)
39
+
40
+ # Option keys accepted by {#checkout}
41
+ #
42
+ CHECKOUT_ALLOWED_OPTS = %i[force f new_branch b start_point].freeze
43
+ private_constant :CHECKOUT_ALLOWED_OPTS
44
+
45
+ # Option keys accepted by {#checkout_index}
46
+ #
47
+ CHECKOUT_INDEX_ALLOWED_OPTS = %i[prefix force all path_limiter].freeze
48
+ private_constant :CHECKOUT_INDEX_ALLOWED_OPTS
49
+
50
+ # Returns the name of the current branch
51
+ #
52
+ # @example Get the current branch name
53
+ # repo.current_branch # => "main"
54
+ #
55
+ # @example In detached HEAD state
56
+ # repo.current_branch # => "HEAD"
57
+ #
58
+ # @return [String] the current branch name, or `'HEAD'` when in detached
59
+ # HEAD state
60
+ #
61
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
62
+ #
63
+ def current_branch
64
+ result = Git::Commands::Branch::ShowCurrent.new(@execution_context).call
65
+ name = result.stdout.strip
66
+ name.empty? ? 'HEAD' : name
67
+ end
68
+
69
+ # Returns the current HEAD state as a structured value object
70
+ #
71
+ # HEAD can be in one of three states:
72
+ #
73
+ # - **`:active`** — HEAD points to a branch ref that has at least one commit.
74
+ # - **`:unborn`** — HEAD points to a branch ref that has been created but has
75
+ # no commits yet (e.g. immediately after `git init` before any commit).
76
+ # - **`:detached`** — HEAD points directly to a commit SHA rather than a branch.
77
+ #
78
+ # @example Active branch
79
+ # repo.current_branch_state
80
+ # # => #<data Git::Repository::Branching::HeadState state=:active, name="main">
81
+ #
82
+ # @example Unborn branch (no commits yet)
83
+ # repo.current_branch_state
84
+ # # => #<data Git::Repository::Branching::HeadState state=:unborn, name="main">
85
+ #
86
+ # @example Detached HEAD
87
+ # repo.current_branch_state
88
+ # # => #<data Git::Repository::Branching::HeadState state=:detached, name="HEAD">
89
+ #
90
+ # @return [Git::Repository::Branching::HeadState] the current HEAD state
91
+ #
92
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
93
+ #
94
+ def current_branch_state
95
+ branch_name = Git::Commands::Branch::ShowCurrent.new(@execution_context).call.stdout.strip
96
+ return HeadState.new(state: :detached, name: 'HEAD') if branch_name.empty?
97
+
98
+ state = Private.get_branch_state(@execution_context, branch_name)
99
+ HeadState.new(state: state, name: branch_name)
100
+ end
101
+
102
+ # Restore working tree files from a tree-ish
103
+ #
104
+ # @example Restore README.md to its HEAD state
105
+ # repo.checkout_file('HEAD', 'README.md')
106
+ #
107
+ # @param version [String] the tree-ish (branch, tag, commit SHA, etc.) to
108
+ # restore the file from
109
+ #
110
+ # @param file [String] the path to the file to restore
111
+ #
112
+ # @return [String] git's stdout from the checkout
113
+ #
114
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
115
+ #
116
+ def checkout_file(version, file)
117
+ Git::Commands::Checkout::Files.new(@execution_context).call(version, pathspec: [file]).stdout
118
+ end
119
+
120
+ # Switch branches or restore working tree files
121
+ #
122
+ # @example Check out an existing branch
123
+ # repo.checkout('main')
124
+ #
125
+ # @example Create and check out a new branch from main
126
+ # repo.checkout('new-feature', new_branch: true, start_point: 'main')
127
+ #
128
+ # @example Create a new branch with a name different from the start point
129
+ # repo.checkout('main', new_branch: 'new-feature')
130
+ #
131
+ # @example Force checkout discarding local changes
132
+ # repo.checkout('main', force: true)
133
+ #
134
+ # @param branch [String, nil] the branch to check out; defaults to nil
135
+ # (i.e. restore HEAD state)
136
+ #
137
+ # @param opts [Hash] options for the checkout command
138
+ #
139
+ # @option opts [Boolean, nil] :force (nil) discard local changes when
140
+ # switching branches
141
+ #
142
+ # @option opts [Boolean, String, nil] :new_branch (nil) when `true`,
143
+ # creates a new branch named `branch` from `:start_point`
144
+ #
145
+ # When a `String`, creates a new branch with that name, using `branch`
146
+ # as the start point.
147
+ #
148
+ # @option opts [Boolean, String, nil] :b (nil) alias for `:new_branch`
149
+ #
150
+ # @option opts [Boolean, nil] :f (nil) alias for `:force`
151
+ #
152
+ # @option opts [String, nil] :start_point (nil) the commit or branch to
153
+ # start the new branch from; used together with `new_branch: true`
154
+ #
155
+ # @return [String] git's stdout from the checkout
156
+ #
157
+ # @raise [ArgumentError] if unsupported options are provided
158
+ #
159
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
160
+ #
161
+ def checkout(branch = nil, opts = {})
162
+ if branch.is_a?(Hash) && opts.empty?
163
+ opts = branch
164
+ branch = nil
165
+ end
166
+
167
+ SharedPrivate.assert_valid_opts!(CHECKOUT_ALLOWED_OPTS, **opts)
168
+
169
+ target, translated_opts = Private.translate_checkout_opts(branch, opts)
170
+ Git::Commands::Checkout::Branch.new(@execution_context).call(target, **translated_opts).stdout
171
+ end
172
+
173
+ # Populate the working tree from the index
174
+ #
175
+ # @example Check out all files from the index
176
+ # repo.checkout_index(all: true)
177
+ #
178
+ # @example Force check out a specific file
179
+ # repo.checkout_index(force: true, path_limiter: 'README.md')
180
+ #
181
+ # @example Check out files to a staging prefix
182
+ # repo.checkout_index(prefix: 'tmp/stage/', all: true)
183
+ #
184
+ # @param options [Hash] options for the checkout-index command
185
+ #
186
+ # @option options [Boolean, nil] :all (nil) check out all files in the index
187
+ #
188
+ # @option options [Boolean, nil] :force (nil) overwrite existing files
189
+ #
190
+ # @option options [String, nil] :prefix (nil) write files under this path prefix
191
+ # rather than the working directory root
192
+ #
193
+ # @option options [String, Pathname, Array<String, Pathname>, nil] :path_limiter (nil)
194
+ # limit the check out to the given path(s)
195
+ #
196
+ # @return [String] git's stdout from the checkout-index command
197
+ #
198
+ # @raise [ArgumentError] if unsupported options are provided
199
+ #
200
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
201
+ #
202
+ def checkout_index(options = {})
203
+ SharedPrivate.assert_valid_opts!(CHECKOUT_INDEX_ALLOWED_OPTS, **options)
204
+
205
+ paths = Private.normalize_pathspecs(options[:path_limiter], 'path_limiter')
206
+ keyword_opts = options.except(:path_limiter)
207
+ Git::Commands::CheckoutIndex.new(@execution_context).call(*paths.to_a, **keyword_opts).stdout
208
+ end
209
+
210
+ # Returns `true` if the named branch exists as a local branch
211
+ #
212
+ # @example Check whether main exists locally
213
+ # repo.local_branch?('main') # => true
214
+ #
215
+ # @param branch [String] the local branch name to look up
216
+ #
217
+ # @return [Boolean] `true` if the branch exists locally, `false` otherwise
218
+ #
219
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
220
+ #
221
+ def local_branch?(branch)
222
+ result = Git::Commands::Branch::List.new(@execution_context).call(branch, format: '%(refname:short)')
223
+ result.stdout.chomp == branch
224
+ end
225
+
226
+ # Returns `true` if the named branch exists as a remote-tracking branch
227
+ #
228
+ # The `branch` argument must be the **short branch name** (e.g. `'master'`),
229
+ # not the combined `remote/branch` form (e.g. `'origin/master'`).
230
+ #
231
+ # @example Check whether master exists on any remote
232
+ # repo.remote_branch?('master') # => true
233
+ #
234
+ # @param branch [String] the short branch name to look up across all remotes
235
+ #
236
+ # @return [Boolean] `true` if a remote-tracking branch with that short name
237
+ # exists, `false` otherwise
238
+ #
239
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
240
+ #
241
+ def remote_branch?(branch)
242
+ result = Git::Commands::Branch::List.new(@execution_context)
243
+ .call("*/#{branch}", remotes: true, format: '%(refname:lstrip=3)')
244
+ result.stdout.each_line.any? { |line| line.chomp == branch }
245
+ end
246
+
247
+ # Returns `true` if the named branch exists locally or as a remote-tracking branch
248
+ #
249
+ # @example Check whether main exists anywhere
250
+ # repo.branch?('main') # => true
251
+ #
252
+ # @param branch [String] the branch name to look up
253
+ #
254
+ # @return [Boolean] `true` if the branch exists locally or remotely,
255
+ # `false` otherwise
256
+ #
257
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
258
+ #
259
+ def branch?(branch)
260
+ local_branch?(branch) || remote_branch?(branch)
261
+ end
262
+
263
+ # Checks whether the named branch exists locally
264
+ #
265
+ # @example Check whether main exists locally
266
+ # repo.is_local_branch?('main') # => true
267
+ #
268
+ # @param branch [String] the local branch name to look up
269
+ #
270
+ # @return [Boolean] `true` if the branch exists locally, `false` otherwise
271
+ #
272
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
273
+ #
274
+ # @deprecated use {#local_branch?} instead
275
+ #
276
+ def is_local_branch?(branch) # rubocop:disable Naming/PredicatePrefix
277
+ Git::Deprecation.warn(
278
+ 'Git::Repository#is_local_branch? is deprecated and will be removed in a future version. ' \
279
+ 'Use Git::Repository#local_branch? instead.'
280
+ )
281
+ local_branch?(branch)
282
+ end
283
+
284
+ # Checks whether the named branch exists as a remote-tracking branch
285
+ #
286
+ # @example Check whether master exists on any remote
287
+ # repo.is_remote_branch?('master') # => true
288
+ #
289
+ # @param branch [String] the short branch name to look up across all remotes
290
+ #
291
+ # @return [Boolean] `true` if a remote-tracking branch with that short name
292
+ # exists, `false` otherwise
293
+ #
294
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
295
+ #
296
+ # @deprecated use {#remote_branch?} instead
297
+ #
298
+ def is_remote_branch?(branch) # rubocop:disable Naming/PredicatePrefix
299
+ Git::Deprecation.warn(
300
+ 'Git::Repository#is_remote_branch? is deprecated and will be removed in a future version. ' \
301
+ 'Use Git::Repository#remote_branch? instead.'
302
+ )
303
+ remote_branch?(branch)
304
+ end
305
+
306
+ # Checks whether the named branch exists locally or as a remote-tracking branch
307
+ #
308
+ # @example Check whether main exists anywhere
309
+ # repo.is_branch?('main') # => true
310
+ #
311
+ # @param branch [String] the branch name to look up
312
+ #
313
+ # @return [Boolean] `true` if the branch exists locally or remotely,
314
+ # `false` otherwise
315
+ #
316
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
317
+ #
318
+ # @deprecated use {#branch?} instead
319
+ #
320
+ def is_branch?(branch) # rubocop:disable Naming/PredicatePrefix
321
+ Git::Deprecation.warn(
322
+ 'Git::Repository#is_branch? is deprecated and will be removed in a future version. ' \
323
+ 'Use Git::Repository#branch? instead.'
324
+ )
325
+ branch?(branch)
326
+ end
327
+
328
+ # Option keys accepted by {#branch_new}
329
+ #
330
+ BRANCH_NEW_ALLOWED_OPTS = %i[].freeze
331
+ private_constant :BRANCH_NEW_ALLOWED_OPTS
332
+
333
+ # Create a new branch
334
+ #
335
+ # @example Create a new branch from the current HEAD
336
+ # repo.branch_new('feature')
337
+ #
338
+ # @example Create a new branch from a specific commit or branch
339
+ # repo.branch_new('feature', 'main')
340
+ #
341
+ # @param branch [String] the name of the branch to create
342
+ #
343
+ # @param start_point [String, nil] the commit, branch, or tag to start the
344
+ # new branch from; defaults to the current HEAD when `nil`
345
+ #
346
+ # @param options [Hash] reserved; must be empty — no options are currently
347
+ # supported
348
+ #
349
+ # @return [void]
350
+ #
351
+ # @raise [ArgumentError] if unsupported options are provided
352
+ #
353
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
354
+ #
355
+ def branch_new(branch, start_point = nil, options = {})
356
+ if start_point.is_a?(Hash) && options.empty?
357
+ options = start_point
358
+ start_point = nil
359
+ end
360
+
361
+ SharedPrivate.assert_valid_opts!(BRANCH_NEW_ALLOWED_OPTS, **options)
362
+ Git::Commands::Branch::Create.new(@execution_context).call(branch, start_point, **options)
363
+
364
+ nil
365
+ end
366
+
367
+ # Option keys accepted by {#branch_delete}
368
+ #
369
+ BRANCH_DELETE_ALLOWED_OPTS = %i[force remotes].freeze
370
+ private_constant :BRANCH_DELETE_ALLOWED_OPTS
371
+
372
+ # Delete one or more local or remote-tracking branches
373
+ #
374
+ # @example Delete a single branch
375
+ # repo.branch_delete('feature') # => "Deleted branch feature (was abc1234)."
376
+ #
377
+ # @example Delete multiple branches at once
378
+ # repo.branch_delete('feature-1', 'feature-2')
379
+ #
380
+ # @example Force-delete an unmerged branch
381
+ # repo.branch_delete('unmerged-branch', force: true)
382
+ #
383
+ # @example Delete a remote-tracking branch
384
+ # repo.branch_delete('origin/feature', remotes: true)
385
+ #
386
+ # @param branches [Array<String>] the name(s) of the branch(es) to delete
387
+ #
388
+ # @param options [Hash] options for the delete command
389
+ #
390
+ # @option options [Boolean, nil] :force (true) allow deleting the branch
391
+ # irrespective of its merged status
392
+ #
393
+ # Defaults to `true` to match the 4.x behavior.
394
+ #
395
+ # @option options [Boolean, nil] :remotes (nil) delete remote-tracking
396
+ # branches
397
+ #
398
+ # Use together with a `remote/branch` name.
399
+ #
400
+ # @return [String] the stdout output from the delete command, e.g.
401
+ # `"Deleted branch feature (was abc1234)."`
402
+ #
403
+ # @raise [ArgumentError] if unsupported options are provided
404
+ #
405
+ # @raise [Git::FailedError] if git exits outside the allowed range (exit code > 1)
406
+ #
407
+ # @raise [Git::Error] if git reports a deletion failure
408
+ #
409
+ def branch_delete(*branches, **options)
410
+ options = { force: true }.merge(options)
411
+ SharedPrivate.assert_valid_opts!(BRANCH_DELETE_ALLOWED_OPTS, **options)
412
+
413
+ result = Git::Commands::Branch::Delete.new(@execution_context).call(*branches, **options)
414
+
415
+ raise Git::Error, result.stderr.strip unless result.status.success?
416
+
417
+ result.stdout.strip
418
+ end
419
+
420
+ # Writes the HEAD symbolic ref to point at the given branch
421
+ #
422
+ # Sets `HEAD` to `refs/heads/<branch_name>` via `git symbolic-ref`. This is
423
+ # equivalent to running `git symbolic-ref HEAD refs/heads/<branch_name>` on
424
+ # the command line and is the mechanism git uses internally for branch
425
+ # renaming and orphan-branch checkout.
426
+ #
427
+ # @example Change HEAD to point to an existing branch
428
+ # repo.change_head_branch('main')
429
+ #
430
+ # @example Initialize a repository with a custom default branch name (unborn-branch pattern)
431
+ # repo = Git.init('/path/to/repo')
432
+ # repo.change_head_branch('my-branch')
433
+ # # HEAD now points at refs/heads/my-branch before any commits exist
434
+ #
435
+ # @note Pointing HEAD at a branch that does not yet exist places the
436
+ # repository in unborn-branch state. This is intentional for repository
437
+ # initialization workflows — for example, setting a custom default branch
438
+ # name before any commits land — but is unexpected if done by mistake.
439
+ # The repository will appear to have no commits until the first commit is
440
+ # made on the new branch.
441
+ #
442
+ # @param branch_name [String] the branch name to point HEAD at
443
+ #
444
+ # @return [void]
445
+ #
446
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
447
+ #
448
+ def change_head_branch(branch_name)
449
+ Git::Commands::SymbolicRef::Update.new(@execution_context).call('HEAD', "refs/heads/#{branch_name}")
450
+ nil
451
+ end
452
+
453
+ # Returns the `git branch --list --contains` stdout for a given commit
454
+ #
455
+ # The output format is the human-readable `git branch` listing: each
456
+ # matching branch name appears on its own line, prefixed with two spaces,
457
+ # or `* ` if it is the currently checked-out branch. This is the same
458
+ # format returned by `Git::Lib#branch_contains` in the 4.x gem series.
459
+ #
460
+ # @example List all branches that contain a commit
461
+ # repo.branch_contains('abc1234')
462
+ # # => " main\n"
463
+ #
464
+ # @example The current branch is marked with an asterisk
465
+ # repo.branch_contains('abc1234')
466
+ # # => "* main\n feature\n"
467
+ #
468
+ # @example Limit the search to branches matching a shell wildcard pattern
469
+ # repo.branch_contains('abc1234', 'feature/*')
470
+ #
471
+ # @example Typical usage: check whether any branch contains the commit
472
+ # repo.branch_contains('abc1234').empty? # => false
473
+ #
474
+ # @param commit [String] the commit SHA or ref to look up
475
+ #
476
+ # @param branch_name [String, nil] a shell wildcard pattern to limit which
477
+ # branches are searched
478
+ #
479
+ # When empty or `nil`, all local branches are searched.
480
+ #
481
+ # @return [String] the `git branch --list --contains` stdout
482
+ #
483
+ # Each matching branch appears on its own line, prefixed with two
484
+ # spaces, or `* ` for the currently checked-out branch. Returns an
485
+ # empty string when no matching branch contains the commit.
486
+ #
487
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
488
+ #
489
+ def branch_contains(commit, branch_name = '')
490
+ branch_name = branch_name.to_s
491
+ pattern = branch_name.empty? ? nil : branch_name
492
+ Git::Commands::Branch::List.new(@execution_context)
493
+ .call(*[pattern].compact, contains: commit, no_color: true)
494
+ .stdout
495
+ end
496
+
497
+ # Returns all local and remote-tracking branches as structured objects
498
+ #
499
+ # @example List all branches
500
+ # repo.branches_all
501
+ # # => [#<data Git::BranchInfo refname="main", current=true, ...>,
502
+ # # #<data Git::BranchInfo refname="remotes/origin/main", current=false, ...>]
503
+ #
504
+ # @example Find the currently checked-out branch
505
+ # repo.branches_all.find(&:current)
506
+ #
507
+ # @example List only local branches
508
+ # repo.branches_all.reject(&:remote?)
509
+ #
510
+ # @return [Array<Git::BranchInfo>] parsed branch information for every
511
+ # local and remote-tracking branch
512
+ #
513
+ # Returns an empty array when the repository has no branches.
514
+ #
515
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
516
+ #
517
+ def branches_all
518
+ result = Git::Commands::Branch::List.new(@execution_context).call(
519
+ all: true, format: Git::Parsers::Branch::FORMAT_STRING
520
+ )
521
+ Git::Parsers::Branch.parse_list(result.stdout)
522
+ end
523
+
524
+ # Update a branch ref to point to a new commit
525
+ #
526
+ # Derives the full ref from the `branch` argument:
527
+ #
528
+ # - `remotes/<remote>/<name>` or `refs/remotes/<remote>/<name>` →
529
+ # writes to `refs/remotes/<remote>/<name>` (remote-tracking branch)
530
+ # - Any other value → writes to `refs/heads/<branch>` (local branch)
531
+ #
532
+ # @example Advance a local branch to the current HEAD
533
+ # repo.update_ref('feature', repo.rev_parse('HEAD'))
534
+ #
535
+ # @example Reset a local branch to an older commit
536
+ # repo.update_ref('main', 'abc1234def5678')
537
+ #
538
+ # @example Update a remote-tracking branch ref
539
+ # repo.update_ref('remotes/origin/main', 'abc1234def5678')
540
+ #
541
+ # @param branch [String] a local or remote-tracking branch name
542
+ #
543
+ # Short local names (e.g. `'main'`) resolve to `refs/heads/<branch>`.
544
+ # Remote-tracking names with a `remotes/<remote>/` or
545
+ # `refs/remotes/<remote>/` prefix (e.g. `'remotes/origin/main'`)
546
+ # resolve to `refs/remotes/<remote>/<name>`.
547
+ #
548
+ # @param commit [String] the commit SHA to point the branch at
549
+ #
550
+ # @return [Git::CommandLineResult] the result of calling `git update-ref`
551
+ #
552
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
553
+ #
554
+ def update_ref(branch, commit)
555
+ ref = Private.build_update_ref(branch)
556
+ Git::Commands::UpdateRef::Update.new(@execution_context).call(ref, commit)
557
+ end
558
+
559
+ # Returns a {Git::Branch} object for the given branch name
560
+ #
561
+ # @example Get a branch object for 'main'
562
+ # repo.branch('main') #=> #<Git::Branch 'main'>
563
+ #
564
+ # @example Get a branch object for the current branch
565
+ # repo.branch #=> #<Git::Branch 'main'>
566
+ #
567
+ # @param branch_name [String] the branch name (defaults to the current branch)
568
+ #
569
+ # @return [Git::Branch] the branch object
570
+ #
571
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
572
+ #
573
+ def branch(branch_name = current_branch)
574
+ branch_info = Git::BranchInfo.new(
575
+ refname: branch_name,
576
+ target_oid: nil,
577
+ current: false,
578
+ worktree: false,
579
+ symref: nil,
580
+ upstream: nil
581
+ )
582
+ Git::Branch.new(self, branch_info)
583
+ end
584
+
585
+ # Returns a {Git::Branches} collection of all branches in the repository
586
+ #
587
+ # @example List all branches
588
+ # repo.branches
589
+ # # => #<Git::Branches ...>
590
+ #
591
+ # @example Iterate over all branches
592
+ # repo.branches.each { |b| puts b.name }
593
+ #
594
+ # @example Access local branches only
595
+ # repo.branches.local
596
+ #
597
+ # @example Access remote-tracking branches only
598
+ # repo.branches.remote
599
+ #
600
+ # @example Look up a branch by name
601
+ # repo.branches['main'] # => #<Git::Branch 'main'>
602
+ #
603
+ # @return [Git::Branches] a collection wrapping all local and
604
+ # remote-tracking branches in the repository
605
+ #
606
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
607
+ #
608
+ def branches
609
+ Git::Branches.new(self)
610
+ end
611
+
612
+ # Private helpers local to {Git::Repository::Branching}
613
+ #
614
+ # @api private
615
+ module Private
616
+ module_function
617
+
618
+ # Determines whether the given branch ref points to an existing commit
619
+ #
620
+ # Returns `:active` when the branch ref resolves successfully. Returns
621
+ # `:unborn` when the branch ref exists but has no commits yet (exit
622
+ # status 1 with empty stderr from `git rev-parse --verify --quiet`).
623
+ # Re-raises for any other failure.
624
+ #
625
+ # @param execution_context [Git::ExecutionContext::Repository] the
626
+ # execution context for git commands
627
+ #
628
+ # @param branch_name [String] the branch name to verify
629
+ #
630
+ # @return [:active, :unborn] the branch ref state
631
+ #
632
+ # @raise [Git::FailedError] if git exits with a failure unrelated to an
633
+ # unborn branch
634
+ #
635
+ # @api private
636
+ #
637
+ def get_branch_state(execution_context, branch_name)
638
+ Git::Commands::RevParse.new(execution_context).call(branch_name, verify: true, quiet: true)
639
+ :active
640
+ rescue Git::FailedError => e
641
+ raise unless e.result.status.exitstatus == 1 && e.result.stderr.empty?
642
+
643
+ :unborn
644
+ end
645
+
646
+ # Translates legacy checkout options to the new command interface
647
+ #
648
+ # Legacy callers passed combinations like:
649
+ # checkout('branch', new_branch: true, start_point: 'main')
650
+ # which should map to:
651
+ # checkout('main', b: 'branch')
652
+ #
653
+ # @param branch [String, nil] the branch argument passed to {#checkout}
654
+ #
655
+ # @param options [Hash] the raw options passed to {#checkout}
656
+ #
657
+ # @return [Array] a two-element tuple `[target, options]` containing the
658
+ # translated checkout arguments
659
+ #
660
+ # `target` (`String` or `nil`) is the branch or commit to check out.
661
+ # `options` is a `Hash` of keyword arguments for
662
+ # `Git::Commands::Checkout::Branch#call`
663
+ #
664
+ # @api private
665
+ #
666
+ def translate_checkout_opts(branch, options)
667
+ if options[:new_branch] == true || options[:b] == true
668
+ [options[:start_point], options.except(:new_branch, :b, :start_point).merge(b: branch)]
669
+ elsif options[:new_branch].is_a?(String)
670
+ [branch, options.except(:new_branch).merge(b: options[:new_branch])]
671
+ else
672
+ [branch, options]
673
+ end
674
+ end
675
+
676
+ # Normalizes path specifications for Git commands
677
+ #
678
+ # @param pathspecs [String, Pathname, Array<String, Pathname>, nil]
679
+ # the path(s) to normalize
680
+ #
681
+ # @param arg_name [String] the argument name used in error messages
682
+ #
683
+ # @return [Array<String>, nil] the normalized paths, or `nil` if none are valid
684
+ #
685
+ # @raise [ArgumentError] when any path is not a `String` or `Pathname`
686
+ #
687
+ # @api private
688
+ #
689
+ def normalize_pathspecs(pathspecs, arg_name)
690
+ return nil unless pathspecs
691
+
692
+ normalized = Array(pathspecs)
693
+ validate_pathspec_types(normalized, arg_name)
694
+
695
+ normalized = normalized.map(&:to_s).reject(&:empty?)
696
+ return nil if normalized.empty?
697
+
698
+ normalized
699
+ end
700
+
701
+ # Raises an error if any element of `pathspecs` is not a `String` or `Pathname`
702
+ #
703
+ # @param pathspecs [Array] the path elements to validate
704
+ #
705
+ # @param arg_name [String] the argument name used in error messages
706
+ #
707
+ # @return [void]
708
+ #
709
+ # @raise [ArgumentError] when any element is not a `String` or `Pathname`
710
+ #
711
+ # @api private
712
+ #
713
+ def validate_pathspec_types(pathspecs, arg_name)
714
+ return if pathspecs.all? { |path| path.is_a?(String) || path.is_a?(Pathname) }
715
+
716
+ raise ArgumentError, "Invalid #{arg_name}: must be a String, Pathname, or Array of Strings/Pathnames"
717
+ end
718
+
719
+ # Builds the full git ref string from a branch name argument
720
+ #
721
+ # Mirrors the routing logic of `Git::Branch#update_ref` for backward
722
+ # compatibility:
723
+ #
724
+ # - `remotes/<remote>/<name>` or `refs/remotes/<remote>/<name>` →
725
+ # `refs/remotes/<remote>/<name>`
726
+ # - Any other value → `refs/heads/<branch>`
727
+ #
728
+ # @param branch [String] a short local branch name or a remote-tracking
729
+ # branch name with a `remotes/` or `refs/remotes/` prefix
730
+ #
731
+ # @return [String] the full git ref string
732
+ #
733
+ # @api private
734
+ #
735
+ def build_update_ref(branch)
736
+ match = branch.match(%r{\A(?:refs/)?remotes/([^/]+)/(.+)\z})
737
+ match ? "refs/remotes/#{match[1]}/#{match[2]}" : "refs/heads/#{branch}"
738
+ end
739
+ end
740
+ private_constant :Private
741
+ end
742
+ end
743
+ end