git 5.0.1 → 5.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08c43ba7ae36ad5b41333b4c5a4d1890ff32c32ad07074145ee75d71cde61b8d'
4
- data.tar.gz: 1380d2019f14ec54339aec4d7fced236098072794747edd38de8559aee8a6b66
3
+ metadata.gz: 94d97e48dd1d4b34affe837d38258f7b0f7edf02338d0e0def333ac80e147244
4
+ data.tar.gz: 5367c11505c46d9745d492a97671346531fddfdc3649b445bae9eb2636f87202
5
5
  SHA512:
6
- metadata.gz: fe650cffb57c334881cda31e8f5a2e062c090bb1028c423647d5a429504c8d3ad96a6cb58812a3373ca0733f9c325e8dda3392bcd5ef4e53e561e80a17c5fa9d
7
- data.tar.gz: c66b6ccf6e4644c09550d035c0b90ad1eb7dfbf91fc7509f8461329e6a33ac55d7324653a1c7770101a20156b4297304f14098a4fb8f97d48e7b6409b751b6d7
6
+ metadata.gz: 4e404e6b31961cf3c71e391ce4898436f07de8dd2ffc37947281f103513241c531e21aa799ae32296ec6ef47d2b1dad465205fd3b0936ee104b6774870805391
7
+ data.tar.gz: 778bbd70beb547b4574e8d361acc2873320b42bd4b5f190012309a3b90da72d55468a8c5b4adf87a3ed773ab08945e7ac81b3d282c86bb8bda64821282a3c101
data/.gitignore CHANGED
@@ -21,4 +21,7 @@ rubocop-report.json
21
21
  # generated git reference docs
22
22
  git-reference/
23
23
 
