git 5.1.0 → 5.3.0

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -0
  3. data/CONTRIBUTING.md +202 -169
  4. data/LICENSE +1 -1
  5. data/README.md +192 -151
  6. data/UPGRADING.md +287 -1
  7. data/git.gemspec +35 -3
  8. data/lib/git/author.rb +11 -0
  9. data/lib/git/author_info.rb +66 -0
  10. data/lib/git/branch.rb +210 -15
  11. data/lib/git/branch_info.rb +1 -1
  12. data/lib/git/branches.rb +35 -7
  13. data/lib/git/command_line/base.rb +1 -2
  14. data/lib/git/commands/base.rb +1 -1
  15. data/lib/git/commands/cat_file/raw.rb +62 -7
  16. data/lib/git/object.rb +13 -7
  17. data/lib/git/parsers/stash.rb +50 -17
  18. data/lib/git/parsers/tag.rb +54 -8
  19. data/lib/git/remote.rb +37 -7
  20. data/lib/git/remote_info.rb +67 -10
  21. data/lib/git/repository/branching.rb +190 -6
  22. data/lib/git/repository/merging.rb +96 -2
  23. data/lib/git/repository/remote_operations.rb +57 -0
  24. data/lib/git/repository/shared_private.rb +67 -0
  25. data/lib/git/stash_info.rb +32 -34
  26. data/lib/git/tag_info.rb +21 -29
  27. data/lib/git/version.rb +1 -1
  28. data/lib/git.rb +1 -0
  29. metadata +6 -94
  30. data/.claude/commands/address-copilot-reviews.md +0 -14
  31. data/.claude/settings.json +0 -16
  32. data/.claude/skills +0 -1
  33. data/.commitlintrc.yml +0 -38
  34. data/.dockerignore +0 -27
  35. data/.github/copilot-instructions.md +0 -30
  36. data/.github/hooks/bin-setup-on-worktree.json +0 -11
  37. data/.github/hooks/run-bin-setup-once.sh +0 -20
  38. data/.github/issue_template.md +0 -15
  39. data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +0 -188
  40. data/.github/pull_request_template.md +0 -21
  41. data/.github/skills/breaking-change-analysis/SKILL.md +0 -99
  42. data/.github/skills/ci-cd-troubleshooting/SKILL.md +0 -264
  43. data/.github/skills/command-implementation/REFERENCE.md +0 -994
  44. data/.github/skills/command-implementation/SKILL.md +0 -230
  45. data/.github/skills/command-test-conventions/SKILL.md +0 -664
  46. data/.github/skills/command-yard-documentation/SKILL.md +0 -434
  47. data/.github/skills/dependency-management/SKILL.md +0 -72
  48. data/.github/skills/development-workflow/SKILL.md +0 -512
  49. data/.github/skills/facade-implementation/REFERENCE.md +0 -837
  50. data/.github/skills/facade-implementation/SKILL.md +0 -269
  51. data/.github/skills/facade-test-conventions/SKILL.md +0 -391
  52. data/.github/skills/facade-yard-documentation/SKILL.md +0 -435
  53. data/.github/skills/make-skill-template/SKILL.md +0 -226
  54. data/.github/skills/pr-readiness-review/SKILL.md +0 -205
  55. data/.github/skills/project-context/SKILL.md +0 -306
  56. data/.github/skills/pull-request-review/SKILL.md +0 -168
  57. data/.github/skills/rebase/SKILL.md +0 -148
  58. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +0 -131
  59. data/.github/skills/release-management/SKILL.md +0 -125
  60. data/.github/skills/resolve-feedback/SKILL.md +0 -288
  61. data/.github/skills/review-arguments-dsl/CHECKLIST.md +0 -788
  62. data/.github/skills/review-arguments-dsl/SKILL.md +0 -214
  63. data/.github/skills/review-cross-command-consistency/SKILL.md +0 -139
  64. data/.github/skills/reviewing-skills/SKILL.md +0 -214
  65. data/.github/skills/rspec-unit-testing-standards/SKILL.md +0 -685
  66. data/.github/skills/tdd-refactor-step/SKILL.md +0 -236
  67. data/.github/skills/test-debugging/SKILL.md +0 -161
  68. data/.github/skills/yard-documentation/SKILL.md +0 -981
  69. data/.github/skills/yard-documentation/element-rules.md +0 -162
  70. data/.github/skills-deprecated/README.md +0 -21
  71. data/.github/skills-deprecated/extract-command-from-lib/SKILL.md +0 -487
  72. data/.github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -22
  73. data/.github/skills-deprecated/extract-facade-from-base-lib/SKILL.md +0 -600
  74. data/.github/skills-deprecated/review-backward-compatibility/SKILL.md +0 -275
  75. data/.github/workflows/continuous_integration.yml +0 -358
  76. data/.github/workflows/enforce_conventional_commits.yml +0 -35
  77. data/.github/workflows/experimental_continuous_integration.yml +0 -59
  78. data/.github/workflows/release.yml +0 -52
  79. data/.github/workflows/warm_bundler_caches.yml +0 -82
  80. data/.gitignore +0 -30
  81. data/.husky/commit-msg +0 -1
  82. data/.husky/pre-commit +0 -13
  83. data/.release-please-config.json +0 -36
  84. data/.release-please-manifest.json +0 -3
  85. data/.rspec +0 -2
  86. data/.rubocop.yml +0 -44
  87. data/.rubocop_todo.yml +0 -30
  88. data/.yard-lint.yml +0 -75
  89. data/CLAUDE.md +0 -11
  90. data/Gemfile +0 -22
  91. data/Rakefile +0 -41
  92. data/docker/test/Dockerfile +0 -32
  93. data/docker/test/docker-compose.yml +0 -0
  94. data/package.json +0 -10
  95. data/redesign/1_architecture_existing.md +0 -102
  96. data/redesign/2_architecture_redesign.md +0 -449
  97. data/redesign/3_architecture_implementation.md +0 -1623
  98. data/redesign/Phase 4 - Step A.md +0 -366
  99. data/redesign/Phase 4 - Step B.md +0 -921
  100. data/redesign/Phase 4 - Step C.md +0 -833
  101. data/redesign/beta_release.md +0 -107
  102. data/redesign/branch_parse_refactor_plan.md +0 -163
  103. data/redesign/c1a-public-api-scope.tsv +0 -256
  104. data/redesign/c1c2_audit.md +0 -566
  105. data/redesign/c1c2_bucket6_lib_orphans.md +0 -626
  106. data/redesign/config_design.rb +0 -501
  107. data/redesign/index.md +0 -34
  108. data/redesign/info_object_migration_plan.md +0 -126
  109. data/redesign/integration_test_analysis.md +0 -521
  110. data/redesign/phase-4-step-b-test-audit.tsv +0 -485
  111. data/redesign/remote_refactor_plan.md +0 -164
  112. data/redesign/reverse_dependencies.sql +0 -44
  113. data/tasks/gem_tasks.rake +0 -14
  114. data/tasks/npm_tasks.rake +0 -7
  115. data/tasks/rspec.rake +0 -111
  116. data/tasks/rubocop.rake +0 -5
  117. data/tasks/test_gem.rake +0 -12
  118. data/tasks/yard.rake +0 -57
