git 5.0.0.beta.2 → 5.0.0.beta.4

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +27 -0
  3. data/.github/copilot-instructions.md +3 -8
  4. data/.github/hooks/bin-setup-on-worktree.json +11 -0
  5. data/.github/hooks/run-bin-setup-once.sh +14 -0
  6. data/.github/skills/breaking-change-analysis/SKILL.md +6 -9
  7. data/.github/skills/ci-cd-troubleshooting/SKILL.md +2 -2
  8. data/.github/skills/command-implementation/REFERENCE.md +34 -33
  9. data/.github/skills/command-implementation/SKILL.md +5 -4
  10. data/.github/skills/command-test-conventions/SKILL.md +13 -9
  11. data/.github/skills/command-yard-documentation/SKILL.md +14 -6
  12. data/.github/skills/development-workflow/SKILL.md +20 -14
  13. data/.github/skills/facade-implementation/REFERENCE.md +19 -22
  14. data/.github/skills/facade-implementation/SKILL.md +0 -5
  15. data/.github/skills/facade-test-conventions/SKILL.md +4 -7
  16. data/.github/skills/facade-yard-documentation/SKILL.md +8 -2
  17. data/.github/skills/make-skill-template/SKILL.md +53 -3
  18. data/.github/skills/pr-readiness-review/SKILL.md +22 -2
  19. data/.github/skills/project-context/SKILL.md +16 -23
  20. data/.github/skills/pull-request-review/SKILL.md +2 -2
  21. data/.github/skills/rebase/SKILL.md +148 -0
  22. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +1 -1
  23. data/.github/skills/resolve-feedback/SKILL.md +288 -0
  24. data/.github/skills/review-arguments-dsl/CHECKLIST.md +3 -3
  25. data/.github/skills/reviewing-skills/SKILL.md +28 -3
  26. data/.github/skills/test-debugging/SKILL.md +20 -19
  27. data/.github/skills/yard-documentation/SKILL.md +671 -483
  28. data/.github/skills/yard-documentation/element-rules.md +162 -0
  29. data/.github/skills-deprecated/README.md +21 -0
  30. data/.github/{skills → skills-deprecated}/extract-command-from-lib/SKILL.md +9 -9
  31. data/.github/{skills → skills-deprecated}/extract-facade-from-base-lib/SKILL.md +12 -12
  32. data/.github/workflows/continuous_integration.yml +3 -2
  33. data/.rubocop.yml +7 -39
  34. data/.yard-lint.yml +75 -0
  35. data/CONTRIBUTING.md +186 -174
  36. data/Gemfile +17 -0
  37. data/README.md +86 -23
  38. data/Rakefile +3 -21
  39. data/UPGRADING.md +219 -70
  40. data/docker/test/Dockerfile +32 -0
  41. data/docker/test/docker-compose.yml +0 -0
  42. data/git.gemspec +3 -4
  43. data/lib/git/author.rb +20 -1
  44. data/lib/git/branch.rb +26 -6
  45. data/lib/git/branch_delete_failure.rb +3 -0
  46. data/lib/git/branch_delete_result.rb +6 -3
  47. data/lib/git/branch_info.rb +6 -6
  48. data/lib/git/command_line/base.rb +6 -13
  49. data/lib/git/command_line/capturing.rb +67 -10
  50. data/lib/git/command_line/result.rb +0 -8
  51. data/lib/git/command_line/streaming.rb +45 -5
  52. data/lib/git/command_line.rb +4 -3
  53. data/lib/git/commands/add.rb +61 -53
  54. data/lib/git/commands/am/abort.rb +2 -2
  55. data/lib/git/commands/am/apply.rb +109 -98
  56. data/lib/git/commands/am/continue.rb +2 -2
  57. data/lib/git/commands/am/quit.rb +2 -2
  58. data/lib/git/commands/am/retry.rb +4 -2
  59. data/lib/git/commands/am/show_current_patch.rb +1 -1
  60. data/lib/git/commands/am/skip.rb +2 -2
  61. data/lib/git/commands/am.rb +2 -2
  62. data/lib/git/commands/apply.rb +7 -2
  63. data/lib/git/commands/archive/list_formats.rb +3 -3
  64. data/lib/git/commands/archive.rb +7 -2
  65. data/lib/git/commands/arguments.rb +1370 -359
  66. data/lib/git/commands/base.rb +111 -13
  67. data/lib/git/commands/branch/copy.rb +29 -21
  68. data/lib/git/commands/branch/create.rb +72 -68
  69. data/lib/git/commands/branch/delete.rb +25 -17
  70. data/lib/git/commands/branch/list.rb +76 -60
  71. data/lib/git/commands/branch/move.rb +29 -21
  72. data/lib/git/commands/branch/set_upstream.rb +8 -8
  73. data/lib/git/commands/branch/show_current.rb +3 -3
  74. data/lib/git/commands/branch/unset_upstream.rb +4 -8
  75. data/lib/git/commands/branch.rb +2 -2
  76. data/lib/git/commands/cat_file/batch.rb +36 -20
  77. data/lib/git/commands/cat_file/filtered.rb +12 -12
  78. data/lib/git/commands/cat_file/raw.rb +13 -13
  79. data/lib/git/commands/cat_file.rb +4 -4
  80. data/lib/git/commands/checkout/branch.rb +7 -5
  81. data/lib/git/commands/checkout/files.rb +5 -4
  82. data/lib/git/commands/checkout.rb +4 -4
  83. data/lib/git/commands/checkout_index.rb +5 -4
  84. data/lib/git/commands/clean.rb +6 -4
  85. data/lib/git/commands/clone.rb +5 -4
  86. data/lib/git/commands/commit.rb +5 -4
  87. data/lib/git/commands/commit_tree.rb +5 -4
  88. data/lib/git/commands/config_option_syntax/add.rb +7 -4
  89. data/lib/git/commands/config_option_syntax/get.rb +9 -5
  90. data/lib/git/commands/config_option_syntax/get_all.rb +7 -4
  91. data/lib/git/commands/config_option_syntax/get_color.rb +8 -4
  92. data/lib/git/commands/config_option_syntax/get_color_bool.rb +7 -4
  93. data/lib/git/commands/config_option_syntax/get_regexp.rb +8 -4
  94. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +8 -4
  95. data/lib/git/commands/config_option_syntax/list.rb +8 -4
  96. data/lib/git/commands/config_option_syntax/remove_section.rb +7 -2
  97. data/lib/git/commands/config_option_syntax/rename_section.rb +7 -2
  98. data/lib/git/commands/config_option_syntax/replace_all.rb +7 -2
  99. data/lib/git/commands/config_option_syntax/set.rb +7 -2
  100. data/lib/git/commands/config_option_syntax/unset.rb +7 -4
  101. data/lib/git/commands/config_option_syntax/unset_all.rb +7 -2
  102. data/lib/git/commands/describe.rb +5 -4
  103. data/lib/git/commands/diff.rb +13 -12
  104. data/lib/git/commands/diff_files.rb +7 -6
  105. data/lib/git/commands/diff_index.rb +10 -7
  106. data/lib/git/commands/fetch.rb +6 -4
  107. data/lib/git/commands/fsck.rb +6 -4
  108. data/lib/git/commands/gc.rb +6 -4
  109. data/lib/git/commands/grep.rb +6 -5
  110. data/lib/git/commands/init.rb +6 -4
  111. data/lib/git/commands/log.rb +287 -285
  112. data/lib/git/commands/ls_files.rb +69 -65
  113. data/lib/git/commands/ls_remote.rb +62 -56
  114. data/lib/git/commands/ls_tree.rb +50 -46
  115. data/lib/git/commands/maintenance/register.rb +25 -23
  116. data/lib/git/commands/maintenance/run.rb +7 -2
  117. data/lib/git/commands/maintenance/start.rb +7 -2
  118. data/lib/git/commands/maintenance/stop.rb +7 -2
  119. data/lib/git/commands/maintenance/unregister.rb +7 -2
  120. data/lib/git/commands/merge/abort.rb +2 -2
  121. data/lib/git/commands/merge/continue.rb +2 -2
  122. data/lib/git/commands/merge/quit.rb +2 -2
  123. data/lib/git/commands/merge/start.rb +7 -2
  124. data/lib/git/commands/merge.rb +2 -2
  125. data/lib/git/commands/merge_base.rb +7 -2
  126. data/lib/git/commands/mv.rb +7 -2
  127. data/lib/git/commands/name_rev.rb +7 -2
  128. data/lib/git/commands/pull.rb +7 -2
  129. data/lib/git/commands/push.rb +7 -2
  130. data/lib/git/commands/read_tree.rb +7 -2
  131. data/lib/git/commands/remote/add.rb +7 -2
  132. data/lib/git/commands/remote/get_url.rb +4 -2
  133. data/lib/git/commands/remote/list.rb +4 -2
  134. data/lib/git/commands/remote/prune.rb +4 -2
  135. data/lib/git/commands/remote/remove.rb +4 -2
  136. data/lib/git/commands/remote/rename.rb +4 -2
  137. data/lib/git/commands/remote/set_branches.rb +9 -2
  138. data/lib/git/commands/remote/set_head.rb +12 -5
  139. data/lib/git/commands/remote/set_url.rb +9 -2
  140. data/lib/git/commands/remote/set_url_add.rb +11 -2
  141. data/lib/git/commands/remote/set_url_delete.rb +9 -2
  142. data/lib/git/commands/remote/show.rb +18 -12
  143. data/lib/git/commands/remote/update.rb +19 -12
  144. data/lib/git/commands/remote.rb +2 -2
  145. data/lib/git/commands/repack.rb +67 -63
  146. data/lib/git/commands/reset.rb +51 -44
  147. data/lib/git/commands/rev_parse.rb +135 -128
  148. data/lib/git/commands/revert/abort.rb +2 -2
  149. data/lib/git/commands/revert/continue.rb +7 -2
  150. data/lib/git/commands/revert/quit.rb +2 -2
  151. data/lib/git/commands/revert/skip.rb +2 -2
  152. data/lib/git/commands/revert/start.rb +7 -2
  153. data/lib/git/commands/revert.rb +2 -2
  154. data/lib/git/commands/rm.rb +35 -36
  155. data/lib/git/commands/show.rb +1 -1
  156. data/lib/git/commands/show_ref/exclude_existing.rb +3 -4
  157. data/lib/git/commands/show_ref/exists.rb +15 -13
  158. data/lib/git/commands/show_ref/list.rb +39 -35
  159. data/lib/git/commands/show_ref/verify.rb +29 -27
  160. data/lib/git/commands/show_ref.rb +4 -4
  161. data/lib/git/commands/stash/apply.rb +31 -25
  162. data/lib/git/commands/stash/branch.rb +10 -8
  163. data/lib/git/commands/stash/clear.rb +7 -5
  164. data/lib/git/commands/stash/create.rb +10 -8
  165. data/lib/git/commands/stash/drop.rb +15 -9
  166. data/lib/git/commands/stash/list.rb +9 -5
  167. data/lib/git/commands/stash/pop.rb +21 -12
  168. data/lib/git/commands/stash/push.rb +20 -11
  169. data/lib/git/commands/stash/show.rb +21 -12
  170. data/lib/git/commands/stash/store.rb +19 -10
  171. data/lib/git/commands/stash.rb +2 -2
  172. data/lib/git/commands/status.rb +7 -2
  173. data/lib/git/commands/symbolic_ref/delete.rb +18 -14
  174. data/lib/git/commands/symbolic_ref/read.rb +24 -20
  175. data/lib/git/commands/symbolic_ref/update.rb +20 -17
  176. data/lib/git/commands/symbolic_ref.rb +4 -4
  177. data/lib/git/commands/tag/create.rb +45 -42
  178. data/lib/git/commands/tag/delete.rb +5 -3
  179. data/lib/git/commands/tag/list.rb +47 -44
  180. data/lib/git/commands/tag/verify.rb +12 -12
  181. data/lib/git/commands/tag.rb +2 -2
  182. data/lib/git/commands/update_ref/batch.rb +6 -1
  183. data/lib/git/commands/update_ref/delete.rb +19 -21
  184. data/lib/git/commands/update_ref/update.rb +22 -25
  185. data/lib/git/commands/update_ref.rb +4 -4
  186. data/lib/git/commands/version.rb +14 -11
  187. data/lib/git/commands/worktree/add.rb +50 -51
  188. data/lib/git/commands/worktree/list.rb +17 -17
  189. data/lib/git/commands/worktree/lock.rb +12 -12
  190. data/lib/git/commands/worktree/move.rb +16 -16
  191. data/lib/git/commands/worktree/prune.rb +2 -2
  192. data/lib/git/commands/worktree/remove.rb +2 -2
  193. data/lib/git/commands/worktree/repair.rb +2 -2
  194. data/lib/git/commands/worktree/unlock.rb +2 -2
  195. data/lib/git/commands/write_tree.rb +2 -2
  196. data/lib/git/commands.rb +4 -3
  197. data/lib/git/config.rb +47 -1
  198. data/lib/git/configuring.rb +89 -15
  199. data/lib/git/detached_head_info.rb +4 -1
  200. data/lib/git/diff.rb +2 -5
  201. data/lib/git/diff_file_numstat_info.rb +3 -1
  202. data/lib/git/diff_file_patch_info.rb +3 -1
  203. data/lib/git/diff_file_raw_info.rb +3 -1
  204. data/lib/git/diff_info.rb +8 -15
  205. data/lib/git/diff_path_status.rb +16 -3
  206. data/lib/git/diff_result.rb +3 -1
  207. data/lib/git/diff_stats.rb +15 -0
  208. data/lib/git/dirstat_info.rb +24 -8
  209. data/lib/git/encoding_utils.rb +32 -1
  210. data/lib/git/errors.rb +19 -9
  211. data/lib/git/escaped_path.rb +55 -3
  212. data/lib/git/execution_context/repository.rb +15 -0
  213. data/lib/git/execution_context.rb +76 -74
  214. data/lib/git/file_ref.rb +6 -3
  215. data/lib/git/fsck_object.rb +8 -0
  216. data/lib/git/fsck_result.rb +26 -15
  217. data/lib/git/log.rb +152 -5
  218. data/lib/git/object.rb +284 -8
  219. data/lib/git/parsers/branch.rb +18 -0
  220. data/lib/git/parsers/cat_file.rb +2 -2
  221. data/lib/git/parsers/diff.rb +213 -5
  222. data/lib/git/parsers/fsck.rb +11 -0
  223. data/lib/git/parsers/ls_remote.rb +1 -1
  224. data/lib/git/parsers/stash.rb +51 -0
  225. data/lib/git/parsers/tag.rb +38 -0
  226. data/lib/git/remote.rb +34 -2
  227. data/lib/git/repository/branching.rb +23 -21
  228. data/lib/git/repository/committing.rb +46 -6
  229. data/lib/git/repository/context_helpers.rb +45 -16
  230. data/lib/git/repository/diffing.rb +32 -23
  231. data/lib/git/repository/factories.rb +153 -28
  232. data/lib/git/repository/inspecting.rb +1 -1
  233. data/lib/git/repository/logging.rb +169 -30
  234. data/lib/git/repository/maintenance.rb +1 -1
  235. data/lib/git/repository/merging.rb +3 -3
  236. data/lib/git/repository/object_operations.rb +108 -14
  237. data/lib/git/repository/remote_operations.rb +150 -171
  238. data/lib/git/repository/shared_private.rb +7 -5
  239. data/lib/git/repository/staging.rb +36 -12
  240. data/lib/git/repository/stashing.rb +16 -16
  241. data/lib/git/repository/status_operations.rb +1 -1
  242. data/lib/git/repository/worktree_operations.rb +1 -1
  243. data/lib/git/repository.rb +287 -6
  244. data/lib/git/stash.rb +16 -21
  245. data/lib/git/stash_info.rb +4 -4
  246. data/lib/git/stashes.rb +20 -26
  247. data/lib/git/status.rb +25 -13
  248. data/lib/git/tag_delete_failure.rb +3 -0
  249. data/lib/git/tag_delete_result.rb +6 -3
  250. data/lib/git/tag_info.rb +1 -0
  251. data/lib/git/url.rb +12 -5
  252. data/lib/git/version.rb +6 -4
  253. data/lib/git/version_constraint.rb +4 -0
  254. data/lib/git.rb +400 -314
  255. data/redesign/3_architecture_implementation.md +81 -30
  256. data/redesign/Phase 4 - Step A.md +6 -0
  257. data/redesign/Phase 4 - Step B.md +921 -0
  258. data/redesign/Phase 4 - Step C.md +833 -0
  259. data/redesign/c1a-public-api-scope.tsv +256 -0
  260. data/redesign/phase-4-step-b-test-audit.tsv +485 -0
  261. data/tasks/yard.rake +24 -17
  262. metadata +24 -58
  263. data/commitlint.test +0 -4
  264. data/lib/git/args_builder.rb +0 -103
  265. data/lib/git/command_line_result.rb +0 -8
  266. data/lib/git/deprecation.rb +0 -9
  267. data/lib/git/repository/configuring.rb +0 -351
  268. data/tasks/test.rake +0 -25
  269. /data/.github/{skills → skills-deprecated}/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -0
  270. /data/.github/{skills → skills-deprecated}/review-backward-compatibility/SKILL.md +0 -0
