git 5.0.0.beta.1 → 5.0.0.beta.2

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 +51 -11
  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/configuring.rb +208 -13
  44. data/lib/git/repository/context_helpers.rb +264 -0
  45. data/lib/git/repository/factories.rb +682 -0
  46. data/lib/git/repository/inspecting.rb +99 -0
  47. data/lib/git/repository/maintenance.rb +65 -0
  48. data/lib/git/repository/merging.rb +63 -1
  49. data/lib/git/repository/object_operations.rb +133 -35
  50. data/lib/git/repository/path_resolver.rb +1 -1
  51. data/lib/git/repository/remote_operations.rb +166 -21
  52. data/lib/git/repository/staging.rb +187 -23
  53. data/lib/git/repository/stashing.rb +39 -3
  54. data/lib/git/repository/status_operations.rb +21 -0
  55. data/lib/git/repository.rb +68 -129
  56. data/lib/git/stash.rb +2 -9
  57. data/lib/git/stashes.rb +2 -7
  58. data/lib/git/status.rb +8 -17
  59. data/lib/git/version.rb +2 -2
  60. data/lib/git/worktree.rb +2 -15
  61. data/lib/git/worktrees.rb +2 -15
  62. data/lib/git.rb +180 -77
  63. data/redesign/3_architecture_implementation.md +148 -111
  64. data/redesign/Phase 4 - Step A.md +360 -0
  65. data/redesign/beta_release.md +107 -0
  66. data/redesign/c1c2_audit.md +566 -0
  67. data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
  68. data/redesign/config_design.rb +501 -0
  69. metadata +19 -5
  70. data/lib/git/base.rb +0 -1204
  71. data/lib/git/lib.rb +0 -2855