data/lib/git/branch.rb CHANGED
@@ -17,6 +17,17 @@ module Git
17
17
  # @example Listing branches
18
18
  # git.branches.each { |b| puts b.name }
19
19
  #
20
+ # @deprecated Use {Git::Repository::Branching#branch_list} and the
21
+ # name-based branch operations on {Git::Repository} instead
22
+ #
23
+ # {Git::Repository::Branching#branch_list} returns immutable
24
+ # {Git::BranchInfo} value objects. Operations that lived on this class are
25
+ # called on the repository with the branch name instead (for example
26
+ # {Git::Repository::Branching#checkout} and
27
+ # {Git::Repository::Branching#branch_delete}). Every operation on a
28
+ # `Git::Branch` emits a deprecation warning; the `full`, `name`, `remote`,
29
+ # `to_s`, and `to_a` readers do not.
30
+ #
20
31
  # @api public
21
32
  #
22
33
  class Branch
@@ -94,13 +105,31 @@ module Git
94
105
  #
95
106
  # @return [Git::Object] the commit at the tip of this branch
96
107
  #
108
+ # @deprecated Use {Git::Repository::ObjectOperations#gcommit} with the branch name instead
109
+ #
110
+ # Pass the branch name for a local branch, or `"remotes/#{remote}/#{name}"`
111
+ # (the value of {#full}) for a remote-tracking branch; the shorter
112
+ # `"#{remote}/#{name}"` can resolve a local branch of that name.
113
+ #
114
+ # @see Git::Repository::ObjectOperations#gcommit
115
+ #
97
116
  def gcommit
117
+ Git::Deprecation.warn(
118
+ 'Git::Branch#gcommit is deprecated and will be removed in v6.0.0. ' \
119
+ 'Use Git::Repository#gcommit(name) or, for a remote-tracking branch, ' \
120
+ 'Git::Repository#gcommit("remotes/remote/name") instead.'
121
+ )
98
122
  @gcommit ||= branch_repository.gcommit(@full)