@@ -9,7 +9,7 @@ module Git
9
9
  #
10
10
  # Included by {Git::Repository}.
11
11
  #
12
- # @api public
12
+ # @api private
13
13
  #
14
14
  module Stashing
15
15
  # Returns all stash entries as an array of index and message pairs
@@ -19,13 +19,6 @@ module Git
19
19
  # message is the stash description with the leading branch prefix (e.g.
20
20
  # `"On main:"` or `"WIP on main:"`) stripped.
21
21
  #
22
- # @note The sequential index returned here is **not** the same as git's
23
- # `stash@{N}` reference used by {#stash_apply}. In git, `stash@{0}` is the
24
- # **most recent** stash, while index `0` here is the **oldest**. To apply a
25
- # specific stash from this list, convert the entry's position to a git
26
- # reference: `'stash@{%d}' % (total - 1 - index)`, or pass the string
27
- # reference directly to {#stash_apply}.
28
- #
29
22
  # @example List all stashes (oldest first)
30
23
  # repo.stashes_all #=> [[0, "Fix bug"], [1, "Add feature"]]
31
24
  #
@@ -35,6 +28,13 @@ module Git
35
28
  #
36
29
  # @raise [Git::FailedError] if git exits with a non-zero exit status
37
30
  #
31
+ # @note The sequential index returned here is **not** the same as git's
32
+ # `stash@{N}` reference used by {#stash_apply}. In git, `stash@{0}` is the
33
+ # **most recent** stash, while index `0` here is the **oldest**. To apply a
34
+ # specific stash from this list, convert the entry's position to a git
35
+ # reference: `'stash@{%d}' % (total - 1 - index)`, or pass the string
36
+ # reference directly to {#stash_apply}.
37
+ #
38
38
  # @see https://git-scm.com/docs/git-stash git-stash documentation
