git 5.0.0.beta.1 → 5.0.0.beta.3

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +6 -0
  3. data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
  4. data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
  5. data/.github/skills/extract-facade-from-base-lib/SKILL.md +28 -14
  6. data/.github/skills/facade-implementation/SKILL.md +14 -0
  7. data/.github/skills/facade-test-conventions/SKILL.md +14 -0
  8. data/.rubocop.yml +5 -0
  9. data/README.md +90 -22
  10. data/UPGRADING.md +141 -0
  11. data/git.gemspec +5 -0
  12. data/lib/git/branch.rb +7 -18
  13. data/lib/git/branches.rb +2 -10
  14. data/lib/git/command_line/base.rb +10 -0
  15. data/lib/git/command_line/capturing.rb +5 -3
  16. data/lib/git/command_line/streaming.rb +5 -3
  17. data/lib/git/command_line.rb +3 -3
  18. data/lib/git/commands/base.rb +7 -6
  19. data/lib/git/commands/cat_file/batch.rb +6 -1
  20. data/lib/git/commands/cat_file/raw.rb +7 -1
  21. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +5 -0
  22. data/lib/git/commands/show_ref/exclude_existing.rb +1 -1
  23. data/lib/git/commands/update_ref/batch.rb +1 -1
  24. data/lib/git/commands/version.rb +5 -0
  25. data/lib/git/commands.rb +5 -7
  26. data/lib/git/config.rb +17 -0
  27. data/lib/git/config_entry_info.rb +106 -0
  28. data/lib/git/configuring.rb +665 -0
  29. data/lib/git/deprecation.rb +9 -0
  30. data/lib/git/diff.rb +4 -8
  31. data/lib/git/diff_path_status.rb +2 -13
  32. data/lib/git/diff_stats.rb +1 -9
  33. data/lib/git/execution_context/global.rb +3 -28
  34. data/lib/git/execution_context/repository.rb +30 -41
  35. data/lib/git/execution_context.rb +43 -24
  36. data/lib/git/log.rb +3 -9
  37. data/lib/git/object.rb +14 -21
  38. data/lib/git/parsers/config_entry.rb +110 -0
  39. data/lib/git/parsers/ls_remote.rb +79 -0
  40. data/lib/git/remote.rb +7 -20
  41. data/lib/git/repository/branching.rb +183 -12
  42. data/lib/git/repository/committing.rb +64 -68
  43. data/lib/git/repository/context_helpers.rb +264 -0
  44. data/lib/git/repository/factories.rb +682 -0
  45. data/lib/git/repository/inspecting.rb +99 -0
  46. data/lib/git/repository/maintenance.rb +65 -0
  47. data/lib/git/repository/merging.rb +63 -1
  48. data/lib/git/repository/object_operations.rb +133 -35
  49. data/lib/git/repository/path_resolver.rb +1 -1
  50. data/lib/git/repository/remote_operations.rb +166 -21
  51. data/lib/git/repository/staging.rb +187 -23
  52. data/lib/git/repository/stashing.rb +39 -3
  53. data/lib/git/repository/status_operations.rb +21 -0
  54. data/lib/git/repository.rb +288 -128
  55. data/lib/git/stash.rb +2 -9
  56. data/lib/git/stashes.rb +2 -7
  57. data/lib/git/status.rb +12 -23
  58. data/lib/git/version.rb +2 -2
  59. data/lib/git/worktree.rb +2 -15
  60. data/lib/git/worktrees.rb +2 -15
  61. data/lib/git.rb +182 -77
  62. data/redesign/3_architecture_implementation.md +170 -112
  63. data/redesign/Phase 4 - Step A.md +366 -0
  64. data/redesign/beta_release.md +107 -0
  65. data/redesign/c1c2_audit.md +566 -0
  66. data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
  67. data/redesign/config_design.rb +501 -0
  68. metadata +19 -6
  69. data/lib/git/base.rb +0 -1204
  70. data/lib/git/lib.rb +0 -2855
  71. data/lib/git/repository/configuring.rb +0 -156
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f42d907159502c20d7ba5a2e9545f202be91fb64bf2efcf5663c418acc99a396
4
- data.tar.gz: 42361a9dd11080081afddcd446131a4784acf1c7b38774a697026f00fbfb3dff
3
+ metadata.gz: '085739aa78a2d5bfacbf1f2048fb15997b8021ea40fda26715e9a66f7d2d8178'
4
+ data.tar.gz: f83f025bc403549cb4f4f889f2ed83ee2af9afdc2947a535345970c47ffa87b5
5
5
  SHA512:
6
- metadata.gz: 264ac7e0a0f8236143c1e95f4bc304b35bca810b7e3d898e8d747ebb7bbec69921a4bc9286899ff3314d95ae02680f349cfcb0f07dcc5d72885e044ab3841b28
7
- data.tar.gz: 3212f8816a84bb0be1131e3099e2b0e5fcf248217851b6bffd6176a442e84840e723cb8e5b12b20600d11f2277d4495b61a35bb3f45f3b0e54d5dda6bfc5958f
6
+ metadata.gz: 2769eab52af46ddc54bfea220b51f5b450e6f3e9999288f3b7d2003940dc4bf428a3b682c34ed41b36294d297ecda67abb48fa680063c396afbd1e45cbd71b75
7
+ data.tar.gz: 81aaa29f87a49c7cf1573e3fc1bbc32e9eb9883952c7550b69f983b73ebf33264f700d0465bb1ac390390083b8becdaefe80faebe3200adcd4d815c895cad57e
@@ -17,6 +17,12 @@ and compatibility requirements see the
17
17
  ## Terminology & Writing Style
18
18
 
19
19
  - Use American English always. Avoid British English spellings and idioms.
20
+ - **Version strings** — use the most precise form appropriate to the context:
21
+ - `vN.x` (e.g. `v5.x`, `v4.x`) — the whole major series; use for compatibility
22
+ statements and upgrade guide scope ("v4.x code works on v5.x").
23
+ - `vN.0.0` (e.g. `v5.0.0`, `v6.0.0`) — a specific first release; use when
24
+ precision matters ("removed in v5.0.0", "the foundation delivered in v5.0.0").
25
+ - `vN.0` — avoid; ambiguous between "minor version 0" and "shorthand for vN.0.0".
20
26
  - **RuboCop** — correct capitalization when referring to the tool by name in prose,
21
27
  documentation, or comments.
22
28
  - **`rubocop`** — correct form when referring to the command-line executable or gem
@@ -0,0 +1,188 @@
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)
@@ -0,0 +1,22 @@
1
+ # Keyword-arg remediation list
2
+
3
+ The following facade methods are known to use `**opts`/`**` keyword-splat where
4
+ the legacy `Git::Base` or `Git::Lib` predecessor used a positional options hash
5
+ (`opts = {}`). Each is a candidate `legacy-contract` violation that must be
6
+ resolved before `Git.open`/`.clone`/`.init`/`.bare` are changed to return
7
+ `Git::Repository`: either fix the signature or
8
+ record an explicit `5.x-native` justification.
9
+
10
+ | Facade method | Current signature | Expected classification | Action needed |
11
+ | --- | --- | --- | --- |
12
+ | `Git::Repository::Staging#add` | `add(paths = '.', **)` | `legacy-contract` | Verify against 4.x `Git::Lib#add`; change to `opts = {}` if legacy |
13
+ | `Git::Repository::Staging#reset` | `reset(commitish = nil, **)` | `legacy-contract` | Verify against 4.x `Git::Lib#reset`; change to `opts = {}` if legacy |
14
+ | `Git::Repository::Committing#commit` | `commit(message = nil, **opts)` | `legacy-contract` | Verify against 4.x `Git::Base#commit`; change to `opts = {}` if legacy |
15
+ | `Git::Repository::Committing#commit_all` | `commit_all(*, **)` | `legacy-contract` | Verify against 4.x `Git::Base#commit_all`; change to `opts = {}` if legacy |
16
+ | `Git::Repository::Committing#commit_tree` | `commit_tree(tree, **opts)` | needs classification | Classify; if 5.x-native confirm; if legacy-contract fix signature |
17
+ | `Git::Repository::Committing#write_and_commit_tree` | `write_and_commit_tree(**)` | needs classification | Classify; if 5.x-native confirm; if legacy-contract fix signature |
18
+ | `Git::Repository::Branching#branch_delete` | `branch_delete(*branches, **options)` | needs classification | Verify against 4.x `Git::Base#branch_delete`; classify and fix or confirm |
19
+ | `Git::Repository::Inspecting#fsck` | `fsck(*objects, **)` | needs classification | Verify against 4.x `Git::Lib#fsck`; classify and fix or confirm |
20
+
21
+ This list is seeded from a static scan of `lib/git/repository/**/*.rb` and may be
22
+ incomplete. A full public-method inventory is required before closing the sweep.
@@ -18,7 +18,6 @@ preserve backward compatibility within the migration window.
18
18
 
