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,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/commands/commit'
4
+ require 'git/commands/commit_tree'
5
+ require 'git/commands/write_tree'
6
+ require 'git/repository/shared_private'
7
+
8
+ module Git
9
+ class Repository
10
+ # Facade methods for committing operations: recording commits, manipulating
11
+ # tree objects, and building commit objects outside the working tree
12
+ #
13
+ # Included by {Git::Repository}.
14
+ #
15
+ # @api public
16
+ #
17
+ module Committing
18
+ # Option keys accepted by {#commit}
19
+ COMMIT_ALLOWED_OPTS = %i[
20
+ all amend allow_empty allow_empty_message author date
21
+ gpg_sign no_gpg_sign no_verify
22
+ ].freeze
23
+ private_constant :COMMIT_ALLOWED_OPTS
24
+
25
+ # Option keys accepted by {#commit_tree}
26
+ COMMIT_TREE_ALLOWED_OPTS = %i[parent p parents message m].freeze
27
+ private_constant :COMMIT_TREE_ALLOWED_OPTS
28
+
29
+ # Record staged changes as a new commit
30
+ #
31
+ # @example Commit with a message
32
+ # repo.commit('Add README')
33
+ #
34
+ # @example Amend the previous commit, reusing its message
35
+ # repo.commit(nil, amend: true)
36
+ #
37
+ # @example Stage all modified files and commit
38
+ # repo.commit('Cleanup', all: true)
39
+ #
40
+ # @param message [String, nil] the commit message; pass `nil` to omit
41
+ # (e.g. when using `:amend` to reuse the previous message)
42
+ #
43
+ # @param opts [Hash] options for the commit command
44
+ #
45
+ # @option opts [Boolean, nil] :all (nil) automatically stage modified and
46
+ # deleted files before committing
47
+ #
48
+ # @option opts [Boolean, nil] :amend (nil) replace the tip of the current
49
+ # branch with a new commit
50
+ #
51
+ # @option opts [Boolean, nil] :allow_empty (nil) allow committing with no
52
+ # changes
53
+ #
54
+ # @option opts [Boolean, nil] :allow_empty_message (nil) allow committing
55
+ # with an empty message
56
+ #
57
+ # @option opts [String] :author (nil) override the commit author in
58
+ # `A U Thor <author@example.com>` format
59
+ #
60
+ # @option opts [String] :date (nil) override the author date
61
+ #
62
+ # @option opts [Boolean, nil] :gpg_sign (nil) GPG-sign the commit
63
+ #
64
+ # @option opts [Boolean, nil] :no_gpg_sign (nil) disable GPG signing
65
+ #
66
+ # @option opts [Boolean, nil] :no_verify (nil) bypass the pre-commit and
67
+ # commit-msg hooks
68
+ #
69
+ # @return [String] git's stdout from the commit
70
+ #
71
+ # @raise [ArgumentError] when unsupported options are provided
72
+ #
73
+ # @raise [Git::FailedError] when git exits with a non-zero exit status
74
+ #
75
+ def commit(message, opts = {})
76
+ opts = opts.dup
77
+ if opts.key?(:add_all)
78
+ Git::Deprecation.warn('The :add_all option for #commit is deprecated, use :all instead')
79
+ opts[:all] = opts.delete(:add_all)
80
+ end
81
+
82
+ SharedPrivate.assert_valid_opts!(COMMIT_ALLOWED_OPTS, **opts)
83
+
84
+ call_opts = { no_edit: true }
85
+ call_opts[:message] = message if message
86
+
87
+ Git::Commands::Commit.new(@execution_context).call(**call_opts, **opts).stdout
88
+ end
89
+
90
+ # Commit all modified tracked files without explicitly staging them first
91
+ #
92
+ # Equivalent to calling {#commit} with `all: true` merged into `opts`.
93
+ #
94
+ # @example Commit all changes with a message
95
+ # repo.commit_all('Update everything')
96
+ #
97
+ # @param message [String] the commit message
98
+ #
99
+ # @param opts [Hash] additional options forwarded to {#commit}
100
+ #
101
+ # @return [String] git's stdout from the commit
102
+ #
103
+ # @raise [ArgumentError] when unsupported options are provided
104
+ #
105
+ # @raise [Git::FailedError] when git exits with a non-zero exit status
106
+ #
107
+ def commit_all(message, opts = {})
108
+ commit(message, opts.merge(all: true))
109
+ end
110
+
111
+ # Create a commit object from a tree SHA without moving HEAD
112
+ #
113
+ # Unlike {#commit}, this does not read the index; it directly wraps
114
+ # `git commit-tree`.
115
+ #
116
+ # @example Commit a tree with a parent
117
+ # repo.commit_tree('deadbeef', message: 'snapshot', parent: 'HEAD')
118
+ #
119
+ # @param tree [String, nil] the tree SHA to commit; defaults to `nil`
120
+ #
121
+ # @param opts [Hash] options for the commit-tree command
122
+ #
123
+ # @option opts [String] :m (nil) the commit message (short form)
124
+ #
125
+ # @option opts [String] :message (nil) the commit message (normalized
126
+ # to `:m` before passing to the command)
127
+ #
128
+ # @option opts [String, Array<String>] :p (nil) parent commit SHA(s)
129
+ #
130
+ # @option opts [String] :parent (nil) a single parent commit SHA
131
+ # (normalized to `:p`)
132
+ #
133
+ # @option opts [Array<String>] :parents (nil) multiple parent commit
134
+ # SHAs (normalized to `:p`)
135
+ #
136
+ # @return [String] the SHA of the newly created commit object
137
+ #
138
+ # @raise [ArgumentError] when unsupported options are provided
139
+ #
140
+ # @raise [Git::FailedError] when git exits with a non-zero exit status
141
+ #
142
+ def commit_tree(tree = nil, opts = {}) # rubocop:disable Metrics/AbcSize
143
+ SharedPrivate.assert_valid_opts!(COMMIT_TREE_ALLOWED_OPTS, **opts)
144
+
145
+ opts = opts.dup
146
+ opts[:p] = opts.delete(:parents) if opts.key?(:parents)
147
+ opts[:p] = opts.delete(:parent) if opts.key?(:parent)
148
+ opts[:m] = opts.delete(:message) if opts.key?(:message)
149
+ opts[:m] = "commit tree #{tree}" unless opts[:m]
150
+
151
+ Git::Commands::CommitTree.new(@execution_context).call(tree, **opts).stdout
152
+ end
153
+
154
+ # Write the current index to a tree object in the object store
155
+ #
156
+ # @example Get the tree SHA of the current index
157
+ # tree_sha = repo.write_tree
158
+ #
159
+ # @return [String] the SHA of the tree object written
160
+ #
161
+ # @raise [Git::FailedError] when git exits with a non-zero exit status
162
+ #
163
+ def write_tree
164
+ Git::Commands::WriteTree.new(@execution_context).call.stdout
165
+ end
166
+
167
+ # Write the current index to a tree object and immediately commit it
168
+ #
169
+ # Combines {#write_tree} and {#commit_tree} in a single call.
170
+ #
171
+ # @example Commit the current index as a snapshot
172
+ # commit_sha = repo.write_and_commit_tree(message: 'snapshot')
173
+ #
174
+ # @param opts [Hash] options forwarded to {#commit_tree}
175
+ #
176
+ # @return [String] the SHA of the newly created commit object
177
+ #
178
+ # @raise [ArgumentError] when unsupported options are provided
179
+ #
180
+ # @raise [Git::FailedError] when git exits with a non-zero exit status
181
+ #
182
+ def write_and_commit_tree(opts = {})
183
+ commit_tree(write_tree, opts)
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,351 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/commands/config_option_syntax'
4
+ require 'git/repository/shared_private'
5
+
6
+ module Git
7
+ class Repository
8
+ # Legacy facade methods for reading and writing git configuration
9
+ #
10
+ # Provides the {#config} and {#global_config} dispatch methods for 4.x
11
+ # compatibility. These methods return raw `String` / `Hash` values instead of
12
+ # {Git::ConfigEntryInfo} objects and are retained so that internal callers such
13
+ # as `Git::Status` continue to work unchanged.
14
+ #
15
+ # The structured `config_*` methods (e.g. `config_get`, `config_list`) are
16
+ # provided by {Git::Configuring}, which is included directly into
17
+ # {Git::Repository}.
18
+ #
19
+ # Included by {Git::Repository}.
20
+ #
21
+ # @api public
22
+ #
23
+ module Configuring
24
+ # Option keys accepted by {#config} when writing a value
25
+ CONFIG_SET_ALLOWED_OPTS = %i[file].freeze
26
+ private_constant :CONFIG_SET_ALLOWED_OPTS
27
+
28
+ # Option keys accepted by {#config} when reading a single value or listing
29
+ CONFIG_READ_ALLOWED_OPTS = %i[file].freeze
30
+ private_constant :CONFIG_READ_ALLOWED_OPTS
31
+
32
+ # Read or write a git configuration entry
33
+ #
34
+ # Dispatches to one of three modes depending on the arguments supplied:
35
+ #
36
+ # * **List** — `config()` returns all visible config entries as a `Hash`.
37
+ # * **Get** — `config(name)` returns the value for a single key as a `String`.
38
+ # * **Set** — `config(name, value)` writes a value and returns the raw
39
+ # command result.
40
+ #
41
+ # @overload config(options = {})
42
+ #
43
+ # @example List all config entries
44
+ # repo.config #=> { "user.name" => "Alice", "core.bare" => "false" }
45
+ #
46
+ # @example List all entries from a custom config file
47
+ # repo.config(file: '/path/to/.gitconfig')
48
+ # #=> { "user.name" => "Alice", "core.bare" => "false" }
49
+ #
50
+ # @param options [Hash] options for the list operation
51
+ #
52
+ # @option options [String, nil] :file (nil) path to a custom config file
53
+ # to read from instead of the default resolution chain
54
+ #
55
+ # @return [Hash{String => String}] all visible config entries, keyed by
56
+ # their full dotted key names (e.g. `"user.name"`)
57
+ #
58
+ # @raise [ArgumentError] if unsupported options are provided
59
+ #
60
+ # @overload config(name, options = {})
61
+ #
62
+ # @example Read the committer name from config
63
+ # repo.config('user.name') #=> "Alice"
64
+ #
65
+ # @example Read a value from a custom config file
66
+ # repo.config('user.name', file: '/path/to/.gitconfig') #=> "Alice"
67
+ #
68
+ # @param name [String] the dotted config key to look up (e.g.
69
+ # `"user.name"`)
70
+ #
71
+ # @param options [Hash] options for the get operation
72
+ #
73
+ # @option options [String, nil] :file (nil) path to a custom config file
74
+ # to read from instead of the default resolution chain
75
+ #
76
+ # @return [String] the value of the config entry
77
+ #
78
+ # @raise [ArgumentError] if unsupported options are provided
79
+ #
80
+ # @overload config(name, value, options = {})
81
+ #
82
+ # @example Set the committer name in local config
83
+ # repo.config('user.name', 'Alice')
84
+ #
85
+ # @example Write a value to a custom config file
86
+ # repo.config('user.name', 'Alice', file: '/path/to/custom/config')
87
+ #
88
+ # @param name [String] the dotted config key to write (e.g.
89
+ # `"user.name"`)
90
+ #
91
+ # @param value [#to_s] the value to assign; must not be `nil` (a `nil`
92
+ # value is treated as "no value" and routes to the get overload).
93
+ # Must not be a `Hash` (a Hash is treated as the `options` argument;
94
+ # call `value.to_s` explicitly before passing if a stringified Hash
95
+ # is genuinely needed). Any other non-nil object is converted to a
96
+ # String via `#to_s` before being passed to git
97
+ #
98
+ # @param options [Hash] options for the set operation
99
+ #
100
+ # @option options [String, nil] :file (nil) path to a custom config file
101
+ # to write to instead of the repository's default `.git/config`
102
+ #
103
+ # @return [Git::CommandLineResult] the raw result of
104
+ # `git config <name> <value>`
105
+ #
106
+ # @raise [ArgumentError] if unsupported options are provided
107
+ #
108
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
109
+ #
110
+ def config(name = nil, value = nil, options = {})
111
+ name, value, options = Private.normalize_config_args(name, value, options)
112
+
113
+ if !name.nil? && !value.nil?
114
+ Private.config_set(@execution_context, name, value, **options)
115
+ elsif name
116
+ Private.config_get(@execution_context, name, **options)
117
+ else
118
+ Private.config_list(@execution_context, **options)
119
+ end
120
+ end
121
+
122
+ # Read or write a global git configuration entry
123
+ #
124
+ # Dispatches to one of three modes depending on the arguments supplied,
125
+ # targeting the git global config scope (`git config --global`):
126
+ #
127
+ # * **List** — `global_config()` returns all global config entries as a `Hash`.
128
+ # * **Get** — `global_config(name)` returns the value for a single key as a `String`.
129
+ # * **Set** — `global_config(name, value)` writes a value and returns the raw
130
+ # command result.
131
+ #
132
+ # @overload global_config
133
+ #
134
+ # @example List all global config entries
135
+ # repo.global_config #=> { "user.name" => "Alice", "core.autocrlf" => "false" }
136
+ #
137
+ # @return [Hash{String => String}] all global config entries, keyed by their
138
+ # full dotted key names (e.g. `"user.name"`)
139
+ #
140
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
141
+ #
142
+ # @overload global_config(name)
143
+ #
144
+ # @example Read the global committer name
145
+ # repo.global_config('user.name') #=> "Alice"
146
+ #
147
+ # @param name [String] the dotted config key to look up (e.g. `"user.name"`)
148
+ #
149
+ # @return [String] the value of the global config entry
150
+ #
151
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
152
+ #
153
+ # @overload global_config(name, value)
154
+ #
155
+ # @example Set the global committer name
156
+ # repo.global_config('user.name', 'Alice')
157
+ #
158
+ # @param name [String] the dotted config key to write (e.g. `"user.name"`)
159
+ #
160
+ # @param value [#to_s] the value to assign; any object is accepted and
161
+ # converted to a String via `#to_s` before being passed to git
162
+ #
163
+ # @return [Git::CommandLineResult] the raw result of
164
+ # `git config --global <name> <value>`
165
+ #
166
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
167
+ #
168
+ def global_config(name = nil, value = nil)
169
+ if !name.nil? && !value.nil?
170
+ Private.global_config_set(@execution_context, name, value)
171
+ elsif !name.nil?
172
+ Private.global_config_get(@execution_context, name)
173
+ else
174
+ Private.global_config_list(@execution_context)
175
+ end
176
+ end
177
+
178
+ # Private helpers local to {Git::Repository::Configuring}
179
+ #
180
+ # @api private
181
+ #
182
+ module Private
183
+ module_function
184
+
185
+ # Normalize `config()` positional arguments
186
+ #
187
+ # In Ruby 3.x, calling `config(file: '/path')` passes the hash as the
188
+ # first positional argument. This helper re-maps those patterns so that
189
+ # `name`, `value`, and `options` are always in their canonical positions.
190
+ #
191
+ # Raises `ArgumentError` for call shapes that are ambiguous or clearly
192
+ # wrong, such as passing extra positional arguments after an options Hash.
193
+ #
194
+ # @param name [String, Hash, nil] the raw first argument to {#config}
195
+ #
196
+ # @param value [Object, Hash, nil] the raw second argument to {#config}
197
+ #
198
+ # @param options [Hash] the raw third argument to {#config}
199
+ #
200
+ # @return [Array(String|nil, Object|nil, Hash)] normalized [name, value, options]
201
+ #
202
+ # @raise [ArgumentError] if extra positional arguments follow an options Hash
203
+ #
204
+ def normalize_config_args(name, value, options)
205
+ if name.is_a?(Hash)
206
+ raise ArgumentError, 'unexpected positional arguments after options hash' if !value.nil? || !options.empty?
207
+
208
+ [nil, nil, name]
209
+ elsif value.is_a?(Hash)
210
+ raise ArgumentError, 'unexpected third argument when second argument is options hash' unless options.empty?
211
+
212
+ [name, nil, value]
213
+ else
214
+ [name, value, options]
215
+ end
216
+ end
217
+
218
+ # Set a config value by key name
219
+ #
220
+ # @overload config_set(execution_context, name, value, **options)
221
+ #
222
+ # @param execution_context [Git::ExecutionContext] the execution context
223
+ #
224
+ # @param name [String] the dotted config key to write (e.g. `"user.name"`)
225
+ #
226
+ # @param value [String] the value to assign
227
+ #
228
+ # @param options [Hash] keyword options forwarded to the command
229
+ #
230
+ # @option options [String, nil] :file (nil) path to a custom config file
231
+ # to write to instead of the repository's default `.git/config`
232
+ #
233
+ # @return [Git::CommandLineResult] the raw result of
234
+ # `git config <name> <value>`
235
+ #
236
+ # @raise [ArgumentError] if unsupported options are provided
237
+ #
238
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
239
+ #
240
+ def config_set(execution_context, name, value, **)
241
+ SharedPrivate.assert_valid_opts!(CONFIG_SET_ALLOWED_OPTS, **)
242
+ Git::Commands::ConfigOptionSyntax::Set.new(execution_context).call(name, value, **)
243
+ end
244
+
245
+ # Retrieve a config value by key name
246
+ #
247
+ # @param execution_context [Git::ExecutionContext] the execution context
248
+ #
249
+ # @param name [String] the dotted config key to look up (e.g. `"user.name"`)
250
+ #
251
+ # @param options [Hash] keyword options
252
+ #
253
+ # @option options [String, nil] :file (nil) path to a custom config file to read from
254
+ #
255
+ # @return [String] the value of the config entry
256
+ #
257
+ # @raise [ArgumentError] if unsupported options are provided
258
+ #
259
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
260
+ #
261
+ def config_get(execution_context, name, **options)
262
+ SharedPrivate.assert_valid_opts!(CONFIG_READ_ALLOWED_OPTS, **options)
263
+ opts = options[:file] ? { file: options[:file] } : {}
264
+ result = Git::Commands::ConfigOptionSyntax::Get.new(execution_context).call(name, **opts)
265
+ raise Git::FailedError, result if result.status.exitstatus != 0
266
+
267
+ result.stdout
268
+ end
269
+
270
+ # Retrieve all config entries as a hash
271
+ #
272
+ # @param execution_context [Git::ExecutionContext] the execution context
273
+ #
274
+ # @param options [Hash] keyword options
275
+ #
276
+ # @option options [String, nil] :file (nil) path to a custom config file to read from
277
+ #
278
+ # @return [Hash{String => String}] all config entries, keyed by their full
279
+ # dotted key names (e.g. `"user.name"`)
280
+ #
281
+ # @raise [ArgumentError] if unsupported options are provided
282
+ #
283
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
284
+ #
285
+ def config_list(execution_context, **options)
286
+ SharedPrivate.assert_valid_opts!(CONFIG_READ_ALLOWED_OPTS, **options)
287
+ opts = options[:file] ? { file: options[:file] } : {}
288
+ lines = Git::Commands::ConfigOptionSyntax::List.new(execution_context).call(**opts).stdout.split("\n")
289
+ lines.each_with_object({}) do |line, hsh|
290
+ key, value = line.split('=', 2)
291
+ hsh[key] = value || ''
292
+ end
293
+ end
294
+
295
+ # Retrieve a global config value by key name
296
+ #
297
+ # @param execution_context [Git::ExecutionContext] the execution context
298
+ #
299
+ # @param name [String] the dotted config key to look up (e.g. `"user.name"`)
300
+ #
301
+ # @return [String] the value of the global config entry
302
+ #
303
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
304
+ #
305
+ def global_config_get(execution_context, name)
306
+ result = Git::Commands::ConfigOptionSyntax::Get.new(execution_context).call(name, global: true)
307
+ raise Git::FailedError, result if result.status.exitstatus != 0
308
+
309
+ result.stdout
310
+ end
311
+
312
+ # Retrieve all global config entries as a hash
313
+ #
314
+ # @param execution_context [Git::ExecutionContext] the execution context
315
+ #
316
+ # @return [Hash{String => String}] all global config entries, keyed by their full
317
+ # dotted key names (e.g. `"user.name"`)
318
+ #
319
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
320
+ #
321
+ def global_config_list(execution_context)
322
+ lines = Git::Commands::ConfigOptionSyntax::List.new(execution_context).call(global: true).stdout.split("\n")
323
+ lines.each_with_object({}) do |line, hsh|
324
+ key, value = line.split('=', 2)
325
+ hsh[key] = value || ''
326
+ end
327
+ end
328
+
329
+ # Set a global config value by key name
330
+ #
331
+ # @param execution_context [Git::ExecutionContext] the execution context
332
+ #
333
+ # @param name [String] the dotted config key to write (e.g. `"user.name"`)
334
+ #
335
+ # @param value [#to_s] the value to assign; any object is accepted and
336
+ # converted to a String via `#to_s` before being passed to git
337
+ #
338
+ # @return [Git::CommandLineResult] the raw result of
339
+ # `git config --global <name> <value>`
340
+ #
341
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
342
+ #
343
+ def global_config_set(execution_context, name, value)
344
+ Git::Commands::ConfigOptionSyntax::Set.new(execution_context).call(name, value, global: true)
345
+ end
346
+ end
347
+
348
+ private_constant :Private
349
+ end
350
+ end
351
+ end