39
39
  #
40
40
  def stashes_all
@@ -48,8 +48,6 @@ module Git
48
48
 
49
49
  # Returns stash entries as a formatted string matching `git stash list` output
50
50
  #
51
- # @deprecated Use {#stashes_all} instead.
52
- #
53
51
  # @example List stashes as a formatted string
54
52
  # repo.stash_list #=> "stash@{0}: On main: WIP\nstash@{1}: On feature: Fix bug"
55
53
  #
@@ -59,6 +57,8 @@ module Git
59
57
  #
60
58
  # @raise [Git::FailedError] if git exits with a non-zero exit status
61
59
  #
60
+ # @deprecated Use {#stashes_all} instead
61
+ #
62
62
  # @see #stashes_all
63
63
  #
64
64
  # @see https://git-scm.com/docs/git-stash git-stash documentation
@@ -75,6 +75,9 @@ module Git
75
75
 
76
76
  # Save the current working directory and index state to a new stash
77
77
  #
78
+ # @example Save current changes
79
+ # repo.stash_save('WIP: feature work')
80
+ #
78
81
  # @param message [String] the stash message
79
82
  #
80
83
  # @return [Boolean] true if changes were stashed, false if there were no
@@ -82,9 +85,6 @@ module Git
82
85
  #
83
86
  # @raise [Git::FailedError] if git exits with a non-zero exit status