24
+ # git versions built by bin/build-git-versions
25
+ git-versions/
26
+
24
27
  tmp
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "5.0.1"
2
+ ".": "5.0.2"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## [5.0.2](https://github.com/ruby-git/ruby-git/compare/v5.0.1...v5.0.2) (2026-08-02)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Add bin/build-git-versions and bin/test-git-versions scripts ([3314503](https://github.com/ruby-git/ruby-git/commit/3314503708efcec2f386ca97bb6d96309a6c5c1a))
14
+
15
+
16
+ ### Other Changes
17
+
18
+ * Align CONTRIBUTING.md with current architecture and testing conventions ([60ac8e9](https://github.com/ruby-git/ruby-git/commit/60ac8e940776a3fb4efe46a98574ca5bbfcd718e))
19
+ * Allow disabling SimpleCov via COVERAGE=false env var ([3788418](https://github.com/ruby-git/ruby-git/commit/37884189eb646013628f78b6671e9876f0ebb925))
20
+ * Allow disabling SimpleCov via COVERAGE=false env var ([3788418](https://github.com/ruby-git/ruby-git/commit/37884189eb646013628f78b6671e9876f0ebb925))
21
+ * Avoid git-version-dependent all-zero SHA in stash store integration spec ([82a15e5](https://github.com/ruby-git/ruby-git/commit/82a15e57ebca03df3c3802f153c3545bc46920f4))
22
+ * Make 5.0.0 release more prominent in README ([2c8c42d](https://github.com/ruby-git/ruby-git/commit/2c8c42d30a7d7d35e03f1c4f8489fa49c866cded))
23
+ * Move Git::Repository::Factories and PathResolver to Git namespace ([dd0ae7b](https://github.com/ruby-git/ruby-git/commit/dd0ae7b34b912187f150d56b38f6eeb14b8882bf))
24
+ * Update README badges ([079a121](https://github.com/ruby-git/ruby-git/commit/079a1211216666f190583b2bfd3124ebb823ae58))
25
+
8
26
  ## [5.0.1](https://github.com/ruby-git/ruby-git/compare/v5.0.0...v5.0.1) (2026-07-30)
9
27
 
10
28
 
data/CONTRIBUTING.md CHANGED
@@ -23,32 +23,28 @@
23
23
  - [Agent skills](#agent-skills)
24
24
  - [Design philosophy](#design-philosophy)
25
25
  - [Layered architecture](#layered-architecture)
26
- - [Command layer responsibilities](#command-layer-responsibilities)
27
- - [Wrapping a git command](#wrapping-a-git-command)
28
- - [Method placement](#method-placement)
29
- - [Method naming](#method-naming)
30
- - [Result class naming](#result-class-naming)
31
- - [Parameter naming](#parameter-naming)
32
- - [Parameter values](#parameter-values)
33
- - [Options](#options)
34
- - [Positional arguments](#positional-arguments)
35
- - [Output processing](#output-processing)
36
- - [From design to implementation](#from-design-to-implementation)
26
+ - [Implementing a git command](#implementing-a-git-command)
27
+ - [API design](#api-design)
28
+ - [Method placement](#method-placement)
29
+ - [Method naming](#method-naming)
30
+ - [Result class naming](#result-class-naming)
31
+ - [Parameter naming](#parameter-naming)
32
+ - [Parameter values](#parameter-values)
33
+ - [Output processing](#output-processing)
34
+ - [Implementation](#implementation)
37
35
  - [Example implementations](#example-implementations)
38
36
  - [Coding standards](#coding-standards)
39
37
  - [Commit message guidelines](#commit-message-guidelines)
40
38
  - [What does this mean for contributors?](#what-does-this-mean-for-contributors)
41
39
  - [What to know about Conventional Commits](#what-to-know-about-conventional-commits)
42
40
  - [Issue and PR references](#issue-and-pr-references)
43
- - [Unit tests](#unit-tests)
44
- - [RSpec best practices](#rspec-best-practices)
41
+ - [Testing guidelines](#testing-guidelines)
45
42
  - [Unit tests vs Integration tests](#unit-tests-vs-integration-tests)
46
43
  - [Building a specific version of the Git command-line](#building-a-specific-version-of-the-git-command-line)
47
44
  - [Install pre-requisites](#install-pre-requisites)
48
45
  - [Obtain Git source code](#obtain-git-source-code)
49
46
  - [Build git](#build-git)
50
47
  - [Use the new Git version](#use-the-new-git-version)
51
- - [Licensing](#licensing)
52
48
 
53
49
  ## Summary
54
50
 
@@ -199,10 +195,6 @@ This project maintains two active branches:
199
195
  - **`4.x`**: Maintenance branch for the v4.x release series. This branch receives bug
200
196
  fixes and backward-compatible improvements only.
201
197
 
202
- **Important:** Never commit directly to `main` or `4.x`. All changes must be
203
- submitted via pull requests from feature branches. This ensures proper code review,
204
- CI validation, and maintains a clean commit history.
205
-
206
198
  When submitting a pull request:
207
199
 
208
200
  - **New features and breaking changes**: Target the `main` branch
@@ -256,7 +248,11 @@ guidance that mirrors maintainer expectations:
256
248
 
257
249
  ## Design philosophy
258
250
 
259
- The `git` gem is designed as a lightweight wrapper around the `git` command-line
251
+ The `git` gem follows a design philosophy that allows users to leverage their
252
+ existing knowledge of Git while benefiting from the expressiveness and power of
253
+ Ruby's syntax and paradigms.
254
+
255
+ Its public API is designed as a lightweight wrapper around the `git` command-line
260
256
  tool, providing Ruby developers with a simple and intuitive interface for
261
257
  programmatically interacting with Git.
262
258
 
@@ -265,44 +261,51 @@ introduce unnecessary abstraction layers or modify Git's core functionality. Ins
265
261
  the gem maintains a close alignment with the existing `git` command-line interface,
266
262
  avoiding extensions or alterations that could lead to unexpected behaviors.
267
263
 
268
- By following this philosophy, the `git` gem allows users to leverage their existing
269
- knowledge of Git while benefiting from the expressiveness and power of Ruby's syntax
270
- and paradigms.
264
+ `git` commands generally translate to `Git::Repository` methods of the same name.
265
+ Positional arguments map to the `git` CLI operands (such as paths, SHAs, etc.) in the
266
+ same order. Keyword arguments map to `git` CLI options by long OR short name.
267
+
268
+ Some examples:
269
+
270
+ - To execute `git clone <url> --depth=1`, call `Git.clone(url, depth: 1)`
271
+ - To execute `git add <path> --force`, call `Git::Repository#add(path, force: true)`
271
272
 
272
273
  ## Layered architecture
273
274
 
274
- The three architectural layers each play a distinct role:
275
+ The `git` gem is organized into three architectural layers:
275
276
 
276
277
  | Layer | Responsibility | Mechanism |
277
278
  | --- | --- | --- |
278
- | **Facade** (`Git::Repository::*` and `Git` module) | Public API and policy | Normalizes Ruby arguments, sets safe defaults, calls one or more `Git::Commands::*` classes, and may parse output into public Ruby objects |
279
- | **Command** (`Git::Commands::*`) | Neutral git CLI interface | Declares CLI arguments via the [Arguments DSL](lib/git/commands/arguments.rb), executes git, and returns `Git::CommandLine::Result` |
280
- | **Execution** (`Git::ExecutionContext`) | Execution context and subprocess defaults | Carries repository/global execution settings such as working directory, environment, timeout, binary path, and logging; runs the git CLI with subprocess defaults such as `GIT_EDITOR='true'` |
281
-
282
- ### Command layer responsibilities
279
+ | **Facade** (`Git::Repository` and `Git`) | Public API | Normalizes Ruby arguments, sets safe defaults, calls one or more `Git::Commands::*` classes, and may parse output into public Ruby objects |
280
+ | **Command** (`Git::Commands::*`) | Neutral git CLI interface | Declares CLI arguments via the [Arguments DSL](lib/git/commands/arguments.rb), builds the git argv and executes git via `#call`, and returns `Git::CommandLine::Result` |
281
+ | **Execution** (`Git::ExecutionContext::*`) | Execution context and subprocess defaults | Carries execution settings such as working directory, environment, timeout, binary path, and logging; runs the git CLI with default global options (such as `-c color.ui=false`) and subprocess environment variables (such as `LC_ALL=en_US.UTF-8`) |
283
282
 
284
283
  Command classes (`Git::Commands::*`) are **faithful, neutral representations of the
285
284
  git CLI**. Each command class does the following:
286
285
 
287
- - Declares every CLI argument/option via the [Arguments DSL](lib/git/commands/arguments.rb)
288
- - Binds `#call` parameters with the [Arguments DSL](lib/git/commands/arguments.rb) to
289
- build the git argv
290
- - Executes a git CLI command via `Git::ExecutionContext`
291
- - Returns the raw git CLI result as a `Git::CommandLine::Result` object
292
-
293
- Command classes should not embed policy choices such as output-control flags, editor
294
- suppression, progress output, or verbose mode. These policy decisions belong to the
295
- `Git::Repository::*` facade methods, which set safe defaults at each call site when
296
- policy is needed. In most cases, the facade gives callers the choice to override those
297
- defaults when they have a legitimate reason (e.g., running in a TTY-attached
286
+ - Declares acceptable CLI arguments and options via the
287
+ [Arguments DSL](lib/git/commands/arguments.rb)
288
+ - Defines a `#call` method which:
289
+ - Maps its parameters to the git argv using the declared arguments
290
+ - Executes a git CLI command via `Git::ExecutionContext`
291
+ - Returns the unprocessed git CLI result as a `Git::CommandLine::Result` object
292
+
293
+ Command classes should not embed choices such as output format flags, editor
294
+ suppression, progress output, or verbose mode. These decisions belong to the facade
295
+ layer which sets them as needed. The facade layer may give callers the choice to
296
+ override those decisions when appropriate (e.g., running in a TTY-attached
298
297
  environment where an editor is desired).
299
298
 
300
299
  For example:
301
300
 
302
- - **Anti-pattern:** `literal '--no-edit'`, `literal '--verbose'`, or
303
- `literal '--no-progress'` inside a command class — embeds policy in the wrong layer
304
- - **Correct pattern:** `flag_option :edit, negatable: true` in the command; `edit:
305
- false` passed from the facade call site
301
+ - **Anti-pattern:** declaring non-overidable and non-default options in the Arguments
302
+ DSL to control output such as `literal '--no-edit'`, `literal '--verbose'`, or
303
+ `literal '--no-progress'` inside a command class. This embeds policy in the wrong
304
+ layer.
305
+ - **Correct pattern:** declaring options which allow the user of the command (often a
306
+ facade method) to set desired values such as: `flag_option :edit, negatable: true`.
307
+ This allows the facade to either accept the default or to hard code `edit: false`
308
+ if it is needed.
306
309
 
307
310
  This separation keeps command classes reusable across facade methods with different
308
311
  policy needs. For example, a facade method that parses command output may pass
@@ -311,41 +314,41 @@ a stable, parseable output shape. Those parser-contract options belong at the fa
311
314
  call site, not as hard-coded literals in the command class. Other facade methods can
312
315
  reuse the same command class with different options.
313
316
 
314
- ## Wrapping a git command
317
+ ## Implementing a git command
315
318
 
316
- This section guides you through wrapping a git command. The first subsections focus
317
- on **API design**: where methods belong, how to name them, and how to handle
318
- parameters and output. These describe the public interface that gem users will see.
319
+ Start with the official git documentation page for the command (e.g., `man git-add`
320
+ or the [git-scm.com](https://git-scm.com/docs) reference page). Its SYNOPSIS line
321
+ identifies the positional operands, and its OPTIONS section identifies the flags and
322
+ value options the Ruby method must expose.
319
323
 
320
- [From design to implementation](#from-design-to-implementation) then shows how to
321
- structure your code using the gem's three-layer architecture. The public API is
322
- `Git::Repository` (and the `Git` module), whose facade methods delegate directly to
323
- internal `Git::Commands::*` classes.
324
+ Implementing the command has two major tasks: [API design](#api-design) and
325
+ [Implementation](#implementation).
324
326
 
325
- > **Note:** When adding new git command wrappers, **always use the architecture**
326
- > described in "From design to implementation" with `Git::Commands::*` classes and
327
- > the [Arguments DSL](lib/git/commands/arguments.rb).
327
+ ### API design
328
328
 
329
- ### Method placement
329
+ The section focuses on deciding where git command methods belong, how to name them,
330
+ and how to handle parameters and output. These describe the public interface that gem
331
+ users will see.
330
332
 
331
- When implementing a git command, first determine what type of command it is. This
332
- determines where to implement it in the Ruby API:
333
+ #### Method placement
333
334
 
334
- > **Note:** These placement guidelines define the **public API**. Always add public
335
- > methods to the `Git` module or `Git::Repository` (the facade), even though the
336
- > implementation will be in a `Git::Commands::*` class.
335
+ The public API is `Git::Repository` (and the `Git` module). These facade methods must
336
+ be exposed there, even when their implementation lives in private mixin modules or
337
+ `Git::Commands::*` classes.
337
338
 
338
- **Repository factory methods** are implemented on the `Git` module. Use these to
339
- obtain a repository object for subsequent operations:
339
+ **Repository factory commands** are exposed via `Git` as module methods and
340
+ are usually implemented in the `Git::Factories` mixin. These methods return a
341
+ `Git::Repository` object for subsequent operations:
340
342
 
341
343
  ```ruby
342
344
  repo = Git.clone('https://github.com/user/repo.git', 'local_path')
343
- repo = Git.init('new_repo')
345
+ repo = Git.init('new_repo', initial_branch: 'main')
344
346
  repo = Git.open('.')
345
347
  ```
346
348
 
347
- **Repository-scoped commands** operate within a repository context. Implement these
348
- `Git::Repository` instance methods:
349
+ **Repository-scoped commands** require a repository context. These methods are
350
+ exposed via `Git::Repository` instance methods and are usually implemented in a
351
+ `Git::Repository::*` mixin.
349
352
 
350
353
  ```ruby
351
354
  repo.add('file.txt')
@@ -353,23 +356,26 @@ repo.commit('Add file')
353
356
  repo.log
354
357
  ```
355
358
 
356
- **Non-repository commands** do not require a repository context. Implement these as
357
- methods on the `Git` module:
359
+ **Global commands** do not require a repository context. Expose these
360
+ as methods on the `Git` module:
358
361
 
359
362
  ```ruby
360
363
  Git.config_get('user.name', global: true)
361
364
  Git.config_set('user.email', 'user@example.com', global: true)
362
365
  ```
363
366
 
364
- Some commands, like `git config`, can operate in multiple contexts:
367
+ Some commands, like `git config` commands, can be called either in a global or
368
+ repository scope. Here is how that was solved for the config commands:
369
+
370
+ - When called via the `Git` module, a scope parameter such as `global: true`,
371
+ `system: true`, or `file: <filename>` MUST be given. `local` and `worktree`
372
+ scopes are not allowed.
365
373
 
366
- - **On the `Git` module**: A scope parameter (`global: true`, `system: true`) or
367
- `file:` parameter is required. The `local:` and `worktree:` options are not allowed
368
- since they require a repository.
369
- - **On a `Git::Repository` instance**: The command defaults to the repository's local
370
- scope. The `worktree: true` option is also available.
374
+ - When called via a `Git::Repository` instance, `local: true` and `worktree: true`
375
+ scope parameters may be given, with `local` being the default if no scope is given.
376
+ `global`, `system`, and `file` scopes are also allowed.
371
377
 
372
- ### Method naming
378
+ #### Method naming
373
379
 
374
380
  Each method corresponds directly to a `git` command. For example, the `git add`
375
381
  command is implemented as `Git::Repository#add`, and the `git ls-files` command is
@@ -397,12 +403,14 @@ names where appropriate.
397
403
  See also [Output processing](#output-processing) for when different output formats
398
404
  require separate methods.
399
405
 
400
- ### Result class naming
406
+ #### Result class naming
401
407
 
402
- Parsed result objects returned from facade methods follow a reserved suffix convention:
408
+ Parsed result objects returned from facade methods follow a reserved suffix
409
+ convention:
403
410
 
404
411
  - **`*Info`** — a parsed metadata struct returned from a query (e.g., `BranchInfo`,
405
- `TagInfo`, `StashInfo`, `DiffInfo`). Always lives in the top-level `Git::` namespace.
412
+ `TagInfo`, `StashInfo`, `DiffInfo`). Always lives in the top-level `Git::`
413
+ namespace.
406
414
  - **`*Result`** — the outcome of a mutating or destructive operation (e.g.,
407
415
  `BranchDeleteResult`, `TagDeleteResult`). Also lives in `Git::`.
408
416
 
@@ -410,7 +418,7 @@ Do **not** use these suffixes on `Git::Commands::*` command classes — those ar
410
418
  subprocess runners, not data objects. A reader seeing `Commands::Foo::BarInfo`
411
419
  expects a parsed struct, not a class that shells out to git.
412
420
 
413
- ### Parameter naming
421
+ #### Parameter naming
414
422
 
415
423
  Parameters within the `git` gem methods are named after their corresponding long
416
424
  command-line options, ensuring familiarity and ease of use for developers already
@@ -424,18 +432,12 @@ This means git itself will validate option combinations and report errors. This
424
432
  approach is preferred as long as the error messages returned by git are actionable
425
433
  and understandable for users of the gem.
426
434
 
427
- When multiple options are mutually exclusive (like `--global`, `--local`,
428
- `--system`), only one may be specified. Providing more than one will raise an
429
- `ArgumentError`.
430
-
431
- Note that not all Git command options are supported.
432
-
433
- ### Parameter values
435
+ #### Parameter values
434
436
 
435
437
  This section defines how git command-line options and positional arguments map to
436
438
  Ruby method parameters. Contributors must follow these conventions:
437
439
 
438
- #### Options
440
+ ##### Options
439
441
 
440
442
  Git command-line options are passed as keyword arguments in the Ruby API. Methods
441
443
  accept these via an options splat parameter (e.g., `def replace(object, replacement,
@@ -504,7 +506,7 @@ accept these via an options splat parameter (e.g., `def replace(object, replacem
504
506
  all of them raises `ArgumentError`. The DSL enforces this via `requires_one_of`
505
507
  declarations at bind time.
506
508
 
507
- #### Positional arguments
509
+ ##### Positional arguments
508
510
 
509
511
  Arguments that are not options (e.g., file names, branch names) are passed as method
510
512
  arguments, not as keyword arguments.
@@ -551,7 +553,7 @@ arguments, not as keyword arguments.
551
553
  These conventions ensure the API is predictable and closely aligned with the git CLI.
552
554
  If a new option type is encountered, extend this section to document the mapping.
553
555
 
554
- ### Output processing
556
+ #### Output processing
555
557
 
556
558
  The `git` gem translates the output of many Git commands into Ruby objects, making it
557
559
  easier to work with programmatically.
@@ -578,7 +580,7 @@ repo.diff_path_status('HEAD~1', 'HEAD') # File paths and status (git diff --name
578
580
  This approach ensures each method has a clear, predictable return type and allows for
579
581
  targeted parsing logic appropriate to each output format.
580
582
 
581
- ### From design to implementation
583
+ ### Implementation
582
584
 
583
585
  The gem uses the three-layer architecture described in
584
586
  [Layered architecture](#layered-architecture). When wrapping a git command, keep the
@@ -596,6 +598,10 @@ layer responsibilities separate:
596
598
  facade policy, calls the command class, and parses the raw result when returning
597
599
  structured Ruby objects.
598
600
 
601
+ Steps 2 and 3 correspond to the Command and Facade layers, respectively. The
602
+ Execution layer (`Git::ExecutionContext::*`) already exists — a command class only
603
+ consumes it via `@execution_context`; it is not authored per command.
604
+
599
605
  Example structure for `git add`:
600
606
 
601
607
  ```ruby
@@ -614,33 +620,54 @@ module Git
614
620
  operand :pathspec, repeatable: true
615
621
  end
616
622
 
617
- # @!method call(*, **)
623
+ # @overload call(*pathspec, **options)
618
624
  #
619
- # @overload call(*pathspec, **options)
625
+ # Execute the `git add` command
620
626
  #
621
- # Execute the `git add` command
627
+ # @param pathspec [Array<String>] files to be added to the repository
628
+ # (relative to the worktree root)
622
629
  #
623
- # @param pathspec [Array<String>] files to be added to the repository
624
- # (relative to the worktree root)
630
+ # @param options [Hash] command options
625
631
  #
626
- # @param options [Hash] command options
632
+ # @option options [Boolean, nil] :verbose (nil) be verbose
627
633
  #
628
- # @option options [Boolean, nil] :verbose (nil) be verbose
634
+ # Alias: :v
629
635
  #
630
- # Alias: :v
636
+ # @option options [Boolean, nil] :force (nil) allow adding otherwise ignored
637
+ # files
631
638
  #
632
- # @option options [Boolean, nil] :force (nil) allow adding otherwise ignored
633
- # files
639
+ # Alias: :f
634
640
  #
635
- # Alias: :f
641
+ # @return [Git::CommandLine::Result] the result of calling `git add`
636
642
  #
637
- # @return [Git::CommandLine::Result] the result of calling `git add`
643
+ # @raise [ArgumentError] if unsupported options are provided
638
644
  #
639
- # @raise [ArgumentError] if unsupported options are provided
645
+ # @raise [Git::FailedError] if git exits with a non-zero exit status
640
646
  #
641
- # @raise [Git::FailedError] if git exits with a non-zero exit status
647
+ # @api public
642
648
  #
643
- # @api public
649
+ def call(*, **)
650
+ super
651
+ end
652
+ end
653
+ end
654
+ end
655
+ ```
656
+
657
+ Here is the corresponding facade method that calls it:
658
+
659
+ ```ruby
660
+ # lib/git/repository/staging.rb (facade — a topic module included into Git::Repository)
661
+ module Git
662
+ class Repository
663
+ module Staging
664
+ ADD_ALLOWED_OPTS = %i[all force].freeze
665
+ private_constant :ADD_ALLOWED_OPTS
666
+
667
+ def add(paths = '.', **)
668
+ SharedPrivate.assert_valid_opts!(ADD_ALLOWED_OPTS, **)
669
+ Git::Commands::Add.new(@execution_context).call(*Array(paths), **).stdout
670
+ end
644
671
  end
645
672
  end
646
673
  end
@@ -678,7 +705,7 @@ into private helpers to satisfy RuboCop `Metrics` thresholds:
678
705
  def call(*objects, **options)
679
706
  raise ArgumentError, '...' if objects.empty? && !options[:batch_all_objects]
680
707
 
681
- bound = args_definition.bind(**options)
708
+ bound = args_definition.bind(*objects, **options)
682
709
  with_stdin(objects.map { |o| "#{o}\n" }.join) { |reader| run_batch(bound, reader) }
683
710
  end
684
711
 
@@ -711,25 +738,9 @@ also handles translation from single values or arrays to the splat format.
711
738
  > testing each option to ensure clarity and isolation. See
712
739
  > `spec/unit/git/commands/add_spec.rb` for examples of comprehensive argument testing.
713
740
 
714
- ```ruby
715
- # lib/git/repository/staging.rb (facade — a topic module included into Git::Repository)
716
- module Git
717
- class Repository
718
- module Staging
719
- ADD_ALLOWED_OPTS = %i[all force].freeze
720
- private_constant :ADD_ALLOWED_OPTS
721
-
722
- def add(paths = '.', **)
723
- SharedPrivate.assert_valid_opts!(ADD_ALLOWED_OPTS, **)
724
- Git::Commands::Add.new(@execution_context).call(*Array(paths), **).stdout
725
- end
726
- end
727
- end
728
- end
729
- ```
730
-
731
741
  For factory methods and module-level commands, the pattern is the same but
732
- `Git::ExecutionContext::Global` is used instead of the repository's `@execution_context`:
742
+ `Git::ExecutionContext::Global` is used instead of the repository's
743
+ `@execution_context`:
733
744
 
734
745
  ```ruby
735
746
  # Factory method (Git.clone) — creates a global context, runs the command, returns a repository
@@ -743,8 +754,9 @@ end
743
754
  ```
744
755
 
745
756
  > **Note:** `Git::Repository` facade methods pass `@execution_context` (a
746
- > `Git::ExecutionContext::Repository`) to each command class they invoke. Module-level
747
- > methods such as `Git.clone` construct a `Git::ExecutionContext::Global` instead.
757
+ > `Git::ExecutionContext::Repository`) to each command class they invoke.
758
+ > Module-level methods such as `Git.clone` construct a
759
+ > `Git::ExecutionContext::Global` instead.
748
760
 
749
761
  ### Example implementations
750
762
 
@@ -884,27 +896,19 @@ process.stdin.on('end', () =>
884
896
  " | jq
885
897
  ```
886
898
 
887
- ### Unit tests
899
+ ### Testing guidelines
888
900
 
889
- - All changes must be accompanied by new or modified unit tests.
890
- - The entire test suite must pass when `bundle exec rake default` is run from the
891
- project's local working copy.
901
+ - All changes must be accompanied by new or modified unit and integration tests as
902
+ appropriate.
903
+ - The entire test suite must pass when `bundle exec rake` is run from the project's
904
+ local working copy.
905
+ - Test runs are covered by SimpleCov by default. Set `COVERAGE=false` (or `0`/`no`/
906
+ `off`) to skip coverage, e.g. `COVERAGE=false bundle exec rake spec`.
892
907
 
893
- This project uses **RSpec** (`spec/`) as its sole test framework.
894
-
895
- #### RSpec best practices
896
-
897
- - **Public methods**: Use a separate `describe '#method_name'` block for each public
898
- method.
899
- - **Contexts**: Use separate `context` blocks for different scenarios.
900
- - **Options**: For methods accepting options (like commands), use a separate
901
- `context` for each option to ensure isolation and comprehensiveness.
902
- - **One assertion per test**: Each test should verify one specific aspect of
903
- behavior. Exceptions include: (a) testing that an object has expected attributes
904
- after creation (e.g., verifying multiple fields of a returned object), (b)
905
- verifying expected side effects of a single operation (e.g., a method that both
906
- returns a value and modifies state), (c) testing that multiple related
907
- assertions hold for the same setup (e.g., boundary conditions).
908
+ This project uses **RSpec** (`spec/`) as its sole test framework. Structure,
909
+ naming, setup, stubbing, and coverage rules for unit specs are defined in the
910
+ [`rspec-unit-testing-standards`](.github/skills/rspec-unit-testing-standards/SKILL.md)
911
+ skill — follow it when writing or reviewing specs under `spec/unit/`.
908
912
 
909
913
  #### Unit tests vs Integration tests
910
914
 
@@ -959,9 +963,6 @@ $ bundle exec rspec spec/unit/git/commands/add_spec.rb
959
963
  $ GIT_PATH=/Users/james/Downloads/git-2.30.2/bin-wrappers bundle exec rake spec
960
964
  ```
961
965
 
962
- New and updated public-facing features should be documented in the project's
963
- [README.md](README.md).
964
-
965
966
  ## Building a specific version of the Git command-line
966
967
 
967
968
  To test with a specific version of the Git command-line, you may need to build that
@@ -1027,11 +1028,3 @@ GIT_PATH=/Users/james/Downloads/git-2.30.2/bin-wrappers bundle exec rake spec
1027
1028
  ```
1028
1029
 
1029
1030
  Note: `GIT_PATH` refers to the directory containing the `git` executable.
1030
-
1031
- ## Licensing
1032
-
1033
- `ruby-git` uses [the MIT license](https://choosealicense.com/licenses/mit/) as
1034
- declared in the [LICENSE](LICENSE) file.
1035
-
1036
- Licensing is critical to open-source projects as it ensures the software remains
1037
- available under the terms desired by the author.
data/README.md CHANGED
@@ -6,14 +6,19 @@
6
6
  # The Git Gem
7
7
 
8
8
  [![Gem Version](https://badge.fury.io/rb/git.svg)](https://badge.fury.io/rb/git)
9
+ [![Build Status](https://github.com/ruby-git/ruby-git/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/ruby-git/ruby-git/actions/workflows/continuous_integration.yml)
9
10
  [![Documentation](https://img.shields.io/badge/Documentation-Latest-green)](https://rubydoc.info/gems/git/)
10
11
  [![Change
11
12
  Log](https://img.shields.io/badge/CHANGELOG-Latest-green)](https://rubydoc.info/gems/git/file/CHANGELOG.md)
12
- [![Build
13
- Status](https://github.com/ruby-git/ruby-git/workflows/CI/badge.svg?branch=main)](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI)
14
13
  [![Conventional
15
14
  Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
16
- [![AI Policy](https://img.shields.io/badge/AI%20Policy-Required-blue)](AI_POLICY.md)
15
+ [![AI Policy](https://img.shields.io/badge/AI%20Policy-Doc-blue)](AI_POLICY.md)
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
17
+
18
+ > **v5.0.0 is here.** This is a major release with a redesigned internal
19
+ > architecture, but most v4.x code runs unchanged thanks to compatibility
20
+ > shims. See [UPGRADING.md](UPGRADING.md) for the migration guide and
21
+ > [CHANGELOG.md](CHANGELOG.md) for full release notes.
17
22
 
18
23
  - [Summary](#summary)
19
24
  - [Install](#install)