99
123
  @gcommit
100
124
  end
101
125
 
102
126
  # Returns the stash list for this repository
103
127
  #
128
+ # This method ignores the branch receiver and returns every stash in the
129
+ # repository, so `git.branch('feature').stashes` and
130
+ # `git.branch('main').stashes` return the same entries. It is deprecated and
131
+ # will be removed in v6.0.0.
132
+ #
104
133
  # The result is memoized after the first call.
105
134
  #
106
135
  # @example Iterate over stash entries
@@ -108,7 +137,16 @@ module Git
108
137
  #
109
138
  # @return [Git::Stashes] the stash list
110
139
  #
140
+ # @deprecated Use {Git::Repository#stashes_all} instead
141
+ #
142
+ # @see Git::Repository#stashes_all
143
+ #
111
144
  def stashes
145
+ Git::Deprecation.warn(
146
+ 'Git::Branch#stashes is deprecated and will be removed in v6.0.0. ' \
147
+ 'It ignores the branch and returns all repository stashes. ' \
148
+ 'Use Git::Repository#stashes_all instead.'
149
+ )
112
150
  @stashes ||= Git::Stashes.new(branch_repository)
113
151
  end
114
152
 
@@ -131,7 +169,30 @@ module Git
131
169
  #
132
170
  # @raise [Git::FailedError] if git exits with a non-zero exit status
133
171
  #
172
+ # @deprecated Use {Git::Repository::Branching#checkout} with the branch name instead
173
+ #
174
+ # {Git::Repository::Branching#checkout} does not create a missing local
175
+ # branch, apart from the guess git makes on its own: with no `:no_guess`
176
+ # option, git creates a tracking branch when exactly one remote has a
177
+ # branch of that name. To reproduce the create-or-checkout behavior of
178
+ # this method, call {Git::Repository::Branching#branch_new} when
179
+ # {Git::Repository::Branching#local_branch?} is false, then
180
+ # {Git::Repository::Branching#checkout}. Pass `"remotes/#{remote}/#{name}"`
181
+ # (the value of {#full}) for a remote-tracking branch; the shorter
182
+ # `"#{remote}/#{name}"` can resolve a local branch of that name.
183
+ #
184
+ # @see Git::Repository::Branching#checkout
185
+ #
186
+ # @see Git::Repository::Branching#branch_new
187
+ #
134
188
  def checkout
189
+ Git::Deprecation.warn(
190
+ 'Git::Branch#checkout is deprecated and will be removed in v6.0.0. ' \
191
+ 'Use Git::Repository#checkout(name) or, for a remote-tracking branch, ' \
192
+ 'Git::Repository#checkout("remotes/remote/name") instead. Git::Repository#checkout does not ' \
193
+ 'create a missing local branch (beyond the guess git makes from a unique remote-tracking ' \
194
+ 'branch); call Git::Repository#branch_new first unless Git::Repository#local_branch? is true.'
195
+ )
135
196
  check_if_create
136
197
  branch_repository.checkout(@full)
137
198
  end
@@ -172,7 +233,20 @@ module Git
172
233
  #
173
234
  # @raise [Git::FailedError] if `git archive` fails
174
235
  #
236
+ # @deprecated Use {Git::Repository::ObjectOperations#archive} with the branch name instead
237
+ #
238
+ # Pass the branch name for a local branch, or `"remotes/#{remote}/#{name}"`
239
+ # (the value of {#full}) for a remote-tracking branch; the shorter
240
+ # `"#{remote}/#{name}"` can resolve a local branch of that name.
241
+ #
242
+ # @see Git::Repository::ObjectOperations#archive
243
+ #
175
244
  def archive(file, opts = {})
245
+ Git::Deprecation.warn(
246
+ 'Git::Branch#archive is deprecated and will be removed in v6.0.0. ' \
247
+ 'Use Git::Repository#archive(name, file, opts) or, for a remote-tracking branch, ' \
248
+ 'Git::Repository#archive("remotes/remote/name", file, opts) instead.'
249
+ )
176
250
  branch_repository.archive(@full, file, opts)
177
251
  end
178
252
 
@@ -203,14 +277,27 @@ module Git
203
277
  #
204
278
  # @yieldreturn [Object] return a truthy value to commit all changes, a falsy value to hard-reset
205
279
  #
280
+ # @deprecated Use {Git::Repository::Branching#in_branch} with the branch name instead
281
+ #
282
+ # {Git::Repository::Branching#in_branch} does not create the branch and
283
+ # restores a detached HEAD to its original commit.
284
+ # It takes an existing local branch, so a remote-tracking `Git::Branch` has
285
+ # no direct replacement: this method checked out the remote-tracking ref,
286
+ # detaching HEAD. Create a local branch from that ref with
287
+ # {Git::Repository::Branching#branch_new} first.
288
+ #
289
+ # @see Git::Repository::Branching#in_branch
290
+ #
206
291
  def in_branch(message = 'in branch work')