@@ -9,11 +9,12 @@ risk and allows for a gradual, controlled migration to the new architecture.
9
9
  - [Facade Modules Completed](#facade-modules-completed)
10
10
  - [Facade module naming convention](#facade-module-naming-convention)
11
11
  - [Next Task](#next-task)
12
- - [Phase 3 Public Interface Completion](#phase-3-public-interface-completion)
12
+ - [D2 / Phase 4 is the remaining redesign step](#d2--phase-4-is-the-remaining-redesign-step)
13
+ - [Phase 3 Overview](#phase-3-overview)
13
14
  - [Workstream A — Fill facade coverage gaps](#workstream-a--fill-facade-coverage-gaps)
14
15
  - [Workstream B — C0: Redirect `Git::Base` factory methods to `facade_repository`](#workstream-b--c0-redirect-gitbase-factory-methods-to-facade_repository)
15
16
  - [Workstream C — C1: Prepare and flip top-level entry points to return `Git::Repository`](#workstream-c--c1-prepare-and-flip-top-level-entry-points-to-return-gitrepository)
16
- - [Workstream D — C2+C3: Remove compatibility bridges](#workstream-d--c2c3-remove-compatibility-bridges)
17
+ - [Workstream D — C3: Remove compatibility fallbacks](#workstream-d--c3-remove-compatibility-fallbacks)
17
18
  - [Workstream E — Migrate or deprecate instance helper methods](#workstream-e--migrate-or-deprecate-instance-helper-methods)
18
19
  - [Workstream F — `Git` module utility methods still using `Git::Lib` directly](#workstream-f--git-module-utility-methods-still-using-gitlib-directly)
19
20
  - [Phase 3 dependency order](#phase-3-dependency-order)
@@ -31,6 +32,10 @@ risk and allows for a gradual, controlled migration to the new architecture.
31
32
  - [⏳ Commands To Migrate](#-commands-to-migrate)
32
33
  - [Phase 3: Refactoring the Public Interface](#phase-3-refactoring-the-public-interface)
33
34
  - [Phase 4: Final Cleanup and Release Preparation](#phase-4-final-cleanup-and-release-preparation)
35
+ - [Phase 4 step graph](#phase-4-step-graph)
36
+ - [Step A — Remove old code](#step-a--remove-old-code)
37
+ - [Step B — Finalize test suite](#step-b--finalize-test-suite)
38
+ - [Step C — Update documentation](#step-c--update-documentation)
34
39
 
35
40
  ## Progress Tracker
36
41
 
@@ -38,44 +43,68 @@ risk and allows for a gradual, controlled migration to the new architecture.
38
43
  | ----- | ------ | ----------- | :--------------: | :--------------: |
39
44
  | Phase 1 | ✅ Complete | Foundation and scaffolding | 5% | 100% |
40
45
  | Phase 2 | ✅ Complete | Migrating commands (all checklist items done) | 40% | 100% |
41
- | Phase 3 | In Progress | Refactoring public interface — see [Facade Modules Completed](#facade-modules-completed) and [Facade coverage checklist](#facade-coverage-checklist) | 45% | 50% |
46
+ | Phase 3 | Complete | Refactoring public interface — see [Facade Modules Completed](#facade-modules-completed) and [Facade coverage checklist](#facade-coverage-checklist) | 45% | 100% |
42
47
  | Phase 4 | 🔲 Not Started | Final cleanup and release | 10% | 0% |
43
- | **TOTAL** | -- | -- | **100%** | **68%** |
48
+ | **TOTAL** | -- | -- | **100%** | **90%** |
44
49
 
45
50
  ### Facade Modules Completed
46
51
 
47
52
  | Module | File | Included in `Git::Repository` | `Git::Base` delegates |
48
53
  | ------ | ---- | ------------------------------ | --------------------- |
49
- | `Git::Repository::Staging` | `lib/git/repository/staging.rb` | ✅ | `add`, `reset`, `rm`, `clean`, `ignored_files` |
54
+ | `Git::Repository::Staging` | `lib/git/repository/staging.rb` | ✅ | `add`, `reset`, `reset_hard`, `apply`, `apply_mail`, `read_tree`, `rm`, `mv`, `clean`, `ignored_files` |
50
55
  | `Git::Repository::Committing` | `lib/git/repository/committing.rb` | ✅ | `commit`, `commit_all`, `write_tree`; `commit_tree` and `write_and_commit_tree` wrap the SHA result in `Git::Object::Commit.new(self, ...)` |
51
- | `Git::Repository::Branching` | `lib/git/repository/branching.rb` | ✅ | `checkout`, `checkout_file`, `checkout_index`, `current_branch`, `local_branch?`, `remote_branch?`, `branch?`, `branch_delete`, `branch_new`, `branch_contains`, `branches_all`, `update_ref` |
56
+ | `Git::Repository::Branching` | `lib/git/repository/branching.rb` | ✅ | `checkout`, `checkout_file`, `checkout_index`, `current_branch`, `current_branch_state`, `local_branch?`, `remote_branch?`, `branch?`, `branch`, `branches`, `branch_delete`, `branch_new`, `change_head_branch`, `branch_contains`, `branches_all`, `update_ref` |
57
+ | `Git::Repository::ContextHelpers` | `lib/git/repository/context_helpers.rb` | ✅ | `chdir`, `with_index`, `with_temp_index`, `with_working`, `with_temp_working`, `set_index`, `set_working` |
52
58
  | `Git::Repository::Merging` | `lib/git/repository/merging.rb` | ✅ | `merge`, `revert`, `each_conflict`; `merge_base` wraps the returned SHA strings in `Git::Object::Commit.new(self, ...)` instances |
53
- | `Git::Repository::RemoteOperations` | `lib/git/repository/remote_operations.rb` | ✅ | `fetch`, `pull`, `push`, `add_remote`, `remove_remote`, `config_remote`, `remotes`, `set_remote_url`, `remote_set_branches` |
54
- | `Git::Repository::Stashing` | `lib/git/repository/stashing.rb` | ✅ | `stash_save`, `stash_apply`, `stash_clear`, `stashes_all` |
55
- | `Git::Repository::Diffing` | `lib/git/repository/diffing.rb` | ✅ | `diff_path_status`, `diff_name_status`, `diff_full` |
56
- | `Git::Repository::Inspecting` | `lib/git/repository/inspecting.rb` | ✅ | `show`, `fsck` |
57
- | `Git::Repository::ObjectOperations` | `lib/git/repository/object_operations.rb` | ✅ | `rev_parse`, `tree_depth`, `ls_tree`, `grep`, `archive`, `tags`, `add_tag`, `delete_tag` |
59
+ | `Git::Repository::RemoteOperations` | `lib/git/repository/remote_operations.rb` | ✅ | `fetch`, `pull`, `push`, `remote_add` (alias: `add_remote`), `remote_remove` (alias: `remove_remote`), `remote_set_url` (alias: `set_remote_url`), `config_remote`, `remote`, `remotes`, `ls_remote`, `remote_set_branches` |
60
+ | `Git::Repository::Stashing` | `lib/git/repository/stashing.rb` | ✅ | `stash_list`, `stash_save`, `stash_apply`, `stash_clear`, `stashes_all` |
61
+ | `Git::Repository::Diffing` | `lib/git/repository/diffing.rb` | ✅ | `diff_full`, `diff_numstat`, `diff_stats`, `diff`, `diff_path_status` (alias: `diff_name_status`), `diff_files`, `diff_index` |
62
+ | `Git::Repository::Inspecting` | `lib/git/repository/inspecting.rb` | ✅ | `describe`, `show`, `fsck` |
58
63
  | `Git::Repository::Logging` | `lib/git/repository/logging.rb` | ✅ | `log`, `full_log_commits` |
59
- | `Git::Repository::StatusOperations` | `lib/git/repository/status_operations.rb` | ✅ | `ls_files`, `no_commits?` (renamed from `Git::Lib#empty?`), `untracked_files`, `status`; `Git::Base#ls_files` delegates to facade |
60
- | `Git::Repository::Configuring` | `lib/git/repository/configuring.rb` | ✅ | `config`; `Git::Base#config` delegates to facade |
64
+ | `Git::Repository::Maintenance` | `lib/git/repository/maintenance.rb` | ✅ | `repack`, `gc` |
65
+ | `Git::Repository::ObjectOperations` | `lib/git/repository/object_operations.rb` | ✅ | `cat_file_contents`, `cat_file_size`, `cat_file_type`, `cat_file_commit`, `cat_file_tag`, `rev_parse`, `tag_sha`, `full_tree`, `tree_depth`, `name_rev`, `ls_tree`, `grep`, `archive`, `gblob`, `gcommit`, `gtree`, `tag`, `object`, `tags`, `add_tag`, `delete_tag` |
66
+ | `Git::Repository::StatusOperations` | `lib/git/repository/status_operations.rb` | ✅ | `ls_files`, `no_commits?` / `empty?`, `untracked_files`, `status` |
67
+ | `Git::Repository::Configuring` | `lib/git/repository/configuring.rb` | ✅ | `config`, `config_get`, `config_list`, `config_set`, `global_config`, `global_config_get`, `global_config_list`, `global_config_set` |
61
68
  | `Git::Repository::WorktreeOperations` | `lib/git/repository/worktree_operations.rb` | ✅ | `worktrees_all`, `worktree_add`, `worktree_remove`, `worktree_prune`, `worktree`, `worktrees` |
62
69
 
63
70
  #### Facade module naming convention
64
71
 
65
- New topic modules follow a **two-tier** convention:
72
+ New topic modules follow a **three-tier** convention:
66
73
 
67
74
  - **Gerund** (verb-ing) when a single action word clearly names the whole module:
68
- `Staging`, `Committing`, `Branching`, `Merging`, `Logging`, `Diffing`, `Stashing`, `Configuring`.
75
+ `Staging`, `Committing`, `Branching`, `Merging`, `Logging`, `Diffing`, `Stashing`,
76
+ `Configuring`, `Inspecting`.
69
77
  - **Noun + `Operations`** when the module is a mixed bag of methods grouped by git
70
78
  concept rather than a single action: `RemoteOperations`, `ObjectOperations`,
71
79
  `StatusOperations`, `WorktreeOperations`.
80
+ - **Descriptive utility names** for cross-cutting helpers or housekeeping APIs that
81
+ are not domain-object names: `ContextHelpers`, `Maintenance`.
72
82
 
73
83
  Do **not** use plain nouns that clash with existing domain-object class names
74
84
  such as `Branch`, `Diff`, `Log`, `Object`, `Remote`, `Status`, `Worktree`, etc.
75
85
 
76
86
  ### Next Task
77
87
 
78
- #### Phase 3 Public Interface Completion
88
+ #### D2 / Phase 4 is the remaining redesign step
89
+
90
+ F1 and F2 are both ✅ complete. All Phase 4 prerequisites are now satisfied, and
91
+ the remaining unchecked redesign item is D2.
92
+
93
+ Phase 4 (final cleanup and release — deleting `Git::Base`/`Git::Lib`) can now begin.
94
+ The first cleanup PR should remove the `base_object` / `from_base` bridge in the
95
+ same releasable change that deletes or retires `Git::Base`.
96
+ The following are also required and are already ✅ complete:
97
+
98
+ | Step | Status |
99
+ | ---- | ------ |
100
+ | C1c-2: public-API parity audit and remediation sweep | ✅ |
101
+ | E: block-based helper/path-context methods migrated | ✅ |
102
+
103
+ Steps C1d-1, C1d-2, and C1d-3 are ✅ complete (see their detail sections below for full specs).
104
+
105
+ ---
106
+
107
+ #### Phase 3 Overview
79
108
 
80
109
  All 9 domain-object migrations are ✅ complete:
81
110
 
@@ -91,19 +120,10 @@ All 9 domain-object migrations are ✅ complete:
91
120
  | `Git::Branches` | [PR #1356](https://github.com/ruby-git/ruby-git/pull/1356), [PR #1357](https://github.com/ruby-git/ruby-git/pull/1357), [PR #1358](https://github.com/ruby-git/ruby-git/pull/1358), [PR #1359](https://github.com/ruby-git/ruby-git/pull/1359) |
92
121
  | `Git::Worktree` + `Git::Worktrees` | — |
93
122
 
94
- The remaining work splits into six workstreams:
95
-
96
- - Workstream A adds missing `Git::Repository` facade methods
97
- - B wires `Git::Base` factory methods to call the facade
98
- - C moves construction/global state and flips the top-level entry points
99
- - D removes compatibility bridges
100
- - E migrates helper/path-context methods
101
- - F removes the last `Git` module utility calls that still route through `Git::Lib`
102
-
103
- The required `Git::Commands::*` classes already exist (`Clone`, `LsRemote`,
104
- `ConfigOptionSyntax::*`, `Rm`, `Clean`, `Show`, `Fsck`, etc.). The remaining work is
105
- facade/adapter wiring, parser reuse, and public-API parity decisions — not new
106
- command-layer scaffolding. The full scope is defined in Workstreams A–F below.
123
+ The work was organized into six workstreams (A–F). All workstreams that are
124
+ prerequisites for C1d are now ✅ complete. F1 and F2 are both ✅ complete — F2
125
+ moved the remaining `Git` module utility methods off `Git::Lib`. Phase 4 is
126
+ ready to proceed.
107
127
 
108
128
  **Sequencing** (see [Phase 3 dependency order](#phase-3-dependency-order) for the
109
129
  reasoning behind each edge):
@@ -121,8 +141,8 @@ graph LR
121
141
  C1a-2 --> C1c-2
122
142
  C1b --> C1c-2
123
143
  C1c-1 --> C1c-2
124
- C1c-2 --> C1d
125
- C1d --> D1 --> Phase4["Phase 4"]
144
+ C1c-2 --> C1d-1
145
+ C1d-1 --> C1d-2 --> C1d-3 --> D1 --> Phase4["Phase 4"]
126
146
  D2 --> Phase4
127
147
  F1 --> Phase4
128
148
  F2 --> Phase4
@@ -177,9 +197,10 @@ These are read-only repository inspection operations that don't fit an existing
177
197
 
178
198
  Files touched: `lib/git/repository/inspecting.rb` (new), `lib/git/repository.rb` (add `include Git::Repository::Inspecting`), `spec/unit/git/repository/inspecting_spec.rb` (new), `lib/git/base.rb`
179
199
 
180
- **Not covered by A1–A4:** lower-level public methods such as `describe`, `repack`,
181
- `gc`, `apply`, `apply_mail`, `read_tree`, and `cat_file` are handled by the C1c-2
182
- public-API parity audit before `Git.open` starts returning `Git::Repository`.
200
+ **Later covered by C1c-2:** lower-level public methods such as `describe`,
201
+ `repack`, `gc`, `apply`, `apply_mail`, `read_tree`, and `cat_file_*` were
202
+ subsequently migrated into `Inspecting`, `Maintenance`, `Staging`, and
203
+ `ObjectOperations` before `Git.open` started returning `Git::Repository`.
183
204
 
184
205
  ---
185
206
 
@@ -228,7 +249,7 @@ This workstream is intentionally split into two PRs because the path/accessor
228
249
  state work is independent of the clone/init work, and combining them would make a
229
250
  very large PR.
230
251
 
231
- **Step C1a-1 — Path state, accessors, and `.open`/`.bare` factories**
252
+ **Step C1a-1 — Path state, accessors, and `.open`/`.bare` factories**
232
253
 
233
254
  | `Git::Base` class method | Target |
234
255
  | --- | --- |
@@ -242,7 +263,7 @@ must also expose the path/accessor surface currently provided by `Git::Base`: `d
242
263
 
243
264
  Files touched: `lib/git/repository.rb`, `lib/git/base.rb`
244
265
 
245
- **Step C1a-2 — `.clone` and `.init` factories**
266
+ **Step C1a-2 — `.clone` and `.init` factories**
246
267
 
247
268
  | `Git::Base` / `Git` method | Target |
248
269
  | --- | --- |
@@ -259,7 +280,7 @@ Workstream F.
259
280
 
260
281
  Files touched: `lib/git/repository.rb`, `lib/git/base.rb`, `lib/git.rb`
261
282
 
262
- **Step C1b — Move global config singleton ownership off `Git::Base`**
283
+ **Step C1b — Move global config singleton ownership off `Git::Base`**
263
284
 
264
285
  `Git.configure` and `Git.config` both delegate to `Base.config`, which returns the
265
286
  `Git::Base`-owned `Git::Config` singleton. When `Git::Base` is deleted, these break.
@@ -286,7 +307,7 @@ documented as a v5 breaking change or already deprecated for removal. This audit
286
307
  the gate that prevents the entry-point flip from silently dropping public methods
287
308
  just because `Git::Base` still exists in the tree.
288
309
 
289
- **Step C1c-1 — Signature-compatibility guidance and process**
310
+ **Step C1c-1 — Signature-compatibility guidance and process**
290
311
 
291
312
  Update extraction and review skills to document the signature-compatibility
292
313
  classification policy (legacy-contract vs 5.x-native), parity-check requirements,
@@ -305,7 +326,7 @@ Files touched: `.github/skills/extract-facade-from-base-lib/SKILL.md`,
305
326
 
306
327
  Tracked as [Issue #1369](https://github.com/ruby-git/ruby-git/issues/1369).
307
328
 
308
- **Step C1c-2 — End-of-Phase-3 public-API parity audit and remediation sweep**
329
+ **Step C1c-2 — End-of-Phase-3 public-API parity audit and remediation sweep**
309
330
 
310
331
  Compare every public `Git::Base` method against `Git::Repository`; fix mismatches
311
332
  or explicitly record each as a documented v5 breaking change. No unclassified
@@ -317,7 +338,7 @@ Required audit buckets:
317
338
  | --- | --- |
318
339
  | Path/accessors | `dir`, `repo`, `index`, `repo_size` must exist on `Git::Repository` (C1a-1 owns this) |
319
340
  | Compatibility aliases/wrappers | `remove`, `revparse`, `diff_name_status`, `reset_hard`, `is_local_branch?`, `is_remote_branch?`, `is_branch?`, `checkout` must be migrated or intentionally removed with upgrade notes (`checkout` is called by `Git.export` on the `Git.clone` result) |
320
- | Low-level public methods | `describe`, `repack`, `gc`, `apply`, `apply_mail`, `read_tree`, `cat_file` must be migrated to topic modules or intentionally removed with upgrade notes |
341
+ | Low-level public methods | Resolved in the current tree: `describe` `Inspecting`; `repack`/`gc` `Maintenance`; `apply`/`apply_mail`/`read_tree` `Staging`; `cat_file_*` `ObjectOperations`. Any intentional removals still require upgrade notes. |
321
342
  | Factory/domain-object returns | Confirm B plus A2/A3 cover `branch`, `branches`, `remote`, `remotes`, `tag`, `tags`, object factories, and tag create/delete return shapes |
322
343
  | Keyword-arg facades | For `legacy-contract` methods, preserve the exact 4.x call shape (including rare `**opts` signatures); for `5.x-native` methods, use `opts = {}` style for consistency |
323
344
 
@@ -326,15 +347,38 @@ Files touched: `lib/git/repository/*.rb` (topic modules for migrated methods),
326
347
 
327
348
  Tracked as [Issue #1370](https://github.com/ruby-git/ruby-git/issues/1370).
328
349
 
329
- **Step C1d — Update `lib/git.rb` entry points to return `Git::Repository`**
350
+ ##### Step C1d-1Flip entry points
330
351
 
331
352
  With C1a, C1b, C1c, A, B, and E in place, update `Git.open`, `Git.clone`,
332
353
  `Git.init`, and `Git.bare` in `lib/git.rb` to call `Git::Repository.*` and return
333
354
  `Git::Repository` directly, bypassing `Git::Base` entirely.
334
355
 
356
+ **Prerequisite fix before landing C1d-1:** delete `spec/integration/git/lib/config_spec.rb`
357
+ after confirming behavior coverage exists in `spec/integration/git/repository/configuring_spec.rb`.
358
+ The `def lib = self` shim causes `subject(:lib) { repo.lib }` to return `Git::Repository` (self),
359
+ which triggers deprecation warnings from every deprecated alias call (config_set, config_get,
360
+ global_config_set, etc.) in that spec.
361
+
362
+ ##### Step C1d-2 — Eliminate internal `.lib` callers
363
+
364
+ Clean up all `.lib` callers from tests while the silent `def lib = self` shim is still in
365
+ place, then add `Git::Deprecation.behavior = :raise` to both test suites. See the phase table
366
+ in the [Next Task](#next-task) section for the full per-phase breakdown.
367
+
368
+ ##### Step C1d-3 — Remove dead fallbacks and add deprecation warning
369
+
370
+ - Add `diff_numstat` delegator to `Git::Base` (prerequisite: not currently defined there)
371
+ - Remove dead `respond_to?` + `.lib` fallback branches from `lib/git/diff.rb`,
372
+ `lib/git/diff_stats.rb`, `lib/git/diff_path_status.rb`, `lib/git/status.rb`
373
+ - Replace `def lib = self` in `lib/git/repository.rb` with a `Git::Deprecation.warn` body
374
+ (removal version: v6.0.0; returns `self`)
375
+ - Remove `command_capturing`, `command_streaming`, and private `env_overrides` from
376
+ `lib/git/repository.rb` — these were added only to feed the silent shim
377
+ - Add unit test asserting the deprecation warning and `self` return
378
+
335
379
  ---
336
380
 
337
- #### Workstream D — C2+C3: Remove compatibility bridges
381
+ #### Workstream D — C3: Remove compatibility fallbacks
338
382
 
339
383
  ⚠️ These are v5-only cleanup steps. They are not 4.x-compatible and must be kept out
340
384
  of 4.x release candidates unless an explicit breaking-change decision has already
@@ -379,20 +423,6 @@ After D1, domain objects should assume their provider is `Git::Repository` (or a
379
423
  compatible object that implements the repository facade methods directly), not an
380
424
  object with a `.lib` escape hatch.
381
425
 
382
- ##### Step D2 — Remove the `base_object` bridge
383
-
384
- ⚠️ Do **not** ship D2 as a standalone PR while `Git::Base` remains functional.
385
- `Git::Base#facade_repository` currently depends on
386
- `Git::ExecutionContext::Repository.from_base(self)`, so deleting the bridge before
387
- deleting or retiring `Git::Base` would leave the tree unreleasable.
388
-
389
- D2 belongs in the Phase 4 old-code deletion PR (or in the same v5 cleanup PR that
390
- removes `Git::Base` as a usable public entry point):
391
-
392
- - Delete `attr_reader :base_object`
393
- - Remove `base_object:` from `#initialize` and body
394
- - Remove or convert `from_base` factory
395
-
396
426
  ---
397
427
 
398
428
  #### Workstream E — Migrate or deprecate instance helper methods
@@ -405,7 +435,7 @@ helpers would drop existing public `Git::Base` behavior.
405
435
  `Git::Repository`. They must either be migrated before `Git::Base` can be deleted,
406
436
  or explicitly deprecated with removal in v6.0. The recommended path is migration.
407
437
 
408
- **Step E — Migrate block-based helper/path-context methods to `Git::Repository`**
438
+ **Step E — Migrate block-based helper/path-context methods to `Git::Repository`**
409
439
 
410
440
  | `Git::Base` method | Proposed destination | Notes |
411
441
  | --- | --- | --- |
@@ -419,8 +449,8 @@ or explicitly deprecated with removal in v6.0. The recommended path is migration
419
449
  removed at the same time, since `with_index`/`with_working` depend on the same
420
450
  invalidation logic.
421
451
 
422
- Files touched: `lib/git/repository.rb` (or a new `Git::Repository::ContextHelpers`
423
- module), `lib/git/base.rb`, `spec/unit/git/repository/` (new or extended spec)
452
+ Files touched: `lib/git/repository/context_helpers.rb`, `lib/git/base.rb`,
453
+ `spec/unit/git/repository/` (new or extended spec)
424
454
 
425
455
  ---
426
456
 
@@ -434,7 +464,7 @@ Three `Git`-module-level methods bypass `Git::Repository` entirely and call
434
464
  non-`Git::Lib` adapter path using `Git::ExecutionContext::Global` plus existing
435
465
  parsing logic.
436
466
 
437
- **Step F1 — Move `Git.ls_remote` and `Git.default_branch` off `Git::Lib`**
467
+ **Step F1 — Move `Git.ls_remote` and `Git.default_branch` off `Git::Lib`**
438
468
 
439
469
  | `Git` module method | Current path | Required work |
440
470
  | --- | --- | --- |
@@ -449,7 +479,7 @@ use the same command class.
449
479
  Files touched: `lib/git.rb`, `lib/git/base.rb`, and parser/helper code extracted
450
480
  from `Git::Lib` as needed
451
481
 
452
- **Step F2 — Move `Git.global_config`, `#config`, and `#global_config` off `Git::Lib`**
482
+ **Step F2 — Move `Git.global_config`, `#config`, and `#global_config` off `Git::Lib`**
453
483
 
454
484
  | `Git` module method | Current path | Required work |
455
485
  | --- | --- | --- |
@@ -494,19 +524,15 @@ classified as a v5-only PR with upgrade-note coverage before it lands.
494
524
  | A4 | ✅ | Add `Inspecting#show` and `#fsck` | 4.x-compatible | `Git::Base#show` and `#fsck` remain behavior-compatible and delegate internally. |
495
525
  | B | ✅ | Redirect `Git::Base` domain-object factories | 4.x-compatible | Method signatures and return types stay the same; only the internal provider changes to `Git::Repository`. Split into object/tag factories and branch/remote factories if the PR grows. |
496
526
  | C1a-1 | ✅ | Add `Git::Repository.open`/`.bare`, path state, and `dir`/`repo`/`index`/`repo_size` | 4.x-compatible additive | `Git.open`/`.bare` still return `Git::Base`; new repository factories are additive until C1d. |
497
- | C1a-2 | | Add `Git::Repository.clone`/`.init` | 4.x-compatible additive | `Git.clone`/`.init` still return `Git::Base`; clone/init behavior is duplicated behind new factories without changing public entry points. |
498
- | C1b | | Move global config ownership | 4.x-compatible | `Git.config`, `Git.configure`, and `Git::Base.config` keep working; `Git::Base.config` remains as a delegator. |
499
- | E | | Add repository helper/path-context methods | 4.x-compatible additive | `Git::Base` helpers keep working; `Git::Repository` gains equivalent behavior before any top-level return-type change. Split index helpers and working-directory helpers if needed. |
500
- | F1 | | Move `Git.ls_remote` and `Git.default_branch` off `Git::Lib` | 4.x-compatible | Return formats and error behavior match current 4.x-compatible behavior. |
501
- | F2 | | Move `Git.global_config`, module `#config`, and module `#global_config` off `Git::Lib` | 4.x-compatible | Config methods keep the same return formats and write behavior. |
502
- | C1c-1 | | Guidance/process: signature-compatibility policy for extraction and review ([#1369](https://github.com/ruby-git/ruby-git/issues/1369)) | 4.x-compatible / docs-only | Guidance and review checklists define legacy-contract vs 5.x-native signatures, including test expectations. |
503
- | C1c-2 | | End-of-Phase-3 public-API parity audit and remediation sweep ([#1370](https://github.com/ruby-git/ruby-git/issues/1370)) | 4.x-compatible | All four parity audit buckets resolved (fix or documented removal) before C1d; no unclassified compatibility gap remains. |
504
- | C1d | | Flip `Git.open`/`.clone`/`.init`/`.bare` to return `Git::Repository` | v5 boundary | Explicit breaking change because class identity changes from `Git::Base` to `Git::Repository`; method-level parity must be complete first. |
505
- | D1 | | Remove domain-object `Git::Base` guards and `@base.lib` fallbacks | v5 cleanup | Explicitly drops direct `Git::Base` provider support in domain-object constructors; normal factory-created objects remain supported. |
506
- | D2 / Phase 4 | ⬜ | Remove `base_object`/`from_base` with `Git::Base` deletion or retirement | v5 cleanup | Must land with the old-code deletion path; not releasable as a standalone PR while `Git::Base#facade_repository` depends on it. |
507
-
508
- ---
509
-
527
+ | C1a-2 | | Add `Git::Repository.clone`/`.init` | 4.x-compatible additive | `Git.clone`/`.init` still return `Git::Base`; clone/init behavior is duplicated behind new factories without changing public entry points. |
528
+ | C1b | [#1385](https://github.com/ruby-git/ruby-git/pull/1385) | Move global config ownership | 4.x-compatible | `Git.config`, `Git.configure`, and `Git::Base.config` keep working; `Git::Base.config` remains as a delegator. |
529
+ | E | | Add repository helper/path-context methods | 4.x-compatible additive | `Git::Base` helpers keep working; `Git::Repository` gains equivalent behavior before any top-level return-type change. Split index helpers and working-directory helpers if needed. |
530
+ | F1 | | Move `Git.ls_remote` and `Git.default_branch` off `Git::Lib` | 4.x-compatible | Return formats and error behavior match current 4.x-compatible behavior. |
531
+ | F2 | | Move `Git.global_config`, module `#config`, and module `#global_config` off `Git::Lib` | 4.x-compatible | Config methods keep the same return formats and write behavior. |
532
+ | C1c-1 | | Guidance/process: signature-compatibility policy for extraction and review ([#1369](https://github.com/ruby-git/ruby-git/issues/1369)) | 4.x-compatible / docs-only | Guidance and review checklists define legacy-contract vs 5.x-native signatures, including test expectations. |
533
+ | C1c-2 | | End-of-Phase-3 public-API parity audit and remediation sweep ([#1370](https://github.com/ruby-git/ruby-git/issues/1370)) | 4.x-compatible | All four parity audit buckets resolved (fix or documented removal) before C1d; no unclassified compatibility gap remains. |
534
+ | C1d | | Flip `Git.open`/`.clone`/`.init`/`.bare` to return `Git::Repository` | v5 boundary | Explicit breaking change because class identity changes from `Git::Base` to `Git::Repository`; method-level parity must be complete first. Split into C1d-1 (entry point flip), C1d-2 (eliminate internal .lib callers + add deprecation enforcement to both test suites), and C1d-3 (remove dead fallbacks + replace silent lib shim with real deprecation warning). |
535
+ | D1 | | Remove domain-object `Git::Base` guards and `@base.lib` fallbacks | v5 cleanup | Explicitly drops direct `Git::Base` provider support in domain-object constructors; normal factory-created objects remain supported. |
510
536
  #### Phase 3 completion criteria
511
537
 
512
538
  Use this table to decide whether a checklist item can be marked complete. A step is
@@ -526,7 +552,6 @@ done only when its code, focused specs, and delegation/cleanup checks are all tr
526
552
  | C1c-2: public-API parity audit and remediation | End-of-Phase-3 sweep complete (Issue #1370): a public-method inventory compares `Git::Base` and `Git::Repository`; every surviving public method has a repository implementation and focused coverage; every intentional removal has an upgrade-note/deprecation decision; no unclassified compatibility gap remains. |
527
553
  | C1d: entry-point flip | `Git.open`, `Git.clone`, `Git.init`, and `Git.bare` return `Git::Repository`; common existing workflows still pass through those entry points; YARD return docs are updated; no top-level factory method calls `Git::Base.*`; full suite passes. |
528
554
  | D1: domain-object fallback removal | No `is_a?(Git::Base)` guards remain; no `@base.lib` fallback remains in domain objects; direct `Git::Base` provider support is documented as a v5-only removal; full suite passes. |
529
- | D2 / Phase 4: `base_object` bridge removal | `Git::ExecutionContext::Repository` no longer accepts or exposes `base_object`; `from_base` is removed or converted to a non-`Git::Base` path; this lands only with the PR that deletes or retires `Git::Base`, so no releasable state contains a broken `Git::Base#facade_repository`. |
530
555
  | E: instance helper methods | `Git::Repository` implements or explicitly deprecates `chdir`, `with_index`, `with_temp_index`, `with_working`, `with_temp_working`, `set_index`, and `set_working`; context rebuilding after index/worktree changes is covered by specs; helpers yield the same values and restore state after block exit/errors. |
531
556
  | F: `Git` module utilities off `Git::Lib` | `Git.default_branch`, `Git.global_config`, `Git.ls_remote`, module instance `#config`, and module instance `#global_config` no longer call `Git::Lib.new`; `Git::Base.repository_default_branch` migrated to use `Git::Commands::LsRemote` directly; existing `LsRemote` and `ConfigOptionSyntax` commands provide the behavior; parser/helper code needed from `Git::Lib` has moved; `grep -n 'Lib.new' lib/git.rb` returns no matches. |
532
557
 
@@ -542,15 +567,14 @@ done only when its code, focused specs, and delegation/cleanup checks are all tr
542
567
  | A4: new `Inspecting` — `show`, `fsck` | ✅ |
543
568
  | B (C0): `Git::Base` factory delegation wiring | ✅ |
544
569
  | C1a-1: `Git::Repository.open`/`.bare`, path state (`dir`, `repo`, `index`, `repo_size`) | ✅ |
545
- | C1a-2: `Git::Repository.clone`/`.init` (no `Git::Lib` dependency) | |
546
- | C1b: Global config ownership (`Base.config` → `Git::Config`) | |
547
- | C1c-1: Guidance/process updates for signature compatibility (#1369) | |
548
- | C1c-2: End-of-Phase-3 public-API parity audit and remediation (#1370) | |
549
- | C1d: Entry-point flip (`Git.open` etc. → `Git::Repository`) | |
550
- | D1 (C3): Remove `is_a?(Git::Base)` guards + `@base.lib` fallbacks | (v5 cleanup) |
551
- | D2 (C2 / Phase 4): Remove `base_object` bridge with `Git::Base` deletion | (v5 cleanup) |
552
- | E: Instance helpers (`#chdir`, `#with_index`, `#with_temp_index`, `#with_working`, `#with_temp_working`) | |
553
- | F: `Git` module utilities (`default_branch`, `global_config`, `ls_remote`) off `Git::Lib` | ⬜ (Phase 4 prereq) |
570
+ | C1a-2: `Git::Repository.clone`/`.init` (no `Git::Lib` dependency) | |
571
+ | C1b: Global config ownership (`Base.config` → `Git::Config`) | |
572
+ | C1c-1: Guidance/process updates for signature compatibility (#1369) | |
573
+ | C1c-2: End-of-Phase-3 public-API parity audit and remediation (#1370) | |
574
+ | C1d: Entry-point flip (`Git.open` etc. → `Git::Repository`) | |
575
+ | D1 (C3): Remove `is_a?(Git::Base)` guards + `@base.lib` fallbacks | |
576
+ | E: Instance helpers (`#chdir`, `#with_index`, `#with_temp_index`, `#with_working`, `#with_temp_working`) | |
577
+ | F: `Git` module utilities (`default_branch`, `global_config`, `ls_remote`) off `Git::Lib` | |
554
578
 
555
579
  #### Quality gates (per step)
556
580
 
@@ -580,7 +604,7 @@ logic. The gem will be fully functional after this phase.*
580
604
  1. **Create New Directory Structure**
581
605
 
582
606
  - `lib/git/commands/` ✅
583
- - `lib/git/repository/` ✅ — populated with 12 facade modules in Phase 3 (see [Facade Modules Completed](#facade-modules-completed))
607
+ - `lib/git/repository/` ✅ — populated with 15 included modules in Phase 3 (see [Facade Modules Completed](#facade-modules-completed))
584
608
 
585
609
  2. **Eliminate Custom Path Classes**
586
610
 
@@ -602,14 +626,14 @@ logic. The gem will be fully functional after this phase.*
602
626
  - `Git::ExecutionContext::Global` subclass in `lib/git/execution_context/global.rb` ✅
603
627
 
604
628
  - `Git::Repository` in `lib/git/repository.rb` ✅
605
- - Now includes 12 facade modules (see [Facade Modules Completed](#facade-modules-completed))
629
+ - Now includes 15 modules via `include` (see [Facade Modules Completed](#facade-modules-completed))
606
630
 
607
631
  - `Git::Commands::Arguments` DSL in `lib/git/commands/arguments.rb` ✅
608
632
  - Provides declarative argument definition for command classes
609
633
 
610
634
  4. **Set Up RSpec Environment**
611
635
 
612
- RSpec configured and working alongside TestUnit. Specs live in `spec/` and can be
636
+ RSpec configured and working alongside Test::Unit. Specs live in `spec/` and can be
613
637
  run with `bundle exec rspec`. ✅
614
638
 
615
639
  ## Phase 2: The Strangler Fig Pattern - Migrating Commands
@@ -1254,7 +1278,7 @@ future work:
1254
1278
  instantiate and call the new `Git::Commands::Add` object, passing `self` as the
1255
1279
  context.
1256
1280
 
1257
- - **Verify**: Run the full test suite (both TestUnit and RSpec). The existing tests
1281
+ - **Verify**: Run the full test suite (both Test::Unit and RSpec). The existing tests
1258
1282
  for `g.add` should still pass, but they will now be executing the new, refactored
1259
1283
  code.
1260
1284
 
@@ -1483,7 +1507,9 @@ order: Basic Snapshotting → Branching & Merging → etc.
1483
1507
  ***Goal**: Switch the public-facing classes to use the new architecture directly,
1484
1508
  breaking the final ties to the old implementation.*
1485
1509
 
1486
- > **Status**: Task 1 below is complete; Task 2 is in progress see the [Next Task](#next-task) section above for the current plan.
1510
+ > **Status**: Phase 3 is complete. Tasks 1 and 2 are both complete; the remaining
1511
+ > redesign work is the Phase 4 cleanup described in the [Next Task](#next-task)
1512
+ > section above.
1487
1513
 
1488
1514
  1. **Add `binary_path:` to `Git::ExecutionContext`** ✅
1489
1515
 
@@ -1493,43 +1519,54 @@ breaking the final ties to the old implementation.*
1493
1519
  stopgap in `Git.run_git_version` was replaced with
1494
1520
  `Git::Commands::Version.new(Git::ExecutionContext::Global.new(...)).call`.
1495
1521
 
1496
- 2. **Implement the Facade**
1522
+ 2. **Implement the Facade**
1497
1523
 
1498
- `Git::Repository` now includes 12 facade modules (see
1499
- [Facade Modules Completed](#facade-modules-completed)). `Git::Base` wraps the
1500
- corresponding methods via `facade_repository`. The domain-object migration
1501
- iterations (iters 1–9) add further facade methods, but full `Git::Base`
1502
- coverage requires additional facade PRs for methods not touched by those
1503
- iterations (e.g. `clean`, `rm`, `tags`/`add_tag`, `fsck`, `show`, `remotes`,
1504
- remote URL/branch helpers) before the cleanup PR can run.
1524
+ `Git::Repository` now includes 15 modules via `include` in
1525
+ `lib/git/repository.rb` (see [Facade Modules Completed](#facade-modules-completed)).
1526
+ `Git::Base` wraps the corresponding methods via `facade_repository`, and the
1527
+ end-of-Phase-3 parity sweep landed the remaining low-level facade coverage
1528
+ needed before the entry-point flip including `describe`, `show`, `fsck`,
1529
+ `apply`, `apply_mail`, `read_tree`, `cat_file_*`, `repack`, `gc`, helper/path
1530
+ context methods, and the remaining remote/tag convenience APIs.
1505
1531
 
1506
1532
  ## Phase 4: Final Cleanup and Release Preparation
1507
1533
 
1508
1534
  ***Goal**: Remove all old code, finalize the test suite, and prepare for the v5.0.0
1509
1535
  release.*
1510
1536
 
1511
- 1. **Remove Old Code**:
1537
+ ### Phase 4 step graph
1512
1538
 
1513
- - Delete the `Git::Lib` class entirely.
1539
+ ```mermaid
1540
+ graph LR
1541
+ A --> B
1542
+ B --> C
1543
+ ```
1514
1544
 
1515
- - Delete the `Git::Base` class file.
1545
+ #### Step A Remove old code
1516
1546
 
1517
- - Remove any other dead code that was part of the old implementation.
1547
+ - Delete `attr_reader :base_object`, remove `base_object:` from `#initialize`, and remove or convert `from_base`.
1548
+ - Delete the `Git::Lib` class entirely.
1549
+ - Delete the `Git::Base` class file.
1550
+ - Remove any other dead code that was part of the old implementation.
1518
1551
 
1519
- 2. **Finalize Test Suite**:
1552
+ **Done when**: `lib/git/lib.rb` and `lib/git/base.rb` are deleted; `Git::ExecutionContext::Repository` no longer accepts or exposes `base_object`; no references to `Git::Lib` or `Git::Base` remain in `lib/`.
1520
1553
 
1521
- - Convert any remaining, relevant TestUnit tests to RSpec.
1554
+ **Planning tip**: Before generating a deletion plan, audit all remaining callers of `Git::Lib`, `Git::Base`, and `from_base` across `lib/` and `spec/`. The bridge removal and `Git::Base` deletion must land atomically in the same PR — plan for a single large deletion commit rather than incremental removals.
1522
1555
 
1523
- - Remove the `test-unit` dependency from the `Gemfile`.
1556
+ #### Step B Finalize test suite
1524
1557
 
1525
- - Ensure the RSpec suite has comprehensive coverage for the new architecture.
1558
+ - Convert any remaining, relevant Test::Unit tests to RSpec.
1559
+ - Remove the `test-unit` dependency from the `Gemfile`.
1560
+ - Ensure the RSpec suite has comprehensive coverage for the new architecture.
1526
1561
 
1527
- 3. **Update Documentation**:
1562
+ **Done when**: The `tests/` directory is empty or removed; `test-unit` is no longer
1563
+ in `Gemfile`; RSpec is the sole test framework.
1528
1564
 
1529
- - Thoroughly document the new public API (`Git`, `Git::Repository`, etc.).
1565
+ #### Step C Update documentation
1530
1566
 
1531
- - Mark all internal classes (`ExecutionContext`, `Commands`, `*Path`) with `@api
1532
- private` in the YARD documentation.
1567
+ - Thoroughly document the new public API (`Git`, `Git::Repository`, etc.).
1568
+ - Mark all internal classes (`ExecutionContext`, `Commands`, `*Path`) with `@api private` in the YARD documentation.
1569
+ - Update the `README.md` and create a `UPGRADING.md` guide explaining the breaking changes for v5.0.0.
1533
1570
 
1534
- - Update the `README.md` and create a `UPGRADING.md` guide explaining the breaking
1535
- changes for v5.0.0.
1571
+ **Done when**: `yard stats` reports no missing docs on public API; `UPGRADING.md`
1572
+ covers all breaking changes; `README.md` reflects the new entry points.