84
87
  #
85
- # @example Save current changes
86
- # repo.stash_save('WIP: feature work')
87
- #
88
88
  # @see https://git-scm.com/docs/git-stash git-stash documentation
89
89
  #
90
90
  def stash_save(message) # rubocop:disable Naming/PredicateMethod
@@ -125,14 +125,14 @@ module Git
125
125
  # Removes all entries from the stash list. Use with caution as this
126
126
  # operation cannot be undone.
127
127
  #
128
+ # @example Clear all stashes
129
+ # repo.stash_clear #=> ""
130
+ #
128
131
  # @return [String] the output from the git stash clear command
129
132
  # (typically empty)
130
133
  #
131
134
  # @raise [Git::FailedError] if git exits with a non-zero exit status
132
135
  #
133
- # @example Clear all stashes
134
- # repo.stash_clear #=> ""
135
- #
136
136
  # @see https://git-scm.com/docs/git-stash git-stash documentation
137
137
  #
138
138
  def stash_clear
@@ -15,7 +15,7 @@ module Git
15
15
  #
16
16
  # Included by {Git::Repository}.
17
17
  #
18
- # @api public
18
+ # @api private
19
19
  #
20
20
  module StatusOperations
21
21
  # Returns `true` if the repository has no commits yet
@@ -10,7 +10,7 @@ module Git
10
10
  #
11
11
  # Included by {Git::Repository}.
12
12
  #
13
- # @api public
13
+ # @api private
14
14
  #
15
15
  module WorktreeOperations
16
16
  # Returns all worktrees as an array of directory and SHA pairs
@@ -4,12 +4,10 @@ require 'find'
4
4
  require 'pathname'
5
5
 
6
6
  require 'git/configuring'
7
- require 'git/deprecation'
8
7
  require 'git/execution_context/repository'