292
+ Git::Deprecation.warn(
293
+ 'Git::Branch#in_branch is deprecated and will be removed in v6.0.0. ' \
294
+ 'Use Git::Repository#in_branch(name, message) instead. It takes an existing local ' \
295
+ 'branch; for a remote-tracking branch, create a local branch from it first.'
296
+ )
207
297
  old_current = branch_repository.current_branch
208
- checkout
209
- if yield
210
- branch_repository.commit_all(message)
211
- else
212
- branch_repository.reset(nil, hard: true)
213
- end
298
+ # checkout is deprecated too; silence it so one in_branch call emits one warning
299
+ Git::Deprecation.silence { checkout }
300
+ yield ? branch_repository.commit_all(message) : branch_repository.reset(nil, hard: true)
214
301
  branch_repository.checkout(old_current)
215
302
  end
216
303
 
@@ -224,7 +311,18 @@ module Git
224
311
  #
225
312
  # @return [nil]
226
313
  #
314
+ # @deprecated Use {Git::Repository::Branching#branch_new} instead
315
+ #
316
+ # {Git::Repository::Branching#branch_new} raises {Git::FailedError} when
317
+ # the branch already exists rather than ignoring the error.
318
+ #
319
+ # @see Git::Repository::Branching#branch_new
320
+ #
227
321
  def create
322
+ Git::Deprecation.warn(
323
+ 'Git::Branch#create is deprecated and will be removed in v6.0.0. ' \
324
+ 'Use Git::Repository#branch_new instead.'
325
+ )
228
326
  check_if_create
229
327
  end
230
328
 
@@ -240,7 +338,19 @@ module Git
240
338
  #
241
339
  # @raise [Git::Error] if the branch cannot be deleted
242
340
  #
341
+ # @deprecated Use {Git::Repository::Branching#branch_delete} instead
342
+ #
343
+ # Pass the branch name for a local branch, or `"#{remote}/#{name}"` with
344
+ # `remotes: true` for a remote-tracking branch.
345
+ #
346
+ # @see Git::Repository::Branching#branch_delete
347
+ #
243
348
  def delete
349
+ Git::Deprecation.warn(
350
+ 'Git::Branch#delete is deprecated and will be removed in v6.0.0. ' \
351
+ 'Use Git::Repository#branch_delete(name) or, for a remote-tracking branch, ' \
352
+ 'Git::Repository#branch_delete("remote/name", remotes: true) instead.'
353
+ )
244
354
  if @remote
245
355
  branch_repository.branch_delete("#{@remote.name}/#{@name}", remotes: true)
246
356
  else
@@ -263,7 +373,16 @@ module Git
263
373
  #
264
374
  # @raise [Git::FailedError] if git exits with a non-zero exit status
265
375
  #
376
+ # @deprecated Compare {Git::Repository::Branching#current_branch} with the
377
+ # branch name instead
378
+ #
379
+ # @see Git::Repository::Branching#current_branch
380
+ #
266
381
  def current # rubocop:disable Naming/PredicateMethod
382
+ Git::Deprecation.warn(
383
+ 'Git::Branch#current is deprecated and will be removed in v6.0.0. ' \
384
+ 'Use Git::Repository#current_branch == name instead.'
385
+ )
267
386
  branch_repository.current_branch == @name
268
387
  end
269
388
 
@@ -283,7 +402,19 @@ module Git
283
402
  #
284
403
  # @raise [Git::FailedError] if git exits with a non-zero exit status
285
404
  #
405
+ # @deprecated Use {Git::Repository::Branching#branch_contains} with the
406
+ # commit and branch name instead
407
+ #
408
+ # {Git::Repository::Branching#branch_contains} returns the matching
409
+ # branch names as a String; test it with `empty?`.
410
+ #
411
+ # @see Git::Repository::Branching#branch_contains
412
+ #
286
413
  def contains?(commit)
414
+ Git::Deprecation.warn(
415
+ 'Git::Branch#contains? is deprecated and will be removed in v6.0.0. ' \
416
+ 'Use !Git::Repository#branch_contains(commit, name).empty? instead.'
417
+ )
287
418
  !branch_repository.branch_contains(commit, name).empty?
288
419
  end
289
420
 
@@ -318,16 +449,27 @@ module Git
318
449
  #
319
450
  # @raise [Git::FailedError] if git exits with a non-zero exit status