19
19
  ## Contents
20
20
 
21
- - [Contents](#contents)
22
21
  - [How to use this skill](#how-to-use-this-skill)
23
22
  - [Prerequisites](#prerequisites)
24
23
  - [Related skills](#related-skills)
@@ -28,6 +27,7 @@ preserve backward compatibility within the migration window.
28
27
  - [Pattern B — `Git::Lib`-only (public-by-exposure)](#pattern-b--gitlib-only-public-by-exposure)
29
28
  - [Pattern C — `Git::Base`-only (no `Git::Lib` method)](#pattern-c--gitbase-only-no-gitlib-method)
30
29
  - [Signature compatibility policy](#signature-compatibility-policy)
30
+ - [Keyword-arg remediation list](#keyword-arg-remediation-list)
31
31
  - [Determining the option allowlist](#determining-the-option-allowlist)
32
32
  - [Workflow](#workflow)
33
33
  - [Branch setup](#branch-setup)
@@ -180,13 +180,29 @@ Use this policy in both extraction mode and review mode:
180
180
 
181
181
  Rules:
182
182
 
183
- 1. Default classification is `legacy-contract` when a legacy predecessor exists.
184
- 2. `5.x-native` requires explicit justification in the plan/review notes.
185
- 3. For `legacy-contract` methods, preserve the exact 4.x signature (including
186
- rare `**opts` signatures). For `5.x-native` methods, use `opts = {}` style
187
- for consistency.
188
- 4. For `legacy-contract` methods, tests must prove the expected call shape,
189
- not only command delegation.
183
+ 1. `legacy-contract` methods preserve the exact 4.x call shape verbatim,
184
+ including rare `**opts` signatures; never alter the parameter list when a
185
+ legacy predecessor exists.
186
+ 2. `5.x-native` methods use `opts = {}` style for consistency; a broader kwargs
187
+ migration is deferred to v6.x so it can be applied uniformly across the
188
+ entire public API.
189
+ 3. Every extracted method must be explicitly classified as `legacy-contract` or
190
+ `5.x-native` before the PR is opened.
191
+ 4. The classification must appear in the PR description and in the extracted
192
+ method's YARD `@note`. Example:
193
+
194
+ ```ruby
195
+ # @note Signature compatibility: legacy-contract — preserves the exact Git::Base#foo 4.x call shape.
196
+ ```
197
+
198
+ ## Keyword-arg remediation list
199
+
200
+ See [KEYWORD_ARG_REMEDIATION.md](KEYWORD_ARG_REMEDIATION.md) for the initial list
201
+ of facade methods that use `**opts`/`**` keyword-splat where the legacy predecessor
202
+ used `opts = {}`. Each method in this list must be resolved before
203
+ `Git.open`/`.clone`/`.init`/`.bare` are changed to return `Git::Repository`:
204
+ either fix the signature to match the `legacy-contract` classification, or
205
+ record an explicit `5.x-native` justification.
190
206
 
191
207
  ## Determining the option allowlist
192
208
 
@@ -409,15 +425,13 @@ end
409
425
 
410
426
  ```ruby
411
427
  # lib/git/base.rb
412
- def add_remote(name, url, opts = {})
413
- repository.add_remote(name, url, opts)
428
+ def remote_add(name, url, opts = {})
429
+ facade_repository.remote_add(name, url, opts)
414
430
  end
415
431
  ```
416
432
 
417
- (The exact accessor `repository`, `@repository`, `self.repository` — depends
418
- on how `Git::Base` and `Git::Lib` hold their reference to the new
419
- `Git::Repository` instance during the migration window. Match the existing
420
- pattern used by other migrated methods.)
433
+ (Use `facade_repository` to access the `Git::Repository` facade instance this
434
+ is the accessor used by all migrated methods in `Git::Base`.)
421
435
 
422
436
  After delegation is in place, verify:
423
437
 
@@ -17,6 +17,7 @@ for the five facade responsibilities this layer is designed around.
17
17
 
18
18
  ## Contents
19
19
 
20
+ - [How to use this skill](#how-to-use-this-skill)
20
21
  - [Related skills](#related-skills)
21
22
  - [Input](#input)
22
23
  - [Existing facade source](#existing-facade-source)
@@ -27,6 +28,19 @@ for the five facade responsibilities this layer is designed around.
27
28
  - [Workflow](#workflow)
28
29
  - [Output](#output)
29
30
 
31
+ ## How to use this skill
32
+
33
+ Attach this file to your Copilot Chat context, then invoke with the facade method
34
+ to scaffold, update, or review. Examples:
35
+
36
+ ```text
37
+ Using the Facade Implementation skill, scaffold Git::Repository::Staging#add.
38
+ ```
39
+
40
+ ```text
41
+ Facade Implementation review: Git::Repository::Committing#commit.
42
+ ```
43
+
30
44
  ## Related skills
31
45
 
32
46
  - [Facade Test Conventions](../facade-test-conventions/SKILL.md) — unit and
@@ -10,6 +10,7 @@ methods on `Git::Repository::*` modules.
10
10
 
11
11
  ## Contents
12
12
 
13
+ - [How to use this skill](#how-to-use-this-skill)
13
14
  - [Related skills](#related-skills)
14
15
  - [Input](#input)
15
16
  - [Reference](#reference)
@@ -30,6 +31,19 @@ methods on `Git::Repository::*` modules.
30
31
  - [When writing new facade tests](#when-writing-new-facade-tests)
31
32
  - [When reviewing existing facade tests](#when-reviewing-existing-facade-tests)
32
33
 
34
+ ## How to use this skill
35
+
36
+ Attach this file to your Copilot Chat context, then invoke with the spec file(s)
37
+ to write or review. Include the corresponding facade module for context. Examples:
38
+
39
+ ```text
40
+ Using the Facade Test Conventions skill, scaffold tests for Git::Repository::Staging.
41
+ ```
42
+
43
+ ```text
44
+ Facade Test Conventions review: spec/unit/git/repository/committing_spec.rb.
45
+ ```
46
+
33
47
  ## Related skills
34
48
 
35
49
  - [RSpec Unit Testing Standards](../rspec-unit-testing-standards/SKILL.md) — baseline
data/.rubocop.yml CHANGED
@@ -45,6 +45,11 @@ Metrics/BlockLength:
45
45
  - "*.gemspec"
46
46
  - "lib/git/commands/**/*.rb"
47
47
 
48
+ # lib/git.rb is the gem's main entry-point module and is expected to be long
49
+ Metrics/ModuleLength:
50
+ Exclude:
51
+ - "lib/git.rb"
52
+
48
53
  # Don't force every test class to be described
49
54
  Style/Documentation:
50
55
  Exclude:
data/README.md CHANGED
@@ -30,6 +30,8 @@ Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?log
30
30
  - [Ruby Version Support Policy](#ruby-version-support-policy)
31
31
  - [Git Version Support Policy](#git-version-support-policy)
32
32
  - [📢 Project Announcements 📢](#-project-announcements-)
33
+ - [2026-06-26: v5.0.0.beta.3 Released](#2026-06-26-v500beta3-released)
34
+ - [2026-06-25: v5.0.0.beta.2 Released](#2026-06-25-v500beta2-released)
33
35
  - [2026-06-04: v5.0.0.beta.1 Released](#2026-06-04-v500beta1-released)
34
36
  - [2026-01-07: AI Policy Introduced](#2026-01-07-ai-policy-introduced)
35
37
  - [2025-07-09: Architectural Redesign](#2025-07-09-architectural-redesign)
@@ -52,7 +54,7 @@ Get started by obtaining a repository object by:
52
54
  [Git.clone](https://rubydoc.info/gems/git/Git#clone-class_method)
53
55
 
54
56
  Methods that can be called on a repository object are documented in
55
- [Git::Base](https://rubydoc.info/gems/git/Git/Base)
57
+ [Git::Repository](https://rubydoc.info/gems/git/Git/Repository)
56
58
 
57
59
  ## Install
58
60
 
@@ -87,8 +89,8 @@ All functionality for this gem starts with the top-level
87
89
  non-repo scoped `git` commands such as `config`.
88
90
 
89
91
  The `Git` module also has factory methods such as `open`, `clone`, and `init` which
90
- return a [`Git::Base`](https://rubydoc.info/gems/git/Git/Base) object. The
91
- `Git::Base` object is used to run repo-specific `git` commands such as `add`,
92
+ return a [`Git::Repository`](https://rubydoc.info/gems/git/Git/Repository) object. The
93
+ `Git::Repository` object is used to run repo-specific `git` commands such as `add`,
92
94
  `commit`, `push`, and `log`.
93
95
 
94
96
  Clone, read status, and log:
@@ -133,15 +135,17 @@ Configure the `git` command line:
133
135
 
134
136
  ```ruby
135
137
  # Global config (in ~/.gitconfig)
136
- settings = Git.global_config # returns a Hash
137
- username = Git.global_config('user.email')
138
- Git.global_config('user.email', 'user@example.com')
138
+ entries = Git.config_list(global: true) # returns Array<Git::ConfigEntryInfo>
139
+ entry = Git.config_get('user.email', global: true) # returns Git::ConfigEntryInfo or nil
140
+ email = entry&.value # => "user@example.com" or nil
141
+ Git.config_set('user.email', 'user@example.com', global: true)
139
142
 
140
143
  # Repository config
141
144
  repo = Git.open('path/to/repo')
142
- settings = repo.config # returns a Hash
143
- username = repo.config('user.email')
144
- repo.config('user.email', 'anotheruser@example.com')
145
+ entries = repo.config_list # returns Array<Git::ConfigEntryInfo>
146
+ entry = repo.config_get('user.email') # returns Git::ConfigEntryInfo or nil
147
+ email = entry&.value # => "anotheruser@example.com" or nil
148
+ repo.config_set('user.email', 'anotheruser@example.com')
145
149
  ```
146
150
 
147
151
  Configure the git gem:
@@ -292,8 +296,8 @@ result = repo.fsck(unreachable: true, strict: true)
292
296
  # Suppress dangling object output
293
297
  result = repo.fsck(dangling: false)
294
298
 
295
- repo.config('user.name') # returns 'Scott Chacon'
296
- repo.config # returns whole config hash
299
+ repo.config_get('user.name')&.value # returns 'Scott Chacon'
300
+ repo.config_list # returns Array<Git::ConfigEntryInfo>
297
301
 
298
302
  # Configuration can be set when cloning using the :config option.
299
303
  # This option can be an single configuration String or an Array
@@ -342,8 +346,8 @@ path = '/tmp/clone'
342
346
  repo = Git.clone(git_url, name, :path => path)
343
347
  repo.dir #=> /tmp/clone/ruby-git-clean
344
348
 
345
- repo.config('user.name', 'Scott Chacon')
346
- repo.config('user.email', 'email@email.com')
349
+ repo.config_set('user.name', 'Scott Chacon')
350
+ repo.config_set('user.email', 'email@email.com')
347
351
 
348
352
  # Clone can take a filter to tell the serve to send a partial clone
349
353
  repo = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
@@ -370,7 +374,7 @@ repo.commit('message')
370
374
  repo.commit_all('message')
371
375
 
372
376
  # Sign a commit using the gpg key configured in the user.signingkey config setting
373
- repo.config('user.signingkey', '0A46826A')
377
+ repo.config_set('user.signingkey', '0A46826A')
374
378
  repo.commit('message', gpg_sign: true)
375
379
 
376
380
  # Sign a commit using a specified gpg key
@@ -416,8 +420,8 @@ repo.merge([branch1, branch2])
416
420
 
417
421
  repo.merge_base('branch1', 'branch2')
418
422
 
419
- r = repo.add_remote(name, uri) # Git::Remote
420
- r = repo.add_remote(name, Git::Base) # Git::Remote
423
+ r = repo.remote_add(name, uri) # Git::Remote
424
+ r = repo.remote_add(name, other_repo) # Git::Remote (other_repo is a Git::Repository instance)
421
425
 
422
426
  repo.remotes # array of Git::Remotes
423
427
  repo.remote(name).fetch
@@ -437,12 +441,12 @@ repo.fetch('origin', {:'update-head-ok' => true})
437
441
  repo.pull
438
442
  repo.pull(Git::Repo, Git::Branch) # fetch and a merge
439
443
 
440
- repo.add_tag('tag_name') # returns Git::Tag
441
- repo.add_tag('tag_name', 'object_reference')
442
- repo.add_tag('tag_name', 'object_reference', {:options => 'here'})
443
- repo.add_tag('tag_name', {:options => 'here'})
444
+ repo.tag_add('tag_name') # returns Git::Object::Tag
445
+ repo.tag_add('tag_name', 'object_reference')
446
+ repo.tag_add('tag_name', 'object_reference', {:options => 'here'})
447
+ repo.tag_add('tag_name', {:options => 'here'})
444
448
 
445
- repo.delete_tag('tag_name')
449
+ repo.tag_delete('tag_name')
446
450
 
447
451
  repo.repack
448
452
 
@@ -650,17 +654,81 @@ notes.
650
654
 
651
655
  ## 📢 Project Announcements 📢
652
656
 
657
+ ### 2026-06-26: v5.0.0.beta.3 Released
658
+
659
+ The architectural redesign is approximately **93% complete** and we have published
660
+ [`git v5.0.0.beta.3`](https://rubygems.org/gems/git/versions/5.0.0.beta.3) as our
661
+ third pre-release.
662
+
663
+ **To try the beta**, add the pre-release version to your `Gemfile`:
664
+
665
+ ```ruby
666
+ gem 'git', '~> 5.0.0.beta'
667
+ ```
668
+
669
+ Or install it directly:
670
+
671
+ ```sh
672
+ gem install git --pre
673
+ ```
674
+
675
+ The intent is full backward compatibility with v4.x, but given the size and scope of
676
+ the redesign, some incompatibilities may exist. Please give the latest beta a try and
677
+ [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
678
+ unexpected — your feedback helps us ship a solid v5.0.0.
679
+
680
+ See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
681
+
682
+ ### 2026-06-25: v5.0.0.beta.2 Released
683
+
684
+ The architectural redesign is approximately **90% complete** and we have published
685
+ [`git v5.0.0.beta.2`](https://rubygems.org/gems/git/versions/5.0.0.beta.2) as our
686
+ second pre-release.
687
+
688
+ **To try the beta**, add the pre-release version to your `Gemfile`:
689
+
690
+ ```ruby
691
+ gem 'git', '~> 5.0.0.beta'
692
+ ```
693
+
694
+ Or install it directly:
695
+
696
+ ```sh
697
+ gem install git --pre
698
+ ```
699
+
700
+ The intent is full backward compatibility with v4.x, but given the size and scope of
701
+ the redesign, some incompatibilities may exist. Please give the latest beta a try and
702
+ [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
703
+ unexpected — your feedback helps us ship a solid v5.0.0.
704
+
705
+ See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
706
+
653
707
  ### 2026-06-04: v5.0.0.beta.1 Released
654
708
 
655
709
  The architectural redesign is approximately **65% complete** and we have published
656
- [`git 5.0.0.beta.1`](https://rubygems.org/gems/git/versions/5.0.0.beta.1) as our
710
+ [`git v5.0.0.beta.1`](https://rubygems.org/gems/git/versions/5.0.0.beta.1) as our
657
711
  first pre-release.
658
712
 
713
+ **To try the beta**, add the pre-release version to your `Gemfile`:
714
+
715
+ ```ruby
716
+ gem 'git', '~> 5.0.0.beta'
717
+ ```
718
+
719
+ Or install it directly:
720
+
721
+ ```sh
722
+ gem install git --pre
723
+ ```
724
+
659
725
  The intent is full backward compatibility with 4.x, but given the size and scope of
660
726
  the redesign, some incompatibilities may exist. Please give the latest beta a try and
661
727
  [open an issue](https://github.com/ruby-git/ruby-git/issues) if you hit anything
662
728
  unexpected — your feedback helps us ship a solid 5.0.0.
663
729
 
730
+ See [UPGRADING.md](UPGRADING.md) for a full list of deprecations and breaking changes.
731
+
664
732
  ### 2026-01-07: AI Policy Introduced
665
733
 
666
734
  We have adopted a formal [AI Policy](AI_POLICY.md) to clarify expectations for