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
data/README.md CHANGED
@@ -26,10 +26,13 @@ Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?log
26
26
  - [Errors Raised By This Gem](#errors-raised-by-this-gem)
27
27
  - [Specifying And Handling Timeouts](#specifying-and-handling-timeouts)
28
28
  - [Deprecations](#deprecations)
29
+ - [Upgrading from v4.x to v5.0.0](#upgrading-from-v4x-to-v500)
29
30
  - [Project Policies](#project-policies)
30
31
  - [Ruby Version Support Policy](#ruby-version-support-policy)
31
32
  - [Git Version Support Policy](#git-version-support-policy)
32
33
  - [📢 Project Announcements 📢](#-project-announcements-)
34
+ - [2026-07-11: v5.0.0.beta.4 Released](#2026-07-11-v500beta4-released)
35
+ - [2026-06-26: v5.0.0.beta.3 Released](#2026-06-26-v500beta3-released)
33
36
  - [2026-06-25: v5.0.0.beta.2 Released](#2026-06-25-v500beta2-released)
34
37
  - [2026-06-04: v5.0.0.beta.1 Released](#2026-06-04-v500beta1-released)
35
38
  - [2026-01-07: AI Policy Introduced](#2026-01-07-ai-policy-introduced)
@@ -63,24 +66,12 @@ Install the gem and add to the application's Gemfile by executing:
63
66
  bundle add git
64
67
  ```
65
68
 
66
- to install version 1.x:
67
-
68
- ```shell
69
- bundle add git --version "~> 1.19"
70
- ```
71
-
72
69
  If bundler is not being used to manage dependencies, install the gem by executing:
73
70
 
74
71
  ```shell
75
72
  gem install git
76
73
  ```
77
74
 
78
- to install version 1.x:
79
-
80
- ```shell
81
- gem install git --version "~> 1.19"
82
- ```
83
-
84
75
  ## Quick Start
85
76
 
86
77
  All functionality for this gem starts with the top-level
@@ -134,15 +125,17 @@ Configure the `git` command line:
134
125
 
135
126
  ```ruby
136
127
  # Global config (in ~/.gitconfig)
137
- settings = Git.global_config # returns a Hash
138
- username = Git.global_config('user.email')
139
- Git.global_config('user.email', 'user@example.com')
128
+ entries = Git.config_list(global: true) # returns Array<Git::ConfigEntryInfo>
129
+ entry = Git.config_get('user.email', global: true) # returns Git::ConfigEntryInfo or nil
130
+ email = entry&.value # => "user@example.com" or nil
131
+ Git.config_set('user.email', 'user@example.com', global: true)
140
132
 
141
133
  # Repository config
142
134
  repo = Git.open('path/to/repo')
143
- settings = repo.config # returns a Hash
144
- username = repo.config('user.email')
145
- repo.config('user.email', 'anotheruser@example.com')
135
+ entries = repo.config_list # returns Array<Git::ConfigEntryInfo>
136
+ entry = repo.config_get('user.email') # returns Git::ConfigEntryInfo or nil
137
+ email = entry&.value # => "anotheruser@example.com" or nil
138
+ repo.config_set('user.email', 'anotheruser@example.com')
146
139
  ```
147
140
 
148
141
  Configure the git gem:
@@ -293,8 +286,8 @@ result = repo.fsck(unreachable: true, strict: true)
293
286
  # Suppress dangling object output
294
287
  result = repo.fsck(dangling: false)
295
288
 
296
- repo.config('user.name') # returns 'Scott Chacon'
297
- repo.config # returns whole config hash
289
+ repo.config_get('user.name')&.value # returns 'Scott Chacon'
290
+ repo.config_list # returns Array<Git::ConfigEntryInfo>
298
291
 
299
292
  # Configuration can be set when cloning using the :config option.
300
293
  # This option can be an single configuration String or an Array
@@ -343,8 +336,8 @@ path = '/tmp/clone'
343
336
  repo = Git.clone(git_url, name, :path => path)
344
337
  repo.dir #=> /tmp/clone/ruby-git-clean
345
338
 
346
- repo.config('user.name', 'Scott Chacon')
347
- repo.config('user.email', 'email@email.com')
339
+ repo.config_set('user.name', 'Scott Chacon')
340
+ repo.config_set('user.email', 'email@email.com')
348
341
 
349
342
  # Clone can take a filter to tell the serve to send a partial clone
350
343
  repo = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
@@ -371,7 +364,7 @@ repo.commit('message')
371
364
  repo.commit_all('message')
372
365
 
373
366
  # Sign a commit using the gpg key configured in the user.signingkey config setting
374
- repo.config('user.signingkey', '0A46826A')
367
+ repo.config_set('user.signingkey', '0A46826A')
375
368
  repo.commit('message', gpg_sign: true)
376
369
 
377
370
  # Sign a commit using a specified gpg key
@@ -591,6 +584,18 @@ You can silence deprecation warnings by adding this line to your source code:
591
584
  Git::Deprecation.behavior = :silence
592
585
  ```
593
586
 
587
+ Or by setting this environment variable before loading the gem:
588
+
589
+ ```sh
590
+ GIT_DEPRECATION_BEHAVIOR=silence
591
+ ```
592
+
593
+ Accepted environment variable values are the behavior names supported by your
594
+ installed ActiveSupport version.
595
+
596
+ If `GIT_DEPRECATION_BEHAVIOR` is set to an unsupported value, loading the gem
597
+ raises `ArgumentError` with the accepted behavior names.
598
+
594
599
  See [the Active Support Deprecation
595
600
  documentation](https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html)
596
601
  for more details.
@@ -599,6 +604,14 @@ If deprecation warnings are silenced, you should reenable them before upgrading
599
604
  git gem to the next major version. This will make it easier to identify changes
600
605
  needed for the upgrade.
601
606
 
607
+ For the full list of deprecated methods and their replacements, see
608
+ [UPGRADING.md](UPGRADING.md).
609
+
610
+ ## Upgrading from v4.x to v5.0.0
611
+
612
+ v5.0.0 is a major release with breaking changes. See
613
+ [UPGRADING.md](UPGRADING.md) for a comprehensive migration guide.
614
+
602
615
  ## Project Policies
603
616
 
604
617
  These documents set expectations for behavior, contribution workflows, AI-assisted
@@ -651,6 +664,56 @@ notes.
651
664
 
652
665
  ## 📢 Project Announcements 📢
653
666
 
667
+ ### 2026-07-11: v5.0.0.beta.4 Released
668
+
669
+ The architectural redesign is **feature complete** and we have published
670
+ [`git v5.0.0.beta.4`](https://rubygems.org/gems/git/versions/5.0.0.beta.4) as our
671
+ fourth pre-release.
672
+
673
+ **To try the beta**, add the pre-release version to your `Gemfile`:
674
+
675
+ ```ruby
676
+ gem 'git', '~> 5.0.0.beta'
677
+ ```
678
+
679
+ Or install it directly:
680
+
681
+ ```sh
682
+ gem install git --pre
683
+ ```
684
+
685
+ The intent is full backward compatibility with v4.x, but given the size and scope of
686
+ the redesign, some incompatibilities may exist. Please give the latest beta a try and
687
+ [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
688
+ unexpected — your feedback helps us ship a solid v5.0.0.
689
+
690
+ See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
691
+
692
+ ### 2026-06-26: v5.0.0.beta.3 Released
693
+
694
+ The architectural redesign is approximately **93% complete** and we have published
695
+ [`git v5.0.0.beta.3`](https://rubygems.org/gems/git/versions/5.0.0.beta.3) as our
696
+ third pre-release.
697
+
698
+ **To try the beta**, add the pre-release version to your `Gemfile`:
699
+
700
+ ```ruby
701
+ gem 'git', '~> 5.0.0.beta'
702
+ ```
703
+
704
+ Or install it directly:
705
+
706
+ ```sh
707
+ gem install git --pre
708
+ ```
709
+
710
+ The intent is full backward compatibility with v4.x, but given the size and scope of
711
+ the redesign, some incompatibilities may exist. Please give the latest beta a try and
712
+ [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
713
+ unexpected — your feedback helps us ship a solid v5.0.0.
714
+
715
+ See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
716
+
654
717
  ### 2026-06-25: v5.0.0.beta.2 Released
655
718
 
656
719
  The architectural redesign is approximately **90% complete** and we have published
data/Rakefile CHANGED
@@ -5,29 +5,11 @@ require 'rake/clean'
5
5
  # Load all .rake files from tasks and its subdirectories.
6
6
  Dir.glob('tasks/**/*.rake').each { |r| load r }
7
7
 
8
- desc 'Run all tests (TestUnit and RSpec)'
9
- task 'test-all': %i[test spec]
10
-
11
- desc 'Run all tests in parallel (TestUnit and RSpec run concurrently)'
12
- task 'test-all:parallel' do
13
- errors = []
14
- mutex = Mutex.new
15
- threads = %w[test:parallel spec:parallel].map do |t|
16
- Thread.new do
17
- Rake::Task[t].invoke
18
- rescue Exception => e # rubocop:disable Lint/RescueException
19
- mutex.synchronize { errors << e }
20
- end
21
- end
22
- threads.each(&:join)
23
- raise errors.first if errors.any?
24
- end
25
-
26
- default_tasks = %i[test spec:unit spec:integration rubocop]
8
+ default_tasks = %i[spec:unit spec:integration rubocop]
27
9
  default_tasks << :yard if Rake::Task.task_defined?(:yard)
28
10
  default_tasks << :build
29
11
 
30
- default_tasks_parallel = %w[test:parallel spec:unit:parallel spec:integration:parallel rubocop]
12
+ default_tasks_parallel = %w[spec:unit:parallel spec:integration:parallel rubocop]
31
13
  default_tasks_parallel << :yard if Rake::Task.task_defined?(:yard)
32
14
  default_tasks_parallel << :build
33
15
 
@@ -54,7 +36,7 @@ module Rake
54
36
  # rake rubocop # => do not output the task name
55
37
  # rake rubocop yard # => output task name for rubocop and yard
56
38
  top_level_tasks = Rake.application.top_level_tasks
57
- box("Rake task: #{name}") unless top_level_tasks.length == 1 && name == top_level_tasks[0]
39
+ box("rake #{name}") unless top_level_tasks.length == 1 && name == top_level_tasks[0]
58
40
  original_execute(args)
59
41
  end
60
42
 
data/UPGRADING.md CHANGED
@@ -1,83 +1,165 @@
1
1
  # Upgrading the `git` Gem
2
2
 
3
- > **⚠️ Work in progress v5.0.0 is currently in beta.**
4
- > This document is updated incrementally as development continues and is not yet
5
- > complete. If you encounter a compatibility problem not covered here, please
6
- > [open an issue](https://github.com/ruby-git/ruby-git/issues).
3
+ This document covers breaking changes and migration steps when upgrading the
4
+ `git` gem to a new major version. Each section describes what changed and how
5
+ to update your code when upgrading from the preceding major version.
7
6
 
8
- - [Upgrading from v4.x to v5.x](#upgrading-from-v4x-to-v5x)
7
+ - [Upgrading to v5.x](#upgrading-to-v5x)
9
8
  - [Overview](#overview)
10
- - [`Git::Lib` removal](#gitlib-removal)
11
- - [Methods with a direct replacement](#methods-with-a-direct-replacement)
12
- - [Methods with no replacement](#methods-with-no-replacement)
13
- - [Internal plumbing methods (no replacement)](#internal-plumbing-methods-no-replacement)
9
+ - [Breaking changes](#breaking-changes)
10
+ - [`Git::Base` removed](#gitbase-removed)
11
+ - [Return type of `Git.open`, `Git.clone`, `Git.init`, `Git.bare`](#return-type-of-gitopen-gitclone-gitinit-gitbare)
12
+ - [`Git::Lib` removed](#gitlib-removed)
13
+ - [`Git::CommandLineResult` deprecated](#gitcommandlineresult-deprecated)
14
14
  - [Deprecated methods](#deprecated-methods)
15
+ - [Facade method renames](#facade-method-renames)
16
+ - [v4.x-style configuration methods](#v4x-style-configuration-methods)
17
+ - [`Git` module mixin deprecations](#git-module-mixin-deprecations)
15
18
 
16
- ## Upgrading from v4.x to v5.x
19
+ ## Upgrading to v5.x
17
20
 
18
21
  ### Overview
19
22
 
20
- The primary goal of v5.0.0 is to move everyone onto a new internal architecture
21
- while keeping the existing v4.x API working. The vast majority of v4.x code
22
- requires no changes to run on v5.x.
23
+ v5.0.0 delivers a new internal architecture while keeping the v4.x API working
24
+ for the vast majority of users. Most v4.x code requires **no changes** to run on
25
+ v5.x.
23
26
 
24
- The new architecture delivered in v5.0.0 is the foundation for future API
25
- improvements across upcoming major releases.
27
+ The new architecture introduces a layered design (`Git::Commands`,
28
+ `Git::Repository`, and associated parsers). Compatibility shims — deprecated
29
+ forwarding methods that map old call patterns to the new API — ensure that v4.x
30
+ code continues to work. These shims emit deprecation warnings that tell you
31
+ exactly what to change and what will be eliminated in v6.0.0.
26
32
 
27
- The new architecture introduces a layered design (`Git::Commands`, `Git::Repository`,
28
- and associated parsers). Compatibility shims deprecated forwarding methods that map
29
- old call patterns to the new API ensure that v4.x code continues to work. These
30
- shims emit deprecation warnings that tell you exactly what to change and what will be
31
- eliminated in a future major release (most likely v6.0.0).
33
+ Hard breaks are limited to a small number of things that had no safe migration
34
+ path. These are described in the [Breaking changes](#breaking-changes) section,
35
+ followed by [Deprecated methods](#deprecated-methods) that still work in v5.x
36
+ but are removed in v6.0.0.
32
37
 
33
- Hard breaks are limited to a small number of methods that had no safe
34
- migration path — these are described in detail below.
35
-
36
- Our intent is to make upgrading to v5.x as smooth as possible. For information
37
- on how to suppress or configure deprecation warnings, see the
38
+ For information on how to suppress or configure deprecation warnings, see the
38
39
  [Deprecations](README.md#deprecations) section of the README.
39
40
 
41
+ **Changes at a glance:**
42
+
43
+ | Change | Type | Impact | Action required |
44
+ |--------|------|--------|-----------------|
45
+ | `Git::Base` removed | Hard break | High for code that references it by name | Replace with `Git::Repository` (returned by `Git.open` etc.) |
46
+ | `Git::Lib` removed | Hard break | High for `.lib.*` callers | Use the equivalent method directly on the repo object (see table below) |
47
+ | `Git.open` etc. return `Git::Repository` (not `Git::Base`) | Hard break | Low for most callers; breaks `is_a?(Git::Base)` | Update type checks and update `be_a(Git::Base)` in tests |
48
+ | `Git::CommandLineResult` deprecated | Deprecation (removed in v6.0.0) | Low; only affects code that references the constant by name | Use `Git::CommandLine::Result` instead |
49
+
40
50
  ---
41
51
 
42
- ### `Git::Lib` removal
52
+ ### Breaking changes
43
53
 
44
- The object returned by `Git.open`, `Git.clone`, and `Git.init` — the object
45
- you call methods on to interact with your repository — inadvertently exposed
46
- a `#lib` method that gave access to `Git::Lib`, the gem's internal
47
- implementation class. This was never intended to be public; it was an
48
- implementation detail that leaked out. `Git::Lib` is removed in v5.0.0.
54
+ #### `Git::Base` removed
49
55
 
50
- Calling `#lib` on the repository object returns `self` with a deprecation
51
- warning so that existing `g.lib.*` call chains continue to work during
52
- migration. The `#lib` method itself is removed in v6.0.0. Calls to methods
53
- that have no replacement (see below) raise `NoMethodError` with an
54
- informative message.
56
+ `Git::Base` the class previously returned by `Git.open`, `Git.clone`,
57
+ `Git.init`, and `Git.bare` is removed in v5.0.0. The replacement is
58
+ `Git::Repository`, which is returned by all four entry points and exposes the
59
+ same public API.
55
60
 
56
- Most public behavior previously accessible via `g.lib.*` is available
57
- directly on the repository object (i.e., `g.*`). A small number of methods
58
- have no replacement — see below. The sections below list every affected method.
61
+ **Code that must be updated:**
59
62
 
60
- #### Methods with a direct replacement
63
+ ```ruby
64
+ # v4.x — explicit Git::Base reference (raises NameError in v5.x)
65
+ repo = Git::Base.new(working_directory: '/path/to/repo')
61
66
 
62
- All of the following `g.lib.*` calls work in v5.x but emit a deprecation
63
- warning. Migrate to the replacement shown to silence the `g.lib.*` deprecation
64
- warning; note that some replacements are themselves deprecated — see the table
65
- notes for the final migration target.
67
+ # v5.x use the entry-point methods; do not construct Git::Repository directly
68
+ repo = Git.open('/path/to/repo')
69
+ ```
66
70
 
67
- | Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
68
- |---------------------------------------------------|-------------|
69
- | `g.lib.config_get(name)` | `g.config(name)` |
70
- | `g.lib.config_list` | `g.config` |
71
- | `g.lib.config_set(name, value)` | `g.config(name, value)` |
71
+ ```ruby
72
+ # v4.x — type-checking against Git::Base (raises NameError in v5.x because Git::Base is removed)
73
+ raise unless repo.is_a?(Git::Base)
74
+
75
+ # v5.x check against Git::Repository
76
+ raise unless repo.is_a?(Git::Repository)
77
+ ```
78
+
79
+ ```ruby
80
+ # v4.x — requiring the internal file (raises LoadError in v5.x)
81
+ require 'git/base'
82
+
83
+ # v5.x — the public entry point is git itself; no internal require needed
84
+ require 'git'
85
+ ```
86
+
87
+ **Public API is preserved:** `Git::Repository` provides every method that
88
+ `Git::Base` did. Code that simply calls methods on the object returned by
89
+ `Git.open` (e.g., `repo.commit`, `repo.status`, `repo.add`) requires no
90
+ changes.
91
+
92
+ ---
93
+
94
+ #### Return type of `Git.open`, `Git.clone`, `Git.init`, `Git.bare`
95
+
96
+ `Git.open`, `Git.clone`, `Git.init`, and `Git.bare` now return
97
+ `Git::Repository` instead of `Git::Base`.
98
+
99
+ For most callers this is transparent — the returned object responds to the same
100
+ methods. Code that explicitly checks `is_a?(Git::Base)` or `be_a(Git::Base)` in
101
+ tests must be updated:
102
+
103
+ ```ruby
104
+ # v4.x
105
+ expect(Git.open(repo_path)).to be_a(Git::Base)
106
+
107
+ # v5.x
108
+ expect(Git.open(repo_path)).to be_a(Git::Repository)
109
+ ```
110
+
111
+ `Git::Repository` does not define `.open`, `.bare`, `.clone`, or `.init` class
112
+ methods. Always use `Git.open`, `Git.bare`, `Git.clone`, and `Git.init` to
113
+ construct a repository object.
114
+
115
+ ---
116
+
117
+ #### `Git::Lib` removed
118
+
119
+ The object returned by `Git.open`, `Git.clone`, `Git.init`, and `Git.bare` previously
120
+ exposed a `#lib` method that gave access to `Git::Lib`, the gem's internal
121
+ implementation class. `Git::Lib` is removed in v5.0.0.
122
+
123
+ In v5.x, calling `#lib` on a repo object returns `self` with a deprecation
124
+ warning. This means `g.lib.some_method(args)` is forwarded to
125
+ `g.some_method(args)` — but only if `some_method` exists on `Git::Repository`.
126
+ Methods that were unique to `Git::Lib` and have no counterpart on
127
+ `Git::Repository` raise `NoMethodError` immediately. The `#lib` method itself
128
+ is removed in v6.0.0.
129
+
130
+ Most public behavior previously accessible via `g.lib.*` is available directly
131
+ on the repository object (`g.*`). See the tables below for every affected
132
+ method.
133
+
134
+ ##### Methods that work via the `#lib` shim (with deprecation warning)
135
+
136
+ The following v4.x `g.lib.*` call shapes are forwarded to their `Git::Repository`
137
+ counterpart by the `#lib → self` shim. They emit a deprecation warning; migrate
138
+ to the replacement shown to silence it.
139
+
140
+ > **Note — config return type change:** `g.lib.config_get(name)` returned a
141
+ > `String`; `g.lib.config_list` returned a `Hash`.
142
+ > The v5.x replacements `config_get` and `config_list` return
143
+ > `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>` respectively — richer
144
+ > objects that expose `.value` (the String), `.key`, `.scope`, and `.origin`.
145
+ >
146
+ > If you only need the String value:
147
+ > - `g.config_get(name)&.value` → replaces `g.lib.config_get(name)`
148
+ > - `g.config_list.to_h { |e| [e.key, e.value] }` → replaces `g.lib.config_list`
149
+ >
150
+ > If your code was using the v4.x public `g.config(name)` API (not `g.lib.*`),
151
+ > that deprecated bridge still returns a `String` in v5.x and continues to work
152
+ > until v6.0.0.
153
+
154
+ | v4.x call | Replacement in v5.x |
155
+ |-----------|---------------------|
156
+ | `g.lib.config_get(name)` | `g.config_get(name)` — returns `Git::ConfigEntryInfo`; use `.value` for the String |
157
+ | `g.lib.config_list` | `g.config_list` — returns `Array<Git::ConfigEntryInfo>` |
158
+ | `g.lib.config_set(name, value)` | `g.config_set(name, value)` |
72
159
  | `g.lib.git_version` | `g.git_version` |
73
- | `g.lib.global_config_get(name)` | `g.global_config(name)` |
74
- | `g.lib.global_config_list` | `g.global_config` |
75
- | `g.lib.global_config_set(name, value)` | `g.global_config(name, value)` |
76
- | `g.lib.parse_config(file)` | `g.config(file: file)` |
77
- | `g.lib.stash_list` | `g.stash_list` *(also deprecated — use `g.stashes_all`)* |
160
+ | `g.lib.stash_list` | `g.stashes_all` |
78
161
  | `g.lib.unmerged` | `g.unmerged` |
79
162
  | `g.lib.change_head_branch(name)` | `g.change_head_branch(name)` |
80
- | `g.lib.branch_current` | `g.current_branch` |
81
163
  | `g.lib.ls_remote(location, opts)` | `g.ls_remote(location, opts)` |
82
164
  | `g.lib.current_branch_state` | `g.current_branch_state` |
83
165
 
@@ -89,13 +171,27 @@ notes for the final migration target.
89
171
  > (`Git::Lib::HeadState.new(:active, 'main')`), update to keyword construction:
90
172
  > `Git::Repository::Branching::HeadState.new(state: :active, name: 'main')`.
91
173
 
92
- #### Methods with no replacement
174
+ ##### Methods that raise `NoMethodError` in v5.x
175
+
176
+ These `Git::Lib` method names have no counterpart on `Git::Repository`, so
177
+ `g.lib.method_name` raises `NoMethodError` even in v5.x (the `#lib → self`
178
+ shim cannot forward them). Update call sites directly:
179
+
180
+ | v4.x call | Replacement in v5.x |
181
+ |-----------|---------------------|
182
+ | `g.lib.global_config_get(name)` | `g.config_get(name, global: true)` |
183
+ | `g.lib.global_config_list` | `g.config_list(global: true)` |
184
+ | `g.lib.global_config_set(name, value)` | `g.config_set(name, value, global: true)` |
185
+ | `g.lib.branch_current` | `g.current_branch` |
186
+ | `g.lib.parse_config(file)` | `g.config_list(file: file)` |
187
+
188
+ ##### Methods with no replacement
93
189
 
94
190
  | v4.x call | Notes |
95
191
  |-----------|-------|
96
192
  | `g.lib.list_files(ref_dir)` | Walked `.git/refs/` directly. Use `g.branches`, `g.tags`, or `g.remotes` instead. |
97
193
 
98
- #### Internal plumbing methods (no replacement)
194
+ ##### Internal plumbing methods (no replacement)
99
195
 
100
196
  The following methods were technically public on `Git::Lib` but are internal
101
197
  helpers with no plausible external use. They have no replacement in v5.0.0:
@@ -115,27 +211,80 @@ helpers with no plausible external use. They have no replacement in v5.0.0:
115
211
 
116
212
  ---
117
213
 
214
+ #### `Git::CommandLineResult` deprecated
215
+
216
+ `Git::CommandLineResult` was an alias for `Git::CommandLine::Result` introduced
217
+ for backward compatibility. It is deprecated in v5.0.0 and removed in v6.0.0.
218
+ Accessing `Git::CommandLineResult` emits a deprecation warning.
219
+
220
+ ```ruby
221
+ # v4.x
222
+ result.is_a?(Git::CommandLineResult)
223
+
224
+ # v5.x
225
+ result.is_a?(Git::CommandLine::Result)
226
+ ```
227
+
228
+ This change is only relevant if your code references `Git::CommandLineResult`
229
+ by name (typically in type checks or documentation). Code that simply uses the
230
+ result object returned by git commands is unaffected.
231
+
232
+ ---
233
+
118
234
  ### Deprecated methods
119
235
 
120
- The following methods are available in v5.x with deprecation warnings and
121
- are removed in v6.0.0.
236
+ The following methods are available in v5.x with deprecation warnings and are
237
+ removed in v6.0.0. Migrate to the replacement shown to silence the warnings.
238
+
239
+ #### Facade method renames
240
+
241
+ Five methods were renamed to follow the project's `noun_verb` naming convention.
242
+ The old names continue to work but emit deprecation warnings:
122
243
 
123
244
  | Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
124
- |---------------------------------------------------|-------------|
125
- | `g.config_get(name)` | `g.config(name)` |
126
- | `g.config_list` | `g.config` |
127
- | `g.config_set(name, value)` | `g.config(name, value)` |
128
- | `g.global_config_get(name)` | `g.global_config(name)` |
129
- | `g.global_config_list` | `g.global_config` |
130
- | `g.global_config_set(name, value)` | `g.global_config(name, value)` |
131
- | `g.parse_config(file)` | `g.config(file: file)` |
132
- | `g.stash_list` | `g.stashes_all` |
245
+ |-----------------------------------------------------|-------------|
133
246
  | `g.add_remote(name, url, opts)` | `g.remote_add(name, url, opts)` |
134
247
  | `g.remove_remote(name)` | `g.remote_remove(name)` |
135
248
  | `g.set_remote_url(name, url)` | `g.remote_set_url(name, url)` |
136
249
  | `g.add_tag(name, ...)` | `g.tag_add(name, ...)` |
137
250
  | `g.delete_tag(name)` | `g.tag_delete(name)` |
138
- | `include Git; config(...)` | `Git.open(Dir.pwd).config(...)` |
139
- | `include Git; global_config(...)` | `Git.global_config(...)` |
251
+
252
+ #### v4.x-style configuration methods
253
+
254
+ The v4.x `config` and `global_config` methods accepted varying argument shapes
255
+ to read, write, or list configuration. These are replaced by separate,
256
+ purpose-named methods.
257
+
258
+ > **Return type change:** The v4.x `g.config(name)` returned a `String` and
259
+ > `g.config` returned a `Hash`. The v5.x replacements `config_get` and
260
+ > `config_list` return `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>`
261
+ > respectively. Use `.value` to get the String value:
262
+ > - `g.config_get(name)&.value` → String or nil
263
+ > - `g.config_list.to_h { |e| [e.key, e.value] }` → Hash (key → value)
264
+
265
+ | Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
266
+ |-----------------------------------------------------|-------------|
267
+ | `g.config(name)` | `g.config_get(name)` — returns `Git::ConfigEntryInfo`; use `.value` for the String |
268
+ | `g.config` | `g.config_list` — returns `Array<Git::ConfigEntryInfo>` |
269
+ | `g.config(name, value)` | `g.config_set(name, value)` |
270
+ | `g.global_config(name)` | `g.config_get(name, global: true)` |
271
+ | `g.global_config` | `g.config_list(global: true)` |
272
+ | `g.global_config(name, value)` | `g.config_set(name, value, global: true)` |
273
+ | `g.parse_config(file)` | `g.config_list(file: file)` |
274
+ | `g.stash_list` | `g.stashes_all` |
275
+
276
+ #### `Git` module mixin deprecations
277
+
278
+ Extending or including the `Git` module to call `config` and `global_config`
279
+ as bare methods is deprecated:
280
+
281
+ | Deprecated usage | Replacement |
282
+ |-----------------|-------------|
283
+ | `include Git; config(name)` | `Git.open(Dir.pwd).config_get(name)` |
284
+ | `include Git; config(name, value)` | `Git.open(Dir.pwd).config_set(name, value)` |
285
+ | `include Git; config` | `Git.open(Dir.pwd).config_list` |
286
+ | `include Git; global_config(name)` | `Git.config_get(name, global: true)` |
287
+ | `include Git; global_config(name, value)` | `Git.config_set(name, value, global: true)` |
288
+ | `include Git; global_config` | `Git.config_list(global: true)` |
140
289
 
141
290
  ---
@@ -0,0 +1,32 @@
1
+ FROM ruby
2
+
3
+ WORKDIR /ruby-git
4
+
5
+
6
+ ADD Gemfile git.gemspec ./
7
+ ADD lib/git/version.rb ./lib/git/version.rb
8
+
9
+ # `git.gemspec`'s `spec.files` shells out to `git ls-files`, which Bundler
10
+ # evaluates below via the Gemfile's `gemspec` directive. Rather than relying
11
+ # on the host's `.git` (which, for a build context copied from a linked git
12
+ # worktree, is a file pointing at an absolute host path that doesn't exist
13
+ # in the image — breaking every git command with "fatal: not a git
14
+ # repository"), always initialize a throwaway repo scoped to the image. This
15
+ # also keeps the image self-contained and avoids ever copying the
16
+ # (potentially large) host `.git` directory in (see `.dockerignore`). A
17
+ # second commit is added below once the full source tree is present, so the
18
+ # final file list is complete.
19
+ RUN git init -q && \
20
+ git -c user.email=docker@example.com -c user.name=docker add -A && \
21
+ git -c user.email=docker@example.com -c user.name=docker commit -q -m 'Throwaway repo for Docker test run'
22
+
23
+ RUN bundle install
24
+
25
+ ADD . .
26
+
27
+ # Refresh the throwaway repo now that the full source tree is present, so
28
+ # `git ls-files` reflects every file for `rake build`'s `spec.files`.
29
+ RUN git -c user.email=docker@example.com -c user.name=docker add -A && \
30
+ git -c user.email=docker@example.com -c user.name=docker commit -q -m 'Add full source' --allow-empty
31
+
32
+ ENTRYPOINT ["bundle", "exec", "rake", "default"]
File without changes
data/git.gemspec CHANGED
@@ -37,8 +37,6 @@ Gem::Specification.new do |spec|
37
37
  spec.add_development_dependency 'create_github_release', '~> 2.1'
38
38
  spec.add_development_dependency 'fuubar', '~> 2.5'
39
39
  spec.add_development_dependency 'main_branch_shared_rubocop_config', '~> 0.1'
40
- spec.add_development_dependency 'minitar', '~> 1.1'
41
- spec.add_development_dependency 'mocha', '~> 2.8'
42
40
  spec.add_development_dependency 'parallel_tests', '~> 5.6'
43
41
  spec.add_development_dependency 'rake', '~> 13.3'
44
42
  spec.add_development_dependency 'rspec', '~> 3.13'
@@ -46,7 +44,6 @@ Gem::Specification.new do |spec|
46
44
  spec.add_development_dependency 'simplecov', '~> 0.22'
47
45
  spec.add_development_dependency 'simplecov-lcov', '~> 0.9'
48
46
  spec.add_development_dependency 'simplecov-rspec', '~> 0.4'
49
- spec.add_development_dependency 'test-unit', '~> 3.7'
50
47
 
51
48
  if RUBY_ENGINE == 'truffleruby' && Gem::Version.new(RUBY_ENGINE_VERSION) < Gem::Version.new('34.0.0')
52
49
  # i18n 1.15+ uses Fiber.[] (Ruby 3.2 Fiber storage) which TruffleRuby < 34.0.0 does not implement
@@ -58,7 +55,9 @@ Gem::Specification.new do |spec|
58
55
  spec.add_development_dependency 'redcarpet', '~> 3.6'
59
56
  spec.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28'
60
57
  spec.add_development_dependency 'yard_example_test', '~> 0.2', '>= 0.2.1'
61
- spec.add_development_dependency 'yardstick', '~> 0.9'
58
+
59
+ # yard-lint requires Ruby >= 3.3, so it is only installed on Ruby 3.3+.
60
+ spec.add_development_dependency 'yard-lint', '~> 1.8' if Gem.ruby_version >= Gem::Version.new('3.3.0')
62
61
  end
63
62
 
64
63
  # Specify which files should be added to the gem when it is released.
data/lib/git/author.rb CHANGED
@@ -2,9 +2,28 @@
2
2
 
3
3
  module Git
4
4
  # An author in a Git commit
5
+ #
6
+ # @api public
7
+ #
5
8
  class Author
6
- attr_accessor :name, :email, :date
9
+ # @return [String, nil] the author's name
10
+ attr_accessor :name
7
11
 
12
+ # @return [String, nil] the author's email
13
+ attr_accessor :email
14
+
15
+ # @return [Time, nil] the date the change was authored (author date, not committer date)
16
+ attr_accessor :date
17
+
18
+ # Initializes a new Author object from a string
19
+ #
20
+ # @example
21
+ # Git::Author.new("John Doe <john.doe@example.com> 1627849923 +0200")
22
+ #
23
+ # @param author_string [String] the author string
24
+ #
25
+ # @return [void]
26
+ #
8
27
  def initialize(author_string)
9
28
  return unless (m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string))
10
29