320
451
  #
452
+ # @deprecated Use {Git::Repository::Merging#merge_into} in place of
453
+ # `merge(branch)` and {Git::Repository::Merging#merge} with the branch
454
+ # name in place of `merge()`
455
+ #
456
+ # {Git::Repository::Merging#merge_into} returns the merge's stdout, does
457
+ # not hard-reset after the merge, and restores a detached HEAD to its
458
+ # original commit.
459
+ # It takes an existing local branch, so a remote-tracking `Git::Branch` has
460
+ # no direct replacement: `merge(branch)` checked out the remote-tracking ref,
461
+ # detaching HEAD. Create a local branch from that ref with
462
+ # {Git::Repository::Branching#branch_new} first.
463
+ #
464
+ # @see Git::Repository::Merging#merge_into
465
+ #
466
+ # @see Git::Repository::Merging#merge
467
+ #
321
468
  def merge(branch = nil, message = nil)
322
469
  if branch
323
- in_branch do
324
- branch_repository.merge(branch, message)
325
- false
326
- end
327
- # merge a branch into this one
470
+ merge_into_this_branch(branch, message)
328
471
  else
329
- # merge this branch into the current one
330
- branch_repository.merge(@name)
472
+ merge_into_current_branch
331
473
  end
332
474
  end
333
475
 
@@ -351,7 +493,19 @@ module Git
351
493
  #
352
494
  # @raise [Git::FailedError] if git exits with a non-zero exit status
353
495
  #
496
+ # @deprecated Use {Git::Repository::Branching#update_ref} instead
497
+ #
498
+ # Pass the branch name for a local branch, or
499
+ # `"remotes/#{remote}/#{name}"` for a remote-tracking branch.
500
+ #
501
+ # @see Git::Repository::Branching#update_ref
502
+ #
354
503
  def update_ref(commit)
504
+ Git::Deprecation.warn(
505
+ 'Git::Branch#update_ref is deprecated and will be removed in v6.0.0. ' \
506
+ 'Use Git::Repository#update_ref(name, commit) or, for a remote-tracking branch, ' \
507
+ 'Git::Repository#update_ref("remotes/remote/name", commit) instead.'
508
+ )
355
509
  if @remote
356
510
  branch_repository.update_ref("remotes/#{@remote.name}/#{@name}", commit)
357
511
  else
@@ -429,7 +583,9 @@ module Git
429
583
  #
430
584
  def initialize_from_branch_info(branch_info)
431
585
  @name = branch_info.short_name
432
- @remote = branch_info.remote_name ? Git::Remote.new(@base, branch_info.remote_name) : nil
586
+ remote_name = branch_info.remote_name
587
+ # Git::Remote is deprecated too; silence it so one Git::Branch call emits one warning
588
+ @remote = remote_name ? Git::Deprecation.silence { Git::Remote.new(@base, remote_name) } : nil
433
589
  @full = @remote ? "remotes/#{@remote.name}/#{@name}" : @name
434
590
  end
435
591
 
@@ -468,11 +624,50 @@ module Git
468
624
  def parse_name(name)
469
625
  # Expect this will always match
470
626
  match = name.match(BRANCH_NAME_REGEXP)
471
- remote = match[:remote_name] ? Git::Remote.new(@base, match[:remote_name]) : nil
627
+ remote_name = match[:remote_name]
628
+ # Git::Remote is deprecated too; silence it so one Git::Branch call emits one warning
629
+ remote = remote_name ? Git::Deprecation.silence { Git::Remote.new(@base, remote_name) } : nil
472
630
  branch_name = match[:branch_name]
473
631
  [remote, branch_name]
474
632
  end
475
633
 
634
+ # Merges the given branch into this branch, then restores the original branch
635
+ #
636
+ # @param branch [String] the name of the branch to merge into this one
637
+ #
638
+ # @param message [String, nil] commit message for the merge commit
639
+ #
640
+ # @return [String] git's stdout from the final checkout back to the original branch
641
+ #
642
+ # @api private
643
+ #
644
+ def merge_into_this_branch(branch, message)
645
+ Git::Deprecation.warn(
646
+ 'Git::Branch#merge(branch) is deprecated and will be removed in v6.0.0. ' \
647
+ 'Use Git::Repository#merge_into(name, branch, message) instead. It takes an existing ' \
648
+ 'local branch; for a remote-tracking branch, create a local branch from it first.'
649
+ )
650
+ # in_branch is deprecated too; silence it so one merge call emits one warning.
651
+ # The falsy block value makes in_branch hard-reset instead of committing.
652
+ Git::Deprecation.silence do
653
+ in_branch { branch_repository.merge(branch, message) && false }
654
+ end
655
+ end
656
+
657
+ # Merges this branch into the currently checked-out branch
658
+ #
659
+ # @return [String] git's stdout from the merge command
660
+ #
661
+ # @api private
662
+ #
663
+ def merge_into_current_branch
664
+ Git::Deprecation.warn(
665
+ 'Git::Branch#merge with no arguments is deprecated and will be removed in v6.0.0. ' \
666
+ 'Use Git::Repository#merge(name) instead.'
667
+ )
668
+ branch_repository.merge(@name)
669
+ end
670
+
476
671
  # Creates the branch if it does not already exist, ignoring errors