9
8
  require 'git/repository/branching'
10
9
  require 'git/repository/context_helpers'
11
10
  require 'git/repository/committing'
12
- require 'git/repository/configuring'
13
11
  require 'git/repository/diffing'
14
12
  require 'git/repository/factories'
15
13
  require 'git/repository/inspecting'
@@ -18,6 +16,7 @@ require 'git/repository/maintenance'
18
16
  require 'git/repository/merging'
19
17
  require 'git/repository/object_operations'
20
18
  require 'git/repository/remote_operations'
19
+ require 'git/repository/shared_private'
21
20
  require 'git/repository/staging'
22
21
  require 'git/repository/stashing'
23
22
  require 'git/repository/status_operations'
@@ -48,14 +47,11 @@ module Git
48
47
  #
49
48
  # @api public
50
49
  #
51
- class Repository
52
- extend Git::Repository::Factories
53
-
50
+ class Repository # rubocop:disable Metrics/ClassLength
54
51
  include Git::Configuring
55
52
  include Git::Repository::Branching
56
53
  include Git::Repository::ContextHelpers
57
54
  include Git::Repository::Committing
58
- include Git::Repository::Configuring
59
55
  include Git::Repository::Diffing
60
56
  include Git::Repository::Inspecting
61
57
  include Git::Repository::Logging
@@ -68,8 +64,42 @@ module Git
68
64
  include Git::Repository::StatusOperations
69
65
  include Git::Repository::WorktreeOperations
70
66
 
67
+ # Allowed keyword options for deprecated config write operations
68
+ #
69
+ # @return [Array<Symbol>] accepted option keys
70
+ #
71
+ CONFIG_SET_ALLOWED_OPTS = %i[file].freeze
72
+ private_constant :CONFIG_SET_ALLOWED_OPTS
73
+
74
+ # Allowed keyword options for deprecated config read operations
75
+ #
76
+ # @return [Array<Symbol>] accepted option keys
77
+ #
78
+ CONFIG_READ_ALLOWED_OPTS = %i[file].freeze
79
+ private_constant :CONFIG_READ_ALLOWED_OPTS
80
+
81
+ # Deprecation warning emitted by {#config}
82
+ #
83
+ # @return [String] the warning message shown to callers
84
+ #
85
+ CONFIG_DEPRECATION_WARNING =
86
+ 'Git::Repository#config is deprecated and will be removed in v6.0.0. ' \
87
+ 'Use config_get(name), config_set(name, value), or config_list instead.'
88
+ private_constant :CONFIG_DEPRECATION_WARNING
89
+
90
+ # Deprecation warning emitted by {#global_config}
91
+ #
92
+ # @return [String] the warning message shown to callers
93
+ #
94
+ GLOBAL_CONFIG_DEPRECATION_WARNING =
95
+ 'Git::Repository#global_config is deprecated and will be removed in v6.0.0. ' \
96
+ 'Use config_get(name, global: true), config_set(name, value, global: true), ' \
97
+ 'or config_list(global: true) instead.'
98
+ private_constant :GLOBAL_CONFIG_DEPRECATION_WARNING
99
+
71
100
  # @return [Git::ExecutionContext::Repository] the execution context used to run
72
101
  # git commands for this repository
102
+ #
73
103
  # @api private
74
104
  attr_reader :execution_context
75
105
 
@@ -153,6 +183,11 @@ module Git
153
183
  # @api private
154
184
  def git_index_file = execution_context.git_index_file
155
185
 
186
+ # Returns the installed git version
187
+ #
188
+ # @param timeout [Numeric, nil] seconds to wait for `git version`; `nil`
189
+ # uses the default timeout for this execution context
190
+ #
156
191
  # @return [Git::Version] the installed git version
157
192
  #
158
193
  # @api private
@@ -168,6 +203,111 @@ module Git
168
203
  # @api private
169
204
  def binary_path = execution_context.binary_path
170
205
 
