git 5.1.0 → 5.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +185 -165
- data/LICENSE +1 -1
- data/README.md +151 -151
- data/git.gemspec +35 -3
- data/lib/git/command_line/base.rb +1 -2
- data/lib/git/commands/base.rb +1 -1
- data/lib/git/commands/cat_file/raw.rb +8 -7
- data/lib/git/repository/branching.rb +79 -5
- data/lib/git/version.rb +1 -1
- metadata +5 -94
- data/.claude/commands/address-copilot-reviews.md +0 -14
- data/.claude/settings.json +0 -16
- data/.claude/skills +0 -1
- data/.commitlintrc.yml +0 -38
- data/.dockerignore +0 -27
- data/.github/copilot-instructions.md +0 -30
- data/.github/hooks/bin-setup-on-worktree.json +0 -11
- data/.github/hooks/run-bin-setup-once.sh +0 -20
- data/.github/issue_template.md +0 -15
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +0 -188
- data/.github/pull_request_template.md +0 -21
- data/.github/skills/breaking-change-analysis/SKILL.md +0 -99
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +0 -264
- data/.github/skills/command-implementation/REFERENCE.md +0 -994
- data/.github/skills/command-implementation/SKILL.md +0 -230
- data/.github/skills/command-test-conventions/SKILL.md +0 -664
- data/.github/skills/command-yard-documentation/SKILL.md +0 -434
- data/.github/skills/dependency-management/SKILL.md +0 -72
- data/.github/skills/development-workflow/SKILL.md +0 -512
- data/.github/skills/facade-implementation/REFERENCE.md +0 -837
- data/.github/skills/facade-implementation/SKILL.md +0 -269
- data/.github/skills/facade-test-conventions/SKILL.md +0 -391
- data/.github/skills/facade-yard-documentation/SKILL.md +0 -435
- data/.github/skills/make-skill-template/SKILL.md +0 -226
- data/.github/skills/pr-readiness-review/SKILL.md +0 -205
- data/.github/skills/project-context/SKILL.md +0 -306
- data/.github/skills/pull-request-review/SKILL.md +0 -168
- data/.github/skills/rebase/SKILL.md +0 -148
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +0 -131
- data/.github/skills/release-management/SKILL.md +0 -125
- data/.github/skills/resolve-feedback/SKILL.md +0 -288
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +0 -788
- data/.github/skills/review-arguments-dsl/SKILL.md +0 -214
- data/.github/skills/review-cross-command-consistency/SKILL.md +0 -139
- data/.github/skills/reviewing-skills/SKILL.md +0 -214
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +0 -685
- data/.github/skills/tdd-refactor-step/SKILL.md +0 -236
- data/.github/skills/test-debugging/SKILL.md +0 -161
- data/.github/skills/yard-documentation/SKILL.md +0 -981
- data/.github/skills/yard-documentation/element-rules.md +0 -162
- data/.github/skills-deprecated/README.md +0 -21
- data/.github/skills-deprecated/extract-command-from-lib/SKILL.md +0 -487
- data/.github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -22
- data/.github/skills-deprecated/extract-facade-from-base-lib/SKILL.md +0 -600
- data/.github/skills-deprecated/review-backward-compatibility/SKILL.md +0 -275
- data/.github/workflows/continuous_integration.yml +0 -358
- data/.github/workflows/enforce_conventional_commits.yml +0 -35
- data/.github/workflows/experimental_continuous_integration.yml +0 -59
- data/.github/workflows/release.yml +0 -52
- data/.github/workflows/warm_bundler_caches.yml +0 -82
- data/.gitignore +0 -30
- data/.husky/commit-msg +0 -1
- data/.husky/pre-commit +0 -13
- data/.release-please-config.json +0 -36
- data/.release-please-manifest.json +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -44
- data/.rubocop_todo.yml +0 -30
- data/.yard-lint.yml +0 -75
- data/CLAUDE.md +0 -11
- data/Gemfile +0 -22
- data/Rakefile +0 -41
- data/docker/test/Dockerfile +0 -32
- data/docker/test/docker-compose.yml +0 -0
- data/package.json +0 -10
- data/redesign/1_architecture_existing.md +0 -102
- data/redesign/2_architecture_redesign.md +0 -449
- data/redesign/3_architecture_implementation.md +0 -1623
- data/redesign/Phase 4 - Step A.md +0 -366
- data/redesign/Phase 4 - Step B.md +0 -921
- data/redesign/Phase 4 - Step C.md +0 -833
- data/redesign/beta_release.md +0 -107
- data/redesign/branch_parse_refactor_plan.md +0 -163
- data/redesign/c1a-public-api-scope.tsv +0 -256
- data/redesign/c1c2_audit.md +0 -566
- data/redesign/c1c2_bucket6_lib_orphans.md +0 -626
- data/redesign/config_design.rb +0 -501
- data/redesign/index.md +0 -34
- data/redesign/info_object_migration_plan.md +0 -126
- data/redesign/integration_test_analysis.md +0 -521
- data/redesign/phase-4-step-b-test-audit.tsv +0 -485
- data/redesign/remote_refactor_plan.md +0 -164
- data/redesign/reverse_dependencies.sql +0 -44
- data/tasks/gem_tasks.rake +0 -14
- data/tasks/npm_tasks.rake +0 -7
- data/tasks/rspec.rake +0 -111
- data/tasks/rubocop.rake +0 -5
- data/tasks/test_gem.rake +0 -12
- data/tasks/yard.rake +0 -57
|
@@ -41,7 +41,7 @@ module Git
|
|
|
41
41
|
|
|
42
42
|
# Option keys accepted by {#checkout}
|
|
43
43
|
#
|
|
44
|
-
CHECKOUT_ALLOWED_OPTS = %i[force f new_branch b start_point].freeze
|
|
44
|
+
CHECKOUT_ALLOWED_OPTS = %i[force f new_branch b start_point orphan].freeze
|
|
45
45
|
private_constant :CHECKOUT_ALLOWED_OPTS
|
|
46
46
|
|
|
47
47
|
# Option keys accepted by {#checkout_index}
|
|
@@ -130,6 +130,9 @@ module Git
|
|
|
130
130
|
# @example Create a new branch with a name different from the start point
|
|
131
131
|
# repo.checkout('main', new_branch: 'new-feature')
|
|
132
132
|
#
|
|
133
|
+
# @example Create and check out an unborn branch with no history
|
|
134
|
+
# repo.checkout('gh-pages', orphan: true)
|
|
135
|
+
#
|
|
133
136
|
# @example Force checkout discarding local changes
|
|
134
137
|
# repo.checkout('main', force: true)
|
|
135
138
|
#
|
|
@@ -151,13 +154,25 @@ module Git
|
|
|
151
154
|
#
|
|
152
155
|
# @option opts [Boolean, nil] :f (nil) alias for `:force`
|
|
153
156
|
#
|
|
157
|
+
# @option opts [Boolean, String, nil] :orphan (nil) when `true`, creates a
|
|
158
|
+
# new unborn branch named `branch` whose first commit has no parents
|
|
159
|
+
#
|
|
160
|
+
# When a `String`, creates an unborn branch with that name, using
|
|
161
|
+
# `branch` as the start point for the working tree and index.
|
|
162
|
+
#
|
|
163
|
+
# `false` and `nil` are both treated as unset. A blank branch name is
|
|
164
|
+
# rejected rather than ignored.
|
|
165
|
+
#
|
|
154
166
|
# @option opts [String, nil] :start_point (nil) the commit or branch to
|
|
155
|
-
# start the new branch from; used together with `new_branch: true`
|
|
167
|
+
# start the new branch from; used together with `new_branch: true` or
|
|
168
|
+
# `orphan: true`
|
|
156
169
|
#
|
|
157
170
|
# @return [String] git's stdout from the checkout
|
|
158
171
|
#
|
|
159
172
|
# @raise [ArgumentError] if unsupported options are provided
|
|
160
173
|
#
|
|
174
|
+
# @raise [ArgumentError] if `:orphan` is given a blank or missing branch name
|
|
175
|
+
#
|
|
161
176
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
162
177
|
#
|
|
163
178
|
def checkout(branch = nil, opts = {})
|
|
@@ -680,19 +695,24 @@ module Git
|
|
|
680
695
|
:unborn
|
|
681
696
|
end
|
|
682
697
|
|
|
683
|
-
# Translates
|
|
698
|
+
# Translates {#checkout} options to the new command interface
|
|
684
699
|
#
|
|
685
700
|
# Legacy callers passed combinations like:
|
|
686
701
|
# checkout('branch', new_branch: true, start_point: 'main')
|
|
687
702
|
# which should map to:
|
|
688
703
|
# checkout('main', b: 'branch')
|
|
689
704
|
#
|
|
705
|
+
# `orphan: true` follows the same shape, naming the unborn branch:
|
|
706
|
+
# checkout('branch', orphan: true, start_point: 'main')
|
|
707
|
+
# maps to:
|
|
708
|
+
# checkout('main', orphan: 'branch')
|
|
709
|
+
#
|
|
690
710
|
# @param branch [String, nil] the branch argument passed to {#checkout}
|
|
691
711
|
#
|
|
692
712
|
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
693
713
|
#
|
|
694
|
-
# @return [Array] a two-element tuple
|
|
695
|
-
# translated checkout arguments
|
|
714
|
+
# @return [Array((String, nil), Hash)] a two-element tuple
|
|
715
|
+
# `[target, options]` containing the translated checkout arguments
|
|
696
716
|
#
|
|
697
717
|
# `target` (`String` or `nil`) is the branch or commit to check out.
|
|
698
718
|
# `options` is a `Hash` of keyword arguments for
|
|
@@ -701,15 +721,69 @@ module Git
|
|
|
701
721
|
# @api private
|
|
702
722
|
#
|
|
703
723
|
def translate_checkout_opts(branch, checkout_options)
|
|
724
|
+
checkout_options = normalize_orphan_option(checkout_options)
|
|
725
|
+
|
|
704
726
|
if checkout_options[:new_branch] == true || checkout_options[:b] == true
|
|
705
727
|
[checkout_options[:start_point], checkout_options.except(:new_branch, :b, :start_point).merge(b: branch)]
|
|
706
728
|
elsif checkout_options[:new_branch].is_a?(String)
|
|
707
729
|
[branch, checkout_options.except(:new_branch).merge(b: checkout_options[:new_branch])]
|
|
730
|
+
elsif checkout_options[:orphan] == true
|
|
731
|
+
translate_orphan_opts(branch, checkout_options)
|
|
708
732
|
else
|
|
709
733
|
[branch, checkout_options]
|
|
710
734
|
end
|
|
711
735
|
end
|
|
712
736
|
|
|
737
|
+
# Normalizes the `:orphan` option, rejecting names that git would never see
|
|
738
|
+
#
|
|
739
|
+
# `:orphan` is a value option on the underlying command, so a literal
|
|
740
|
+
# `false` would be emitted as `--orphan false` and create a branch named
|
|
741
|
+
# "false". Flag options such as `:force` already ignore `false`; this
|
|
742
|
+
# gives `:orphan` the same behavior.
|
|
743
|
+
#
|
|
744
|
+
# A blank name is rejected rather than dropped: the argument DSL omits
|
|
745
|
+
# empty values, so `orphan: ''` would otherwise degrade silently into a
|
|
746
|
+
# plain checkout.
|
|
747
|
+
#
|
|
748
|
+
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
749
|
+
#
|
|
750
|
+
# @return [Hash] the options with a `false` `:orphan` key removed
|
|
751
|
+
#
|
|
752
|
+
# @raise [ArgumentError] if `:orphan` is given a blank branch name
|
|
753
|
+
#
|
|
754
|
+
# @api private
|
|
755
|
+
#
|
|
756
|
+
def normalize_orphan_option(checkout_options)
|
|
757
|
+
orphan = checkout_options[:orphan]
|
|
758
|
+
return checkout_options.except(:orphan) if orphan == false
|
|
759
|
+
raise ArgumentError, 'orphan requires a non-empty branch name' if orphan.is_a?(String) && orphan.strip.empty?
|
|
760
|
+
|
|
761
|
+
checkout_options
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
# Translates `orphan: true` into the command's `:orphan` value option
|
|
765
|
+
#
|
|
766
|
+
# `orphan: true` names the unborn branch from the positional argument and
|
|
767
|
+
# takes its start point from `:start_point`, mirroring `new_branch: true`.
|
|
768
|
+
#
|
|
769
|
+
# @param branch [String, nil] the branch argument passed to {#checkout}
|
|
770
|
+
#
|
|
771
|
+
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
772
|
+
#
|
|
773
|
+
# @return [Array((String, nil), Hash)] a two-element tuple
|
|
774
|
+
# `[target, options]` containing the translated checkout arguments
|
|
775
|
+
#
|
|
776
|
+
# @raise [ArgumentError] if `branch` is blank (`nil`, empty, or whitespace
|
|
777
|
+
# only), since the unborn branch would otherwise have no name
|
|
778
|
+
#
|
|
779
|
+
# @api private
|
|
780
|
+
#
|
|
781
|
+
def translate_orphan_opts(branch, checkout_options)
|
|
782
|
+
raise ArgumentError, 'orphan: true requires a branch name' if branch.to_s.strip.empty?
|
|
783
|
+
|
|
784
|
+
[checkout_options[:start_point], checkout_options.except(:start_point).merge(orphan: branch)]
|
|
785
|
+
end
|
|
786
|
+
|
|
713
787
|
# Normalizes path specifications for Git commands
|
|
714
788
|
#
|
|
715
789
|
# @param pathspecs [String, Pathname, Array<String, Pathname>, nil]
|
data/lib/git/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Scott Chacon and others
|
|
@@ -43,14 +43,14 @@ dependencies:
|
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '4.
|
|
46
|
+
version: '4.1'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '4.
|
|
53
|
+
version: '4.1'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: rchardet
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -298,80 +298,16 @@ executables: []
|
|
|
298
298
|
extensions: []
|
|
299
299
|
extra_rdoc_files: []
|
|
300
300
|
files:
|
|
301
|
-
- ".claude/commands/address-copilot-reviews.md"
|
|
302
|
-
- ".claude/settings.json"
|
|
303
|
-
- ".claude/skills"
|
|
304
|
-
- ".commitlintrc.yml"
|
|
305
|
-
- ".dockerignore"
|
|
306
|
-
- ".github/copilot-instructions.md"
|
|
307
|
-
- ".github/hooks/bin-setup-on-worktree.json"
|
|
308
|
-
- ".github/hooks/run-bin-setup-once.sh"
|
|
309
|
-
- ".github/issue_template.md"
|
|
310
|
-
- ".github/prompts/iteratively-address-copilot-reviews.prompt.md"
|
|
311
|
-
- ".github/pull_request_template.md"
|
|
312
|
-
- ".github/skills-deprecated/README.md"
|
|
313
|
-
- ".github/skills-deprecated/extract-command-from-lib/SKILL.md"
|
|
314
|
-
- ".github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md"
|
|
315
|
-
- ".github/skills-deprecated/extract-facade-from-base-lib/SKILL.md"
|
|
316
|
-
- ".github/skills-deprecated/review-backward-compatibility/SKILL.md"
|
|
317
|
-
- ".github/skills/breaking-change-analysis/SKILL.md"
|
|
318
|
-
- ".github/skills/ci-cd-troubleshooting/SKILL.md"
|
|
319
|
-
- ".github/skills/command-implementation/REFERENCE.md"
|
|
320
|
-
- ".github/skills/command-implementation/SKILL.md"
|
|
321
|
-
- ".github/skills/command-test-conventions/SKILL.md"
|
|
322
|
-
- ".github/skills/command-yard-documentation/SKILL.md"
|
|
323
|
-
- ".github/skills/dependency-management/SKILL.md"
|
|
324
|
-
- ".github/skills/development-workflow/SKILL.md"
|
|
325
|
-
- ".github/skills/facade-implementation/REFERENCE.md"
|
|
326
|
-
- ".github/skills/facade-implementation/SKILL.md"
|
|
327
|
-
- ".github/skills/facade-test-conventions/SKILL.md"
|
|
328
|
-
- ".github/skills/facade-yard-documentation/SKILL.md"
|
|
329
|
-
- ".github/skills/make-skill-template/SKILL.md"
|
|
330
|
-
- ".github/skills/pr-readiness-review/SKILL.md"
|
|
331
|
-
- ".github/skills/project-context/SKILL.md"
|
|
332
|
-
- ".github/skills/pull-request-review/SKILL.md"
|
|
333
|
-
- ".github/skills/rebase/SKILL.md"
|
|
334
|
-
- ".github/skills/refactor-command-to-commandlineresult/SKILL.md"
|
|
335
|
-
- ".github/skills/release-management/SKILL.md"
|
|
336
|
-
- ".github/skills/resolve-feedback/SKILL.md"
|
|
337
|
-
- ".github/skills/review-arguments-dsl/CHECKLIST.md"
|
|
338
|
-
- ".github/skills/review-arguments-dsl/SKILL.md"
|
|
339
|
-
- ".github/skills/review-cross-command-consistency/SKILL.md"
|
|
340
|
-
- ".github/skills/reviewing-skills/SKILL.md"
|
|
341
|
-
- ".github/skills/rspec-unit-testing-standards/SKILL.md"
|
|
342
|
-
- ".github/skills/tdd-refactor-step/SKILL.md"
|
|
343
|
-
- ".github/skills/test-debugging/SKILL.md"
|
|
344
|
-
- ".github/skills/yard-documentation/SKILL.md"
|
|
345
|
-
- ".github/skills/yard-documentation/element-rules.md"
|
|
346
|
-
- ".github/workflows/continuous_integration.yml"
|
|
347
|
-
- ".github/workflows/enforce_conventional_commits.yml"
|
|
348
|
-
- ".github/workflows/experimental_continuous_integration.yml"
|
|
349
|
-
- ".github/workflows/release.yml"
|
|
350
|
-
- ".github/workflows/warm_bundler_caches.yml"
|
|
351
|
-
- ".gitignore"
|
|
352
|
-
- ".husky/commit-msg"
|
|
353
|
-
- ".husky/pre-commit"
|
|
354
|
-
- ".release-please-config.json"
|
|
355
|
-
- ".release-please-manifest.json"
|
|
356
|
-
- ".rspec"
|
|
357
|
-
- ".rubocop.yml"
|
|
358
|
-
- ".rubocop_todo.yml"
|
|
359
|
-
- ".yard-lint.yml"
|
|
360
301
|
- ".yardopts"
|
|
361
302
|
- AI_POLICY.md
|
|
362
303
|
- CHANGELOG.md
|
|
363
|
-
- CLAUDE.md
|
|
364
304
|
- CODE_OF_CONDUCT.md
|
|
365
305
|
- CONTRIBUTING.md
|
|
366
306
|
- GOVERNANCE.md
|
|
367
|
-
- Gemfile
|
|
368
307
|
- LICENSE
|
|
369
308
|
- MAINTAINERS.md
|
|
370
309
|
- README.md
|
|
371
|
-
- Rakefile
|
|
372
310
|
- UPGRADING.md
|
|
373
|
-
- docker/test/Dockerfile
|
|
374
|
-
- docker/test/docker-compose.yml
|
|
375
311
|
- git.gemspec
|
|
376
312
|
- lib/git.rb
|
|
377
313
|
- lib/git/author.rb
|
|
@@ -600,39 +536,14 @@ files:
|
|
|
600
536
|
- lib/git/version_constraint.rb
|
|
601
537
|
- lib/git/worktree.rb
|
|
602
538
|
- lib/git/worktrees.rb
|
|
603
|
-
- package.json
|
|
604
|
-
- redesign/1_architecture_existing.md
|
|
605
|
-
- redesign/2_architecture_redesign.md
|
|
606
|
-
- redesign/3_architecture_implementation.md
|
|
607
|
-
- redesign/Phase 4 - Step A.md
|
|
608
|
-
- redesign/Phase 4 - Step B.md
|
|
609
|
-
- redesign/Phase 4 - Step C.md
|
|
610
|
-
- redesign/beta_release.md
|
|
611
|
-
- redesign/branch_parse_refactor_plan.md
|
|
612
|
-
- redesign/c1a-public-api-scope.tsv
|
|
613
|
-
- redesign/c1c2_audit.md
|
|
614
|
-
- redesign/c1c2_bucket6_lib_orphans.md
|
|
615
|
-
- redesign/config_design.rb
|
|
616
|
-
- redesign/index.md
|
|
617
|
-
- redesign/info_object_migration_plan.md
|
|
618
|
-
- redesign/integration_test_analysis.md
|
|
619
|
-
- redesign/phase-4-step-b-test-audit.tsv
|
|
620
|
-
- redesign/remote_refactor_plan.md
|
|
621
|
-
- redesign/reverse_dependencies.sql
|
|
622
|
-
- tasks/gem_tasks.rake
|
|
623
|
-
- tasks/npm_tasks.rake
|
|
624
|
-
- tasks/rspec.rake
|
|
625
|
-
- tasks/rubocop.rake
|
|
626
|
-
- tasks/test_gem.rake
|
|
627
|
-
- tasks/yard.rake
|
|
628
539
|
homepage: http://github.com/ruby-git/ruby-git
|
|
629
540
|
licenses:
|
|
630
541
|
- MIT
|
|
631
542
|
metadata:
|
|
632
543
|
homepage_uri: http://github.com/ruby-git/ruby-git
|
|
633
544
|
source_code_uri: http://github.com/ruby-git/ruby-git
|
|
634
|
-
changelog_uri: https://rubydoc.info/gems/git/5.
|
|
635
|
-
documentation_uri: https://rubydoc.info/gems/git/5.
|
|
545
|
+
changelog_uri: https://rubydoc.info/gems/git/5.2.0/file/CHANGELOG.md
|
|
546
|
+
documentation_uri: https://rubydoc.info/gems/git/5.2.0
|
|
636
547
|
rubygems_mfa_required: 'true'
|
|
637
548
|
rdoc_options: []
|
|
638
549
|
require_paths:
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Address all unresolved Copilot review threads on the active pull request
|
|
3
|
-
argument-hint: "[PR number — defaults to the PR for the current branch]"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Follow the shared agent prompt in
|
|
7
|
-
`.github/prompts/iteratively-address-copilot-reviews.prompt.md` exactly. That file
|
|
8
|
-
is the canonical instructions for this task and is shared with other AI agents; read
|
|
9
|
-
it before doing anything else.
|
|
10
|
-
|
|
11
|
-
@.github/prompts/iteratively-address-copilot-reviews.prompt.md
|
|
12
|
-
|
|
13
|
-
If `$ARGUMENTS` is non-empty, treat it as the pull request number to operate on
|
|
14
|
-
instead of detecting the PR from the current branch.
|
data/.claude/settings.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
3
|
-
"hooks": {
|
|
4
|
-
"SessionStart": [
|
|
5
|
-
{
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "\"$CLAUDE_PROJECT_DIR/.github/hooks/run-bin-setup-once.sh\"",
|
|
10
|
-
"timeout": 900
|
|
11
|
-
}
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
}
|
data/.claude/skills
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
../.github/skills
|
data/.commitlintrc.yml
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
extends: '@commitlint/config-conventional'
|
|
3
|
-
|
|
4
|
-
rules:
|
|
5
|
-
# See: https://commitlint.js.org/reference/rules.html
|
|
6
|
-
#
|
|
7
|
-
# Rules are made up by a name and a configuration array. The configuration
|
|
8
|
-
# array contains:
|
|
9
|
-
#
|
|
10
|
-
# * Severity [0..2]: 0 disable rule, 1 warning if violated, or 2 error if
|
|
11
|
-
# violated
|
|
12
|
-
# * Applicability [always|never]: never inverts the rule
|
|
13
|
-
# * Value: value to use for this rule (if applicable)
|
|
14
|
-
#
|
|
15
|
-
# Run `npx commitlint --print-config` to see the current setting for all
|
|
16
|
-
# rules.
|
|
17
|
-
#
|
|
18
|
-
header-max-length: [2, always, 100] # Header can not exceed 100 chars
|
|
19
|
-
|
|
20
|
-
type-case: [2, always, lower-case] # Type must be lower case
|
|
21
|
-
type-empty: [2, never] # Type must not be empty
|
|
22
|
-
|
|
23
|
-
# Supported conventional commit types
|
|
24
|
-
type-enum: [2, always, [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test]]
|
|
25
|
-
|
|
26
|
-
scope-case: [2, always, lower-case] # Scope must be lower case
|
|
27
|
-
|
|
28
|
-
# Error if subject is one of these cases (encourages lower-case)
|
|
29
|
-
subject-case: [2, never, [sentence-case, start-case, pascal-case, upper-case]]
|
|
30
|
-
subject-empty: [2, never] # Subject must not be empty
|
|
31
|
-
subject-full-stop: [2, never, "."] # Subject must not end with a period
|
|
32
|
-
|
|
33
|
-
body-leading-blank: [2, always] # Body must have a blank line before it
|
|
34
|
-
body-max-line-length: [2, always, 100] # Body lines can not exceed 100 chars
|
|
35
|
-
|
|
36
|
-
footer-leading-blank: [2, always] # Footer must have a blank line before it
|
|
37
|
-
footer-max-line-length: [2, always, 100] # Footer lines can not exceed 100 chars
|
|
38
|
-
|
data/.dockerignore
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Keep the Docker build context free of host-generated artifacts so the
|
|
2
|
-
# image always builds gems fresh instead of picking up stale or
|
|
3
|
-
# host-specific state (see .gitignore for the equivalent git-tracked list).
|
|
4
|
-
#
|
|
5
|
-
# .git is also excluded: the Dockerfile initializes its own throwaway git
|
|
6
|
-
# repo instead of relying on the host's, since the host's `.git` may be a
|
|
7
|
-
# linked-worktree pointer file referencing a path that doesn't exist in the
|
|
8
|
-
# image (see docker/test/Dockerfile for details).
|
|
9
|
-
.git
|
|
10
|
-
*.gem
|
|
11
|
-
*.kpf
|
|
12
|
-
*.sw?
|
|
13
|
-
.DS_Store
|
|
14
|
-
.bundle/
|
|
15
|
-
vendor/bundle/
|
|
16
|
-
coverage
|
|
17
|
-
doc
|
|
18
|
-
.yardoc
|
|
19
|
-
pkg
|
|
20
|
-
rdoc
|
|
21
|
-
Gemfile.lock
|
|
22
|
-
node_modules
|
|
23
|
-
package-lock.json
|
|
24
|
-
ai-prompt.erb
|
|
25
|
-
rubocop-report.json
|
|
26
|
-
.rspec_status
|
|
27
|
-
git-reference/
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# GitHub Copilot Instructions for ruby-git
|
|
2
|
-
|
|
3
|
-
## Project Overview
|
|
4
|
-
|
|
5
|
-
A Ruby gem providing an interface to Git repositories by wrapping system calls to the
|
|
6
|
-
`git` CLI.
|
|
7
|
-
|
|
8
|
-
Read the "Project Context" skill (`.github/skills/project-context/SKILL.md`) for
|
|
9
|
-
design philosophy, technical details, and compatibility requirements.
|
|
10
|
-
|
|
11
|
-
This project enforces Conventional Commits. See `.commitlintrc.yml` for allowed types
|
|
12
|
-
and scopes. Never use `#` in the commit message body. Doing so will cause
|
|
13
|
-
commitlint to incorrectly parse the commit message body as a footer. If you need to
|
|
14
|
-
refer to an issue in the body, use `issue 999` instead of `issue #999`. It is still
|
|
15
|
-
fine to use `#` in footer values such as `Closes: #999` or `Refs: #999`.
|
|
16
|
-
|
|
17
|
-
## Terminology & Writing Style
|
|
18
|
-
|
|
19
|
-
- Use American English.
|
|
20
|
-
- **Version strings:** Use `vN.x` for major series compatibility (e.g., `v4.x`) and
|
|
21
|
-
`vN.0.0` for specific releases (e.g., `v5.0.0`). Never use the ambiguous `vN.0`.
|
|
22
|
-
- **RuboCop:** Use `RuboCop` for prose and `rubocop` for CLI or gem names. Never use
|
|
23
|
-
`Rubocop`.
|
|
24
|
-
|
|
25
|
-
## Branch & PR Strategy
|
|
26
|
-
|
|
27
|
-
| Target | When |
|
|
28
|
-
| --- | --- |
|
|
29
|
-
| `main` | New features, breaking changes, all active development |
|
|
30
|
-
| `4.x` | Security fixes and backward-compatible bug fixes for the v4.x series |
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# This hook is shared by every agent configured for this repo (GitHub Copilot via
|
|
5
|
-
# .github/hooks/, Claude Code via .claude/settings.json), so do not assume the
|
|
6
|
-
# caller's working directory.
|
|
7
|
-
command -v git >/dev/null 2>&1 || exit 0
|
|
8
|
-
cd "$(dirname "${BASH_SOURCE[0]}")/../.." || exit 0
|
|
9
|
-
|
|
10
|
-
# Skip if this repo does not use bin/setup.
|
|
11
|
-
[[ -x "./bin/setup" ]] || exit 0
|
|
12
|
-
|
|
13
|
-
# Keep setup idempotent per-worktree. The marker is shared across agents so that
|
|
14
|
-
# cloning and opening the repo in two different tools does not run setup twice.
|
|
15
|
-
marker="$(git rev-parse --git-path agent-bin-setup.done 2>/dev/null)" || exit 0
|
|
16
|
-
[[ -f "$marker" ]] && exit 0
|
|
17
|
-
|
|
18
|
-
./bin/setup
|
|
19
|
-
mkdir -p "$(dirname "$marker")"
|
|
20
|
-
touch "$marker"
|
data/.github/issue_template.md
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
### Subject of the issue
|
|
2
|
-
Describe your issue here.
|
|
3
|
-
|
|
4
|
-
### Your environment
|
|
5
|
-
* version of git and ruby-git
|
|
6
|
-
* version of ruby
|
|
7
|
-
|
|
8
|
-
### Steps to reproduce
|
|
9
|
-
Tell us how to reproduce this issue.
|
|
10
|
-
|
|
11
|
-
### Expected behaviour
|
|
12
|
-
What did you expect to happen?
|
|
13
|
-
|
|
14
|
-
### Actual behaviour
|
|
15
|
-
What actually happened?
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
agent: agent
|
|
3
|
-
model: claude-sonnet-4.6
|
|
4
|
-
description: Address all unresolved Copilot review threads on the active pull request until there are no remaining unresolved review threads
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Address unresolved **Copilot** review threads on the active pull request. Ignore threads opened by human reviewers. Ask me for clarification or decisions as needed.
|
|
8
|
-
|
|
9
|
-
If any terminal script command fails, stop immediately. Do not continue the loop, do not resolve additional threads, and do not request a new review. Report: the failed command, exit code, and the most relevant stderr output. **Exception**: the reply POST in Step 3 is intentionally non-fatal — a 404 after a force-push is expected and the resolve step must still run.
|
|
10
|
-
|
|
11
|
-
## Terminology
|
|
12
|
-
|
|
13
|
-
- **Review** — a top-level review submission by `copilot-pull-request-reviewer`, with a `submittedAt` timestamp and an optional summary body. A single review may contain zero or more Review Threads.
|
|
14
|
-
- **Review Thread** — an inline comment thread attached to a specific code location. Key fields: `id` (GraphQL node ID, e.g. `PRRT_…`), `isResolved` (manually resolved by a maintainer), `isOutdated` (the underlying code changed since the thread was created). Each thread has one or more comments; the first comment is Copilot's suggestion.
|
|
15
|
-
- **Check Run** — a standard CI status object on the HEAD commit. Note: Copilot Reviews do **not** create a Check Run; use the Reviews API to detect completion instead.
|
|
16
|
-
|
|
17
|
-
## Before the Loop
|
|
18
|
-
|
|
19
|
-
Run in terminal to establish `OWNER`, `REPO`, and `PR_NUMBER` for use throughout:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
set -euo pipefail
|
|
23
|
-
OWNER=$(gh repo view --json owner --jq '.owner.login')
|
|
24
|
-
REPO=$(gh repo view --json name --jq '.name')
|
|
25
|
-
PR_NUMBER=$(gh pr view --json number --jq '.number')
|
|
26
|
-
: "${OWNER:?failed to resolve OWNER}"
|
|
27
|
-
: "${REPO:?failed to resolve REPO}"
|
|
28
|
-
: "${PR_NUMBER:?failed to resolve PR_NUMBER}"
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Fetch unresolved, non-outdated Copilot Review Threads:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
set -euo pipefail
|
|
35
|
-
: "${OWNER:?missing OWNER}"
|
|
36
|
-
: "${REPO:?missing REPO}"
|
|
37
|
-
: "${PR_NUMBER:?missing PR_NUMBER}"
|
|
38
|
-
threads_json=$(gh api graphql -f query='
|
|
39
|
-
query($owner:String!,$repo:String!,$pr:Int!){
|
|
40
|
-
repository(owner:$owner,name:$repo){
|
|
41
|
-
pullRequest(number:$pr){
|
|
42
|
-
reviewThreads(first:100){nodes{id isResolved isOutdated path
|
|
43
|
-
comments(first:1){nodes{databaseId author{login} createdAt body}}}}}}
|
|
44
|
-
}' -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER" \
|
|
45
|
-
--jq '.data.repository.pullRequest.reviewThreads.nodes')
|
|
46
|
-
if [[ $(echo "$threads_json" | jq 'length') -ge 100 ]]; then
|
|
47
|
-
echo "Error: the PR already has 100 threads or more. Aborting."
|
|
48
|
-
exit 1
|
|
49
|
-
fi
|
|
50
|
-
echo "$threads_json" | jq '[.[] |
|
|
51
|
-
select(.isResolved==false) |
|
|
52
|
-
select(.isOutdated==false) |
|
|
53
|
-
select(.comments.nodes[0].author.login=="copilot-pull-request-reviewer")]'
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
- **Results non-empty** → proceed directly to the iteration loop.
|
|
57
|
-
- **Results empty** → record `REVIEW_REQUESTED_AT` (current UTC, `YYYY-MM-DDTHH:MM:SSZ`, e.g. `2026-06-16T12:00:00Z`), request a new Copilot Review using the `mcp_github_mcp_se_request_copilot_review` tool (owner, repo, pullNumber), then jump to the **Wait for Review** section below.
|
|
58
|
-
|
|
59
|
-
## Iteration Loop
|
|
60
|
-
|
|
61
|
-
Repeat up to **${input:maxIterations:5}** iterations:
|
|
62
|
-
|
|
63
|
-
### 1. Address threads
|
|
64
|
-
|
|
65
|
-
Re-fetch unresolved, non-outdated Copilot Review Threads using the same `gh api graphql` query from Before the Loop. Group by file. For each file, read it once and address all its threads in that single pass:
|
|
66
|
-
- Validate each suggestion before accepting it.
|
|
67
|
-
- If a suggestion is invalid or out of scope: reply explaining why, then resolve the thread without changing code.
|
|
68
|
-
- Otherwise: implement the change using TDD where possible; ensure test coverage.
|
|
69
|
-
|
|
70
|
-
Skip any thread where `isOutdated` is true — the code it references has already changed; Copilot will re-evaluate it in the next Review.
|
|
71
|
-
|
|
72
|
-
After all threads are addressed, run `rake`. If it fails, capture `rake 2>&1 | tail -n 50` and fix the failure before continuing.
|
|
73
|
-
|
|
74
|
-
### 2. Commit and push
|
|
75
|
-
|
|
76
|
-
Amend each change into the most relevant existing commit on the branch based on file name. If a change spans multiple commits or doesn't map clearly to one, ask me which commit to amend into (or whether to create a new commit). Confirm the working tree is clean and `rake` passes, then force push.
|
|
77
|
-
|
|
78
|
-
### 3. Reply and resolve
|
|
79
|
-
|
|
80
|
-
For each addressed thread object from the unresolved-threads query, in the same `run_in_terminal` script block that performs reply/resolve, export:
|
|
81
|
-
|
|
82
|
-
- `COMMENT_DBID=.comments.nodes[0].databaseId`
|
|
83
|
-
- `THREAD_ID=.id`
|
|
84
|
-
- `EXPLANATION` to your plain-language fix summary for that thread
|
|
85
|
-
|
|
86
|
-
Set the per-thread variables (`COMMENT_DBID`, `THREAD_ID`, `EXPLANATION`) immediately before running the commands below — do not rely on them surviving from a prior terminal invocation.
|
|
87
|
-
|
|
88
|
-
Then post a reply and resolve it:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
set -euo pipefail
|
|
92
|
-
: "${OWNER:?missing OWNER}"
|
|
93
|
-
: "${REPO:?missing REPO}"
|
|
94
|
-
: "${COMMENT_DBID:?missing COMMENT_DBID}"
|
|
95
|
-
: "${EXPLANATION:?missing EXPLANATION}"
|
|
96
|
-
|
|
97
|
-
# Reply (COMMENT_DBID = databaseId of the thread's first comment)
|
|
98
|
-
# Build JSON via jq to safely handle quotes/newlines/special chars in EXPLANATION.
|
|
99
|
-
# EXPLANATION should contain the full reply text (e.g. "Fixed: ..." or "Not addressing this because...").
|
|
100
|
-
BODY_JSON=$(jq -n --arg body "$EXPLANATION" '{body:$body}')
|
|
101
|
-
# Non-fatal: a force-push can mark threads as outdated, causing the REST reply to return 404.
|
|
102
|
-
# Always continue to the GraphQL resolve step regardless.
|
|
103
|
-
gh api "repos/$OWNER/$REPO/pulls/comments/$COMMENT_DBID/replies" \
|
|
104
|
-
-X POST --input - <<<"$BODY_JSON" \
|
|
105
|
-
|| echo "Warning: reply POST failed (thread may be outdated after force-push) — skipping reply, will still resolve"
|
|
106
|
-
|
|
107
|
-
: "${THREAD_ID:?missing THREAD_ID}"
|
|
108
|
-
|
|
109
|
-
# Resolve (THREAD_ID = GraphQL node id, e.g. PRRT_...)
|
|
110
|
-
gh api graphql \
|
|
111
|
-
-f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' \
|
|
112
|
-
-f id="$THREAD_ID"
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### 4. Request review
|
|
116
|
-
|
|
117
|
-
**If this was the ${input:maxIterations:5}th iteration**, skip steps 4 and 6 entirely — go directly to step 5 (Report) and then produce the Final Report.
|
|
118
|
-
|
|
119
|
-
Otherwise, capture `REVIEW_REQUESTED_AT` by running `date -u +%Y-%m-%dT%H:%M:%SZ` in the terminal immediately before requesting the review. Then request a new Copilot Review using the `mcp_github_mcp_se_request_copilot_review` tool (owner, repo, pullNumber).
|
|
120
|
-
|
|
121
|
-
### 5. Report
|
|
122
|
-
|
|
123
|
-
List what was addressed and how each issue was resolved.
|
|
124
|
-
|
|
125
|
-
### 6. Wait
|
|
126
|
-
|
|
127
|
-
Jump to the **Wait for Review** section below. Return here to begin the next iteration once the new Copilot Review has been submitted.
|
|
128
|
-
|
|
129
|
-
## Wait for Review
|
|
130
|
-
|
|
131
|
-
**[BLOCKING — do not proceed until complete]** Poll for a new Copilot Review submission using the Reviews API. A Review with `submittedAt >= REVIEW_REQUESTED_AT` is the authoritative completion signal — it fires even when Copilot produces zero Review Threads.
|
|
132
|
-
|
|
133
|
-
Run the following script via `run_in_terminal` (sync mode, timeout 750000 ms). Set the four variables on the first line to their actual values. On success, capture the script's last output line; on failure, follow the global failure-reporting rule (failed command, exit code, relevant stderr):
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
set -euo pipefail
|
|
137
|
-
# Replace with actual values. REVIEW_REQUESTED_AT = output of `date -u +%Y-%m-%dT%H:%M:%SZ` captured just before requesting the review.
|
|
138
|
-
OWNER="ruby-git"; REPO="ruby-git"; PR_NUMBER="1439"; REVIEW_REQUESTED_AT="2026-06-16T12:00:00Z"
|
|
139
|
-
: "${OWNER:?missing OWNER}"
|
|
140
|
-
: "${REPO:?missing REPO}"
|
|
141
|
-
: "${PR_NUMBER:?missing PR_NUMBER}"
|
|
142
|
-
: "${REVIEW_REQUESTED_AT:?missing REVIEW_REQUESTED_AT}"
|
|
143
|
-
START=$(date +%s)
|
|
144
|
-
for i in $(seq 1 60); do
|
|
145
|
-
new_review=$(gh pr view "$PR_NUMBER" --repo "$OWNER/$REPO" --json reviews \
|
|
146
|
-
--jq "[.reviews[] | select(.author.login==\"copilot-pull-request-reviewer\") | select(.submittedAt != null) | select(.submittedAt | fromdateiso8601 >= (\"$REVIEW_REQUESTED_AT\" | fromdateiso8601))] | length") \
|
|
147
|
-
|| { rc=$?; echo "Error: gh pr view failed (exit $rc)"; exit $rc; }
|
|
148
|
-
if [[ -n "$new_review" && "$new_review" -gt 0 ]]; then
|
|
149
|
-
raw_nodes=$(gh api graphql -f query='
|
|
150
|
-
query($owner:String!,$repo:String!,$pr:Int!){
|
|
151
|
-
repository(owner:$owner,name:$repo){
|
|
152
|
-
pullRequest(number:$pr){
|
|
153
|
-
reviewThreads(first:100){nodes{isResolved isOutdated comments(first:1){nodes{author{login}}}}}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}' -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER" \
|
|
157
|
-
--jq '.data.repository.pullRequest.reviewThreads.nodes') \
|
|
158
|
-
|| { rc=$?; echo "Error: gh api graphql failed (exit $rc)"; exit $rc; }
|
|
159
|
-
if [[ $(echo "$raw_nodes" | jq 'length') -ge 100 ]]; then
|
|
160
|
-
echo "Error: the PR already has 100 threads or more. Aborting."
|
|
161
|
-
exit 1
|
|
162
|
-
fi
|
|
163
|
-
count=$(echo "$raw_nodes" | jq "[.[] |
|
|
164
|
-
select(.isResolved==false) |
|
|
165
|
-
select(.isOutdated==false) |
|
|
166
|
-
select(.comments.nodes[0].author.login==\"copilot-pull-request-reviewer\")] | length")
|
|
167
|
-
echo "done: $count threads" # count of all unresolved non-outdated Copilot Review Threads
|
|
168
|
-
exit 0
|
|
169
|
-
fi
|
|
170
|
-
elapsed=$(( $(date +%s) - START ))
|
|
171
|
-
echo "Waiting for Copilot Review to complete... (${elapsed}s elapsed)"
|
|
172
|
-
sleep 10
|
|
173
|
-
done
|
|
174
|
-
echo "timed out after 60 polls"
|
|
175
|
-
exit 1
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
**If `timed out after 60 polls`**: stop immediately and ask me whether to re-request the review and retry, or abort.
|
|
179
|
-
|
|
180
|
-
**If `done: 0 threads`**: the loop is complete — exit.
|
|
181
|
-
|
|
182
|
-
**If `done: N threads`** (N > 0): begin the next iteration.
|
|
183
|
-
|
|
184
|
-
## Final Report
|
|
185
|
-
|
|
186
|
-
- Total iterations completed
|
|
187
|
-
- Total threads addressed
|
|
188
|
-
- Unresolved threads in the final Copilot review (should be 0 if the loop exited cleanly)
|