477
672
  #
478
673
  # @return [nil]
@@ -70,7 +70,7 @@ module Git
70
70
  # info.remote_name #=> 'origin'
71
71
  # info.short_name #=> 'main'
72
72
  #
73
- # @see Git::Branch for the full-featured branch object with operations
73
+ # @see Git::Repository::Branching#branch_list for the repository method that returns these
74
74
  #
75
75
  # @see Git::Commands::Branch::List for the command that produces these
76
76
  #
data/lib/git/branches.rb CHANGED
@@ -10,6 +10,14 @@ module Git
10
10
  # branches = repo.branches
11
11
  # branches.each { |b| puts b.name }
12
12
  #
13
+ # @deprecated Use {Git::Repository::Branching#branch_list} instead
14
+ #
15
+ # {Git::Repository::Branching#branch_list} returns `Array<Git::BranchInfo>`
16
+ # (immutable value objects). Filter it with `select(&:remote?)` or
17
+ # `reject(&:remote?)` in place of {#remote} and {#local}, and look a
18
+ # branch up by name with `branch_list(name).first` in place of {#[]}.
19
+ # Constructing a `Git::Branches` emits a deprecation warning.
20
+ #
13
21
  # @api public
14
22
  #
15
23
  class Branches
@@ -24,18 +32,21 @@ module Git
24
32
  #
25
33
  # @raise [Git::FailedError] if git exits with a non-zero exit status
26
34
  #
35
+ # @deprecated Use {Git::Repository::Branching#branch_list} instead
36
+ #
37
+ # @see Git::Repository::Branching#branch_list
38
+ #
27
39
  def initialize(base)
40
+ Git::Deprecation.warn(
41
+ 'Git::Branches is deprecated and will be removed in v6.0.0. ' \
42
+ 'Use Git::Repository#branch_list instead.'
43
+ )
28
44
  @branches = {}
29
45
  @lookup = {}
30
46
 
31
47
  @base = base
32
48
 
33
- branch_repository.branch_list.each do |branch_info|
34
- branch = Git::Branch.new(base, branch_info)
35
-
36
- @branches[branch_info.refname] = branch
37
- index_branch_lookup(branch, refname: branch_info.refname)
38
- end
49
+ load_branches
39
50
  end
40
51
 
41
52
  # Returns all local (non-remote-tracking) branches
@@ -127,13 +138,30 @@ module Git
127
138
  def to_s
128
139
  out = +''
129
140
  @branches.each_value do |b|
130
- out << (b.current ? '* ' : ' ') << b.to_s << "\n"
141
+ # Git::Branch#current is deprecated too; silence it so one to_s call emits one warning
142
+ current = Git::Deprecation.silence { b.current }
143
+ out << (current ? '* ' : ' ') << b.to_s << "\n"
131
144
  end
132
145
  out
133
146
  end
134
147
 
135
148
  private
136
149
 
150
+ # Builds a Git::Branch for every branch in the repository and indexes it
151
+ #
152
+ # @return [void]
153
+ #
154
+ # @api private
155
+ #
156
+ def load_branches
157
+ branch_repository.branch_list.each do |branch_info|
158
+ branch = Git::Branch.new(@base, branch_info)
159
+
160
+ @branches[branch_info.refname] = branch
161
+ index_branch_lookup(branch, refname: branch_info.refname)
162
+ end
163
+ end
164
+
137
165
  # @return [Git::Repository] the repository used to enumerate branches
138
166
  #
139
167
  # @api private
@@ -232,7 +232,7 @@ module Git
232
232
  #
233
233
  # @api private
234
234
  #
235
- # rubocop:disable Metrics/ParameterLists
235
+ # rubocop:disable-next Metrics/ParameterLists
236
236
  def command_line_result(command, result, processed_out, processed_err, timeout, raise_on_failure)
237
237
  Git::CommandLine::Result.new(command, result, processed_out, processed_err).tap do |processed_result|
238
238
  raise Git::TimeoutError.new(processed_result, timeout) if result.timed_out?