206
+ # Reads or writes a git configuration entry
207
+ #
208
+ # Dispatches to one of three modes depending on the arguments supplied:
209
+ #
210
+ # * **List** — `config()` returns all visible config entries as a `Hash`.
211
+ # * **Get** — `config(name)` returns the value for a single key as a `String`.
212
+ # * **Set** — `config(name, value)` writes a value and returns the raw
213
+ # command result.
214
+ #
215
+ # @example List all config entries
216
+ # repo.config #=> { "user.name" => "Alice", "core.bare" => "false" }
217
+ #
218
+ # @example Read a config value
219
+ # repo.config('user.name') #=> "Alice"
220
+ #
221
+ # @example Set a config value
222
+ # repo.config('user.name', 'Alice')
223
+ #
224
+ # @param name [String, Hash, nil] the dotted config key, or an options hash
225
+ # for list mode when `value` and `options` are omitted
226
+ #
227
+ # @param value [#to_s, Hash, nil] the value to set, or an options hash in the
228
+ # legacy `config(name, options)` call shape
229
+ #
230
+ # @param options [Hash] options forwarded to git config
231
+ #
232
+ # @option options [String, nil] :file (nil) path to a custom config file
233
+ #
234
+ # @return [Hash{String => String}, String, Git::CommandLine::Result] all config
235
+ # entries, a single value, or the command result for set mode
236
+ #
237
+ # @raise [ArgumentError] if unsupported options are provided
238
+ #
239
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
240
+ #
241
+ def config(name = nil, value = nil, options = {})
242
+ Git::Deprecation.warn(CONFIG_DEPRECATION_WARNING)
243
+ name, value, options = deprecated_normalize_config_args(name, value, options)
244
+
245
+ if !name.nil? && !value.nil?
246
+ deprecated_config_set(name, value, **options)
247
+ elsif name
248
+ deprecated_config_get(name, **options)
249
+ else
250
+ deprecated_config_list(**options)
251
+ end
252
+ end
253
+
254
+ # Read or write a global git configuration entry
255
+ #
256
+ # Dispatches to one of three modes depending on the arguments supplied,
257
+ # targeting the git global config scope (`git config --global`):
258
+ #
259
+ # * **List** — `global_config()` returns all global config entries as a `Hash`.
260
+ # * **Get** — `global_config(name)` returns the value for a single key as a `String`.
261
+ # * **Set** — `global_config(name, value)` writes a value and returns the raw
262
+ # command result.
263
+ #
264
+ # @overload global_config
265
+ #
266
+ # @example List all global config entries
267
+ # repo.global_config #=> { "user.name" => "Alice", "core.autocrlf" => "false" }
268
+ #
269
+ # @return [Hash{String => String}] all global config entries, keyed by their
270
+ # full dotted key names (e.g. `"user.name"`)
271
+ #
272
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
273
+ #
274
+ # @overload global_config(name)
275
+ #
276
+ # @example Read the global committer name
277
+ # repo.global_config('user.name') #=> "Alice"
278
+ #
279
+ # @param name [String] the dotted config key to look up (e.g. `"user.name"`)
280
+ #
281
+ # @return [String] the value of the global config entry
282
+ #
283
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
284
+ #
285
+ # @overload global_config(name, value)
286
+ #
287
+ # @example Set the global committer name
288
+ # repo.global_config('user.name', 'Alice')
289
+ #
290
+ # @param name [String] the dotted config key to write (e.g. `"user.name"`)
291
+ #
292
+ # @param value [#to_s] the value to assign; any object is accepted and
293
+ # converted to a String via `#to_s` before being passed to git
294
+ #
295
+ # @return [Git::CommandLine::Result] the raw result of
296
+ # `git config --global <name> <value>`
297
+ #
298
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
299
+ #
300
+ def global_config(name = nil, value = nil)
301
+ Git::Deprecation.warn(GLOBAL_CONFIG_DEPRECATION_WARNING)
302
+ if !name.nil? && !value.nil?
303
+ deprecated_global_config_set(name, value)
304
+ elsif !name.nil?
305
+ deprecated_global_config_get(name)
306
+ else
307
+ deprecated_global_config_list
308
+ end
309
+ end
310
+
171
311
  # Returns the size of the repository directory in bytes
172
312
  #
173
313
  # Sums the sizes of every regular file under the repository (`.git`)
@@ -197,6 +337,147 @@ module Git
197
337
 
198
338
  private
199
339
 
340
+ # Normalizes deprecated `config` call shapes into positional arguments
341
+ #
342
+ # @param name [String, Hash, nil] config key or an options hash
343
+ #
344
+ # @param value [#to_s, Hash, nil] config value or an options hash
345
+ #
346
+ # @param options [Hash] explicit options hash argument
347
+ #
348
+ # @option options [String, nil] :file (nil) path to a custom config file
349
+ #
350
+ # @return [Array((String, nil), (#to_s, nil), Hash)] normalized
351
+ # `[name, value, options]`
352
+ #
353
+ # @raise [ArgumentError] if deprecated arguments mix an options hash with
354
+ # unexpected additional positional arguments
355
+ #
356
+ def deprecated_normalize_config_args(name, value, options)
357
+ if name.is_a?(Hash)
358
+ raise ArgumentError, 'unexpected positional arguments after options hash' if !value.nil? || !options.empty?
359
+
360
+ [nil, nil, name]
361
+ elsif value.is_a?(Hash)
362
+ raise ArgumentError, 'unexpected third argument when second argument is options hash' unless options.empty?
363
+
364
+ [name, nil, value]
365
+ else
366
+ [name, value, options]
367
+ end
368
+ end
369
+
370
+ # Writes a config value using the deprecated `config(name, value, ...)` path
371
+ #
372
+ # @overload deprecated_config_set(name, value, **options)
373
+ #
374
+ # @param name [String] the dotted config key to write
375
+ #
376
+ # @param value [#to_s] the value to assign
377
+ #
378
+ # @param options [Hash] command options
379
+ #
380
+ # @option options [String, nil] :file (nil) path to a custom config file
381
+ #
382
+ # @return [Git::CommandLine::Result] the command result
383
+ #
384
+ # @raise [ArgumentError] if unsupported options are provided
385
+ #
386
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
387
+ #
388
+ def deprecated_config_set(name, value, **)
389
+ SharedPrivate.assert_valid_opts!(CONFIG_SET_ALLOWED_OPTS, **)
390
+ Git::Commands::ConfigOptionSyntax::Set.new(@execution_context).call(name, value, **)
391
+ end
392
+
393
+ # Reads a config value using the deprecated `config(name, ...)` path
394
+ #
395
+ # @param name [String] the dotted config key to read
396
+ #
397
+ # @param options [Hash] command options
398
+ #
399
+ # @option options [String, nil] :file (nil) path to a custom config file
400
+ #
401
+ # @return [String] the config value
402
+ #
403
+ # @raise [ArgumentError] if unsupported options are provided
404
+ #
405
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
406
+ #
407
+ def deprecated_config_get(name, **options)
408
+ SharedPrivate.assert_valid_opts!(CONFIG_READ_ALLOWED_OPTS, **options)
409
+ opts = options[:file] ? { file: options[:file] } : {}
410
+ result = Git::Commands::ConfigOptionSyntax::Get.new(@execution_context).call(name, **opts)
411
+ raise Git::FailedError, result if result.status.exitstatus != 0
412
+
413
+ result.stdout
414
+ end
415
+
416
+ # Lists config entries using the deprecated `config(...)` path
417
+ #
418
+ # @param options [Hash] command options
419
+ #
420
+ # @option options [String, nil] :file (nil) path to a custom config file
421
+ #
422
+ # @return [Hash{String => String}] all visible config entries keyed by name
423
+ #
424
+ # @raise [ArgumentError] if unsupported options are provided
425
+ #
426
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
427
+ #
428
+ def deprecated_config_list(**options)
429
+ SharedPrivate.assert_valid_opts!(CONFIG_READ_ALLOWED_OPTS, **options)
430
+ opts = options[:file] ? { file: options[:file] } : {}
431
+ lines = Git::Commands::ConfigOptionSyntax::List.new(@execution_context).call(**opts).stdout.split("\n")
432
+ lines.each_with_object({}) do |line, hsh|
433
+ key, value = line.split('=', 2)
434
+ hsh[key] = value || ''
435
+ end
436
+ end
437
+
438
+ # Reads a global config value using the deprecated `global_config(name)` path
439
+ #
440
+ # @param name [String] the dotted config key to read
441
+ #
442
+ # @return [String] the config value
443
+ #
444
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
445
+ #
446
+ def deprecated_global_config_get(name)
447
+ result = Git::Commands::ConfigOptionSyntax::Get.new(@execution_context).call(name, global: true)
448
+ raise Git::FailedError, result if result.status.exitstatus != 0
449
+
450
+ result.stdout
451
+ end
452
+
453
+ # Lists global config entries using the deprecated `global_config` path
454
+ #
455
+ # @return [Hash{String => String}] all global config entries keyed by name
456
+ #
457
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
458
+ #
459
+ def deprecated_global_config_list
460
+ lines = Git::Commands::ConfigOptionSyntax::List.new(@execution_context).call(global: true).stdout.split("\n")
461
+ lines.each_with_object({}) do |line, hsh|
462
+ key, value = line.split('=', 2)
463
+ hsh[key] = value || ''
464
+ end
465
+ end
466
+
467
+ # Writes a global config value using the deprecated `global_config` path
468
+ #
469
+ # @param name [String] the dotted config key to write
470
+ #
471
+ # @param value [#to_s] the value to assign
472
+ #
473
+ # @return [Git::CommandLine::Result] the command result
474
+ #
475
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
476
+ #
477
+ def deprecated_global_config_set(name, value)
478
+ Git::Commands::ConfigOptionSyntax::Set.new(@execution_context).call(name, value, global: true)
479
+ end
480
+
200
481
  # All git config scopes are valid in a repository context
201
482
  #
202
483
  # @return [void]
data/lib/git/stash.rb CHANGED
@@ -16,15 +16,6 @@ module Git
16
16
  # When `existing` is `false` (the default), immediately calls {#save} to push
17
17
  # the current working-directory state onto the stash stack.
18
18
  #
19
- # @param base [Git::Repository] the git repository
20
- #
21
- # @param message [String] the stash message
22
- #
23
- # @param existing [Boolean] (false) when `true`, wraps an existing stash entry
24
- # without pushing any changes
25
- #
26
- # @return [void]
27
- #
28
19
  # @example Create a new stash entry
29
20
  # stash = Git::Stash.new(repo, 'WIP: feature work')
30
21
  # stash.saved? #=> true
@@ -33,6 +24,14 @@ module Git
33
24
  # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
34
25
  # stash.saved? #=> nil
35
26
  #
27
+ # @param base [Git::Repository] the git repository
28
+ #
29
+ # @param message [String] the stash message
30
+ #
31
+ # @param existing [Boolean] (false) when `true`, wraps an existing stash entry
32
+ # without pushing any changes
33
+ #
34
+ # @return [void]
36
35
  def initialize(base, message, existing: false)
37
36
  @base = base
38
37
  @message = message
@@ -41,50 +40,46 @@ module Git
41
40
 
42
41
  # Saves the current working-directory state to the stash stack
43
42
  #
44
- # @return [Boolean] `true` if changes were stashed, `false` if there were no
45
- # local changes to save
46
- #
47
- # @raise [Git::FailedError] if git exits with a non-zero exit status
48
- #
49
43
  # @example Save changes to the stash stack
50
44
  # stash = Git::Stash.new(repo, 'WIP', existing: true)
51
45
  # stash.save #=> true
52
46
  #
47
+ # @return [Boolean] `true` if changes were stashed, `false` if there were no
48
+ # local changes to save
49
+ #
50
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
53
51
  def save
54
52
  @saved = stash_repository.stash_save(@message)
55
53
  end
56
54
 
57
55
  # Returns whether the stash was saved successfully
58
56
  #
59
- # @return [Boolean, nil] `true` if changes were stashed, `false` if there were no
60
- # local changes, `nil` if {#save} has not been called (e.g. `existing: true`)
61
- #
62
57
  # @example Check if changes were stashed
63
58
  # stash = Git::Stash.new(repo, 'WIP: feature work')
64
59
  # stash.saved? #=> true
65
60
  #
61
+ # @return [Boolean, nil] `true` if changes were stashed, `false` if there were no
62
+ # local changes, `nil` if {#save} has not been called (e.g. `existing: true`)
66
63
  def saved?
67
64
  @saved
68
65
  end
69
66
 
70
67
  # Returns the stash description
71
68
  #
72
- # @return [String] the stash message
73
- #
74
69
  # @example Read the stash message
75
70
  # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
76
71
  # stash.message #=> "WIP: feature work"
77
72
  #
73
+ # @return [String] the stash message
78
74
  attr_reader :message
79
75
 
80
76
  # Returns the stash description as a string