@@ -242,7 +242,6 @@ module Git
242
242
  raise Git::FailedError, processed_result if raise_on_failure && !result.success?
243
243
  end
244
244
  end
245
- # rubocop:enable Metrics/ParameterLists
246
245
  end
247
246
  end
248
247
  end
@@ -453,7 +453,7 @@ module Git
453
453
  #
454
454
  # @example Feed bound object names to a git batch command
455
455
  # bound = args_definition.bind(*args, **kwargs)
456
- # stdin_content = Array(bound.objects).map { |object| "#{object}\n" }.join
456
+ # stdin_content = Array(bound.object).map { |object| "#{object}\n" }.join
457
457
  # with_stdin(stdin_content) do |reader|
458
458
  # @execution_context.command_capturing('cat-file', '--batch-check', in: reader, raise_on_failure: false)
459
459
  # end
@@ -49,9 +49,12 @@ module Git
49
49
  # See https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt--s
50
50
  flag_option :s
51
51
 
52
- # Allow -t and -s to query broken or corrupt objects of unknown type;
53
- # rejected by git in any other mode enforced by constraint below
54
- # See https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt---allow-unknown-type
52
+ # Allow -t and -s to query broken or corrupt objects of unknown type.
53
+ # Deprecated and removed in v6.0.0 (see issue 1709); passing it emits a
54
+ # deprecation warning. Git 2.28-2.49 honors it with -t and -s and rejects
55
+ # it in other modes; git 2.50+ accepts and ignores it everywhere (the
56
+ # unknown-type feature was removed).
57
+ # See https://git-scm.com/docs/git-cat-file/2.49.0#Documentation/git-cat-file.txt---allow-unknown-type
55
58
  flag_option :allow_unknown_type
56
59
 
57
60
  # Map committer/author identities through the mailmap before reporting size
@@ -74,8 +77,6 @@ module Git
74
77
 
75
78
  # Object name: SHA, ref, `HEAD`, treeish path reference, etc.
76
79
  operand :object, required: true
77
-
78
- requires_one_of :t, :s, when: :allow_unknown_type
79
80
  end
80
81
 
81
82
  # Execute `git cat-file` for a single object.
@@ -92,6 +93,13 @@ module Git
92
93
  #
93
94
  # @param options [Hash] command options
94
95
  #
96
+ # @option options [Boolean, nil] :allow_unknown_type (nil) pass `--allow-unknown-type` through to git,
97
+ # which rejects it in this mode on git 2.28-2.49 and accepts it as a no-op
98
+ # on git 2.50 and later
99
+ #
100
+ # Deprecated and removed in v6.0.0; passing it emits a deprecation
101
+ # warning.
102
+ #
95
103
  # @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
96
104
  #
97
105
  # @option options [Boolean, nil] :no_use_mailmap (nil) suppress mailmap remapping (`--no-use-mailmap`)
@@ -114,7 +122,11 @@ module Git
114
122
  # @param options [Hash] command options
115
123
  #
116
124
  # @option options [Boolean, nil] :allow_unknown_type (nil) allow querying broken or corrupt objects of
117
- # unknown type
125
+ # unknown type on git 2.28-2.49
126
+ #
127
+ # Deprecated and removed in v6.0.0; passing it emits a deprecation
128
+ # warning. Git 2.50 removed the unknown-type feature and accepts this
129
+ # flag as a no-op.
118
130
  #
119
131
  # @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
120
132
  #
@@ -138,7 +150,11 @@ module Git
138
150
  # @param options [Hash] command options
139
151
  #
140
152
  # @option options [Boolean, nil] :allow_unknown_type (nil) allow querying broken or corrupt objects of
141
- # unknown type
153
+ # unknown type on git 2.28-2.49
154
+ #
155
+ # Deprecated and removed in v6.0.0; passing it emits a deprecation
156
+ # warning. Git 2.50 removed the unknown-type feature and accepts this
157
+ # flag as a no-op.
142
158
  #
143
159
  # @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
144
160
  #
@@ -161,6 +177,13 @@ module Git
161
177
  #
162
178
  # @param options [Hash] command options
163
179
  #
180
+ # @option options [Boolean, nil] :allow_unknown_type (nil) pass `--allow-unknown-type` through to git,
181
+ # which rejects it in this mode on git 2.28-2.49 and accepts it as a no-op
182
+ # on git 2.50 and later
183
+ #
184
+ # Deprecated and removed in v6.0.0; passing it emits a deprecation
185
+ # warning.
186
+ #
164
187
  # @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
165
188
  #