81
77
  #
82
- # @return [String] the stash message
83
- #
84
78
  # @example Convert stash to string
85
79
  # stash = Git::Stash.new(repo, 'WIP: feature work', existing: true)
86
80
  # stash.to_s #=> "WIP: feature work"
87
81
  #
82
+ # @return [String] the stash message
88
83
  def to_s
89
84
  message
90
85
  end
@@ -8,7 +8,6 @@ module Git
8
8
  # its index, reference name, commit SHA, branch, message, author/committer
9
9
  # details, and timestamps.
10
10
  #
11
- # @api public
12
11
  #
13
12
  # @example Create a StashInfo from parsed stash list output
14
13
  # info = Git::StashInfo.new(
@@ -39,6 +38,8 @@ module Git
39
38
  # info.committer_email # => 'jane@example.com'
40
39
  # info.committer_date # => '2026-01-24T10:30:00-08:00'
41
40
  #
41
+ # @api public
42
+ #
42
43
  # @!attribute [r] index
43
44
  # @return [Integer] the stash index (0, 1, 2, ...)
44
45
  #
@@ -92,11 +93,10 @@ module Git
92
93
  ) do
93
94
  # Returns the stash reference name
94
95
  #
95
- # @return [String] the stash name (e.g., 'stash@\\{0}')
96
- #
97
- # @example
96
+ # @example Convert to string
98
97
  # info.to_s # => 'stash@{0}'
99
98
  #
99
+ # @return [String] the stash name (e.g., 'stash@\\{0}')
100
100
  def to_s
101
101
  name
102
102
  end
data/lib/git/stashes.rb CHANGED
@@ -19,16 +19,15 @@ module Git
19
19
  #
20
20
  # Loads all existing stash entries from the repository at construction time.
21
21
  #
22
+ # @example Load stashes for a repository
23
+ # stashes = Git::Stashes.new(repo)
24
+ # stashes.size #=> 2
25
+ #
22
26
  # @param base [Git::Repository] the git repository
23
27
  #
24
28
  # @return [void]
25
29
  #
26
30
  # @raise [Git::FailedError] if git exits with a non-zero exit status
27
- #
28
- # @example Load stashes for a repository
29
- # stashes = Git::Stashes.new(repo)
30
- # stashes.size #=> 2
31
- #
32
31
  def initialize(base)
33
32
  @stashes = []
34
33
  @base = base
@@ -57,16 +56,15 @@ module Git
57
56
 
58
57
  # Saves the current working-directory state to a new stash entry
59
58
  #
59
+ # @example Save current changes to the stash
60
+ # git.stashes.save('WIP: feature work')
61
+ # git.stashes.size #=> 1
62
+ #
60
63
  # @param message [String] the stash message
61
64
  #
62
65
  # @return [void]
63
66
  #
64
67
  # @raise [Git::FailedError] if git exits with a non-zero exit status
65
- #
66
- # @example Save current changes to the stash
67
- # git.stashes.save('WIP: feature work')
68
- # git.stashes.size #=> 1
69
- #
70
68
  def save(message)
71
69
  s = Git::Stash.new(@base, message)
72
70
  @stashes.unshift(s) if s.saved?
@@ -74,32 +72,30 @@ module Git
74
72
 
75
73
  # Applies a stash entry to the working directory
76
74
  #
77
- # @param index [Integer, nil] the stash index to apply (default: latest)
78
- #
79
- # @return [String] the output from the git stash apply command
80
- #
81
- # @raise [Git::FailedError] if git exits with a non-zero exit status
82
- #
83
75
  # @example Apply the most recent stash
84
76
  # git.stashes.apply
85
77
  #
86
78
  # @example Apply a specific stash by index
87
79
  # git.stashes.apply(1)
88
80
  #
81
+ # @param index [Integer, nil] the stash index to apply (default: latest)
82
+ #
83
+ # @return [String] the output from the git stash apply command
84
+ #
85
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
89
86
  def apply(index = nil)
90
87
  stash_repository.stash_apply(index)
91
88
  end
92
89
 
93
90
  # Removes all stash entries
94
91
  #
95
- # @return [void]
96
- #
97
- # @raise [Git::FailedError] if git exits with a non-zero exit status
98
- #
99
92
  # @example Clear all stashes
100
93
  # git.stashes.clear
101
94
  # git.stashes.size #=> 0
102
95
  #
96
+ # @return [void]
97
+ #
98
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
103
99
  def clear
104
100
  stash_repository.stash_clear
105
101
  @stashes = []
@@ -108,11 +104,10 @@ module Git
108
104
 
109
105
  # Returns the number of stash entries
110
106
  #
111
- # @return [Integer] the number of stashes
112
- #
113
107
  # @example Check how many stashes exist
114
108
  # git.stashes.size #=> 2
115
109
  #
110
+ # @return [Integer] the number of stashes
116
111
  def size
117
112
  @stashes.size
118
113
  end
@@ -144,13 +139,12 @@ module Git
144
139
  #
145
140
  # Stashes are stored in newest-first order; index 0 is the most recent stash.
146
141
  #
147
- # @param index [Integer, #to_i] the stash index (0 = most recent)
148
- #
149
- # @return [Git::Stash, nil] the stash entry, or `nil` if the index is out of bounds
150
- #
151
142
  # @example Access the most recent stash
152
143
  # git.stashes[0].message #=> "WIP: feature work"
153
144
  #
145
+ # @param index [Integer, #to_i] the stash index (0 = most recent)
146
+ #
147
+ # @return [Git::Stash, nil] the stash entry, or `nil` if the index is out of bounds
154
148
  def [](index)
155
149
  @stashes[index.to_i]
156
150
  end