166
189
  # @option options [Boolean, nil] :no_use_mailmap (nil) suppress mailmap remapping (`--no-use-mailmap`)
@@ -182,6 +205,13 @@ module Git
182
205
  #
183
206
  # @param options [Hash] command options
184
207
  #
208
+ # @option options [Boolean, nil] :allow_unknown_type (nil) pass `--allow-unknown-type` through to git,
209
+ # which rejects it in this mode on git 2.28-2.49 and accepts it as a no-op
210
+ # on git 2.50 and later
211
+ #
212
+ # Deprecated and removed in v6.0.0; passing it emits a deprecation
213
+ # warning.
214
+ #
185
215
  # @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
186
216
  #
187
217
  # @option options [Boolean, nil] :no_use_mailmap (nil) suppress mailmap remapping (`--no-use-mailmap`)
@@ -198,6 +228,7 @@ module Git
198
228
  # @option options [Numeric, nil] :timeout (nil) abort the command after this many seconds
199
229
  #
200
230
  def call(*, **)
231
+ warn_allow_unknown_type_deprecated(**)
201
232
  bound = args_definition.bind(*, **)
202
233
  validate_version!(bound.execution_options)
203
234
  result = execute_command(bound)
@@ -210,6 +241,30 @@ module Git
210
241
 
211
242
  result
212
243
  end
244
+
245
+ private
246
+
247
+ # Emit the deprecation warning when the `allow_unknown_type` keyword is passed
248
+ #
249
+ # Keys on the keyword being present, whatever its value: `false` and `nil`
250
+ # suppress the flag but still name a deprecated option.
251
+ #
252
+ # @param options [Hash] the keyword arguments passed to {#call}
253
+ #
254
+ # @option options [Boolean, nil] :allow_unknown_type the deprecated option;
255
+ # any value, including `false` and `nil`, triggers the warning
256
+ #
257
+ # @return [void]
258
+ #
259
+ def warn_allow_unknown_type_deprecated(**options)
260
+ return unless options.key?(:allow_unknown_type)
261
+
262
+ Git::Deprecation.warn(
263
+ 'The allow_unknown_type option of Git::Commands::CatFile::Raw is deprecated ' \
264
+ 'and will be removed in v6.0.0. Git 2.50 removed the unknown-type feature ' \
265
+ 'and accepts --allow-unknown-type as a no-op.'
266
+ )
267
+ end
213
268
  end
214
269
  end
215
270
  end
data/lib/git/object.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'git/author'
3
+ require 'git/author_info'
4
4
  require 'git/diff'
5
5
  require 'git/errors'
6
6
  require 'git/log'
@@ -438,7 +438,10 @@ module Git
438
438
  @parents
439
439
  end
440
440
 
441
- # git author
441
+ # Returns the commit author identity
442
+ #
443
+ # @return [Git::AuthorInfo] the author name, email, and author date
444
+ #
442
445
  def author
443
446
  check_commit
444
447
  @author
@@ -452,7 +455,10 @@ module Git
452
455
  author.date
453
456
  end
454
457
 
455
- # git author
458
+ # Returns the commit committer identity
459
+ #
460
+ # @return [Git::AuthorInfo] the committer name, email, and commit date
461
+ #
456
462
  def committer
457
463
  check_commit
458
464
  @committer
@@ -499,8 +505,8 @@ module Git
499
505
  #
500
506
  def from_data(data)
501
507
  @sha ||= data['sha']
502
- @committer = Git::Author.new(data['committer'])
503
- @author = Git::Author.new(data['author'])
508
+ @committer = Git::AuthorInfo.parse(data['committer'])
509
+ @author = Git::AuthorInfo.parse(data['author'])
504
510
  @tree = Git::Object::Tree.new(@base, data['tree'])
505
511
  @parents = data['parent'].map { |sha| Git::Object::Commit.new(@base, sha) }
506
512
  @message = data['message'].chomp
@@ -593,7 +599,7 @@ module Git
593
599
 
594
600
  # Returns the tagger identity
595
601
  #
596
- # @return [Git::Author, nil] the tagger for an annotated tag, or `nil`
602
+ # @return [Git::AuthorInfo, nil] the tagger for an annotated tag, or `nil`
597
603
  # for a lightweight tag
598
604
  #
599
605
  def tagger
@@ -613,7 +619,7 @@ module Git
613
619
  if annotated?
614
620
  tdata = object_repository.cat_file_tag(@name)
615
621
  @message = tdata['message'].chomp
616
- @tagger = Git::Author.new(tdata['tagger'])
622
+ @tagger = Git::AuthorInfo.parse(tdata['tagger'])
617
623
  else
618
624
  @message = @tagger = nil
619
625
  end