git 4.1.0 → 4.1.1

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: 46a0a933115990124037806bd799be30b6ade9a6e00929062ab87ca8c320539f
4
- data.tar.gz: f91ebc5061789e42d12e9ba5a50c26958b8ffe5f5f9751685c3e28b85551f763
3
+ metadata.gz: 0e74c843d872d01532fd6938f338d16cfa84a25a4c47287347edbea39e580488
4
+ data.tar.gz: d7db0f868a554c60fc39d5716096dbc7967d974afad249b7625266f00cb4c305
5
5
  SHA512:
6
- metadata.gz: 4d83c53f966a90497b698d312b102069d49a39e7f87586b181de0ddc5e45ae4ee833719318674c0d5f6fa5c26780b5c7ec60b95230afa7a4541648db0f7739f5
7
- data.tar.gz: a60047e9d3e22307268b63efb55ee0dcc2e295348438059c7da486ba5050feb9bbbc0300d3bc2fba3c363ede1e5aaa396e1662c8aef1c819d606a0319e4f5fe0
6
+ metadata.gz: 41504a21ea74ab571a0db205b3654a69fd6e6a5af7917e9612c4dab8cbfc321c5babc44bdf62287e890146282fe64343c97fc5af49d0f9520b340db5f4f8f4a6
7
+ data.tar.gz: bccb9b41fd526b5b6c92870e05fcf967d9a235898988efd41aa4f2e3ed7a2e10a4d9e3fda1e8ee7a25d4870cea132d2ae7b50dbb72252e8bb9e292a98ccebf7e
@@ -1,8 +1,17 @@
1
1
  Review our [guidelines for contributing](https://github.com/ruby-git/ruby-git/blob/main/CONTRIBUTING.md) to this repository. A good start is to:
2
2
 
3
- * Write tests for your changes
4
- * Run `rake` before pushing
5
- * Include / update docs in the README.md and in YARD documentation
3
+ - Write tests for your changes
4
+ - Run `rake` before pushing
5
+ - Include / update docs in the README.md and in YARD documentation
6
6
 
7
7
  # Description
8
8
 
9
+ \<your description here\>
10
+
11
+ ## Checklist
12
+
13
+ - [ ] I reviewed and applied the project's [AI Policy](../AI_POLICY.md). I understand
14
+ and verify any AI-assisted changes included in this PR and ensured they meet
15
+ quality, security, and licensing standards.
16
+ - [ ] Tests added/updated as needed and `rake` passes locally.
17
+ - [ ] Documentation updated where applicable (README and/or YARD).
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "4.1.0"
2
+ ".": "4.1.1"
3
3
  }
data/.yardopts CHANGED
@@ -6,5 +6,9 @@
6
6
  -
7
7
  README.md
8
8
  CHANGELOG.md
9
+ CODE_OF_CONDUCT.md
9
10
  CONTRIBUTING.md
11
+ AI_POLICY.md
12
+ GOVERNANCE.md
10
13
  MAINTAINERS.md
14
+ LICENSE
data/AI_POLICY.md ADDED
@@ -0,0 +1,24 @@
1
+ <!--
2
+ # @markup markdown
3
+ # @title AI Policy
4
+ -->
5
+
6
+ # AI Policy
7
+
8
+ AI assisted contributions are welcome in this project.
9
+
10
+ Reviewing and maintaining code requires human insight. While AI tools can be helpful
11
+ assistants, they are no substitute for human judgment and creativity.
12
+
13
+ We value the unique perspectives and critical thinking that our contributors bring.
14
+ If you use AI tools to assist your work:
15
+
16
+ 1. **You are responsible**: You must review and understand every line of code or text
17
+ you submit.
18
+ 2. **Focus on quality**: Ensure that AI-generated content meets our standards for
19
+ correctness, readability, and security, and respects all licensing requirements.
20
+ 3. **Be transparent**: We encourage you to disclose if significant portions of your
21
+ contribution were AI-generated.
22
+
23
+ Ultimately, the quality of this project depends on *your* expertise. Use tools
24
+ wisely, but lead with your own intelligence.
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## [4.1.1](https://github.com/ruby-git/ruby-git/compare/v4.1.0...v4.1.1) (2026-01-09)
9
+
10
+
11
+ ### Other Changes
12
+
13
+ * Add AI Policy and update documentation ([8616cdf](https://github.com/ruby-git/ruby-git/commit/8616cdf7c6cfd1a3f2ccb931f59367b0fdfa36d1))
14
+ * Add code of conduct links ([0769c8e](https://github.com/ruby-git/ruby-git/commit/0769c8ede791a2578291fa301d74144bc7fb2bfb))
15
+ * Add governance policy and update project policies ([8d8263c](https://github.com/ruby-git/ruby-git/commit/8d8263c8395ff4e127b7dc6eb25b0371c272593a))
16
+ * Add Quick Start section and reorganize README for new users ([1811a75](https://github.com/ruby-git/ruby-git/commit/1811a75e4b0b8b8233988d38a411ba585f35c044))
17
+ * Clarify JRuby on Windows support policy ([c37b3d6](https://github.com/ruby-git/ruby-git/commit/c37b3d6c256cdc925578c7ff198f6b351dcb5844))
18
+
8
19
  ## [4.1.0](https://github.com/ruby-git/ruby-git/compare/v4.0.7...v4.1.0) (2026-01-02)
9
20
 
10
21
 
@@ -0,0 +1,25 @@
1
+ <!--
2
+ # @markup markdown
3
+ # @title Code of Conduct
4
+ -->
5
+
6
+ # Code of Conduct
7
+
8
+ ℹ️ We have adopted the [Ruby code of conduct](https://www.ruby-lang.org/en/conduct/).
9
+
10
+ This document provides community guidelines for a safe, respectful, productive, and
11
+ collaborative place for any person who is willing to contribute to the Ruby
12
+ community. It applies to all “collaborative space”, which is defined as community
13
+ communications channels (such as mailing lists, submitted patches, commit comments,
14
+ etc.).
15
+
16
+ - Participants will be tolerant of opposing views.
17
+ - Participants must ensure that their language and actions are free of personal
18
+ attacks and disparaging personal remarks.
19
+ - When interpreting the words and actions of others, participants should always
20
+ assume good intentions.
21
+ - Behavior which can be reasonably considered harassment will not be tolerated.
22
+
23
+ Report violations to the maintainers by [opening an
24
+ issue](https://github.com/ruby-git/ruby-git/issues/new) or contacting a
25
+ [maintainer](MAINTAINERS.md) privately.
data/CONTRIBUTING.md CHANGED
@@ -12,6 +12,7 @@
12
12
  - [Commit your changes to a fork of `ruby-git`](#commit-your-changes-to-a-fork-of-ruby-git)
13
13
  - [Create a pull request](#create-a-pull-request)
14
14
  - [Get your pull request reviewed](#get-your-pull-request-reviewed)
15
+ - [AI-assisted contributions](#ai-assisted-contributions)
15
16
  - [Design philosophy](#design-philosophy)
16
17
  - [Direct mapping to git commands](#direct-mapping-to-git-commands)
17
18
  - [Parameter naming](#parameter-naming)
@@ -41,6 +42,11 @@ judgment when contributing.
41
42
  If you have suggestions for improving these guidelines, please propose changes via a
42
43
  pull request.
43
44
 
45
+ Please also review and adhere to our [Code of Conduct](CODE_OF_CONDUCT.md) when
46
+ participating in the project.
47
+ Governance and maintainer expectations are described in
48
+ [GOVERNANCE.md](GOVERNANCE.md).
49
+
44
50
  ## How to contribute
45
51
 
46
52
  You can contribute in the following ways:
@@ -98,6 +104,13 @@ At least one approval from a project maintainer is required before your pull req
98
104
  can be merged. The maintainer is responsible for ensuring that the pull request meets
99
105
  [the project's coding standards](#coding-standards).
100
106
 
107
+ ## AI-assisted contributions
108
+
109
+ AI-assisted contributions are welcome. Please review and apply our [AI Policy](AI_POLICY.md)
110
+ before submitting changes. You are responsible for understanding and verifying any
111
+ AI-assisted work included in PRs and ensuring it meets our standards for quality,
112
+ security, and licensing.
113
+
101
114
  ## Design philosophy
102
115
 
103
116
  *Note: As of v2.x of the `git` gem, this design philosophy is aspirational. Future
data/GOVERNANCE.md ADDED
@@ -0,0 +1,63 @@
1
+ <!--
2
+ # @markup markdown
3
+ # @title Governance
4
+ -->
5
+
6
+ # Governance
7
+
8
+ This document explains how we steward the project with a light, principles-first
9
+ approach: enable trusted people, minimize dormant access, and keep decisions
10
+ transparent.
11
+
12
+ ## Roles
13
+
14
+ A **Maintainer** is a trusted leader with write access who stewards the project's
15
+ health and direction. Responsibilities center on triage, review, merge, and
16
+ helping the community stay unblocked.
17
+
18
+ A **Project Lead** is a maintainer with additional administrative scope (repo
19
+ Admin, org Owner). They handle settings, secrets, access, and tie-breaks when
20
+ needed.
21
+
22
+ ## Becoming a Maintainer
23
+
24
+ Maintainers invite contributors who consistently ship, review, and model our
25
+ values to become maintainers. Anyone can nominate themselves or others in an
26
+ issue or via a private note. Current maintainers discuss nominations (see
27
+ [Decision Making](#decision-making)) with a focus on contribution quality,
28
+ alignment with project goals, and communication style.
29
+
30
+ ## Access Principles
31
+
32
+ - Stewardship: Maintainer access exists to keep the project healthy and responsive.
33
+ - Least privilege: Elevated access is temporary and kept only while it’s needed.
34
+ - Continuity: Dormant access is paused to protect the project and unblock
35
+ contributors.
36
+ - Respect: Status changes are transparent, reversible, and acknowledge past
37
+ contributions.
38
+
39
+ ## How We Apply Them
40
+
41
+ - Staying active: Maintainers keep elevated access while participating (shipping,
42
+ reviewing, triaging, or governance).
43
+ - When access is paused: If there’s no project activity for about a year, we’ll
44
+ check in. If we don’t hear back after a short window, we move the maintainer to
45
+ Emeritus and pause Owner/Admin/Write/package access (including CODEOWNERS
46
+ entries).
47
+ - Coming back: Emeritus maintainers can be re-added quickly after a brief period of
48
+ renewed participation to refresh context.
49
+ - Recognition: Emeritus maintainers remain listed to honor prior contributions.
50
+
51
+ Access changes are communicated openly (e.g., PRs or issues) and reflected in the
52
+ Maintainers list.
53
+
54
+ ## Decision Making
55
+
56
+ Decisions are usually made by consensus among the active maintainers. If consensus
57
+ cannot be reached, the decision is made by a majority vote. If a vote results in a
58
+ tie, the Project Lead has the final say.
59
+
60
+ ## Code of Conduct
61
+
62
+ All maintainers and contributors must adhere to the project's [Code of
63
+ Conduct](./CODE_OF_CONDUCT.md).
data/MAINTAINERS.md CHANGED
@@ -5,8 +5,20 @@
5
5
 
6
6
  # Maintainers
7
7
 
8
- When making changes in this repository, one of the maintainers below must review and approve your pull request.
8
+ See [GOVERNANCE.md](GOVERNANCE.md) for a definition of the Maintainer role.
9
9
 
10
- * [James Couball](https://github.com/jcouball)
11
- * [Frank Throckmorton](https://github.com/frankthrock)
12
- * [Per Lundberg](https://github.com/perlun)
10
+ ## Active Maintainers
11
+
12
+ - [James Couball](https://github.com/jcouball) (Project Lead)
13
+ - [Frank Throckmorton](https://github.com/frankthrock)
14
+ - [Per Lundberg](https://github.com/perlun)
15
+
16
+ ## Maintainers Emeritus (Alumni)
17
+
18
+ **Maintainers Emeritus** are former maintainers who are no longer active. We honor
19
+ their past contributions.
20
+
21
+ - [Vern Burton](https://github.com/tarcinil)
22
+ - [Daniel Perez](https://github.com/dpmex4527)
23
+ - [Richard Vodden](https://github.com/rvodden)
24
+ - [Scott Chacon](https://github.com/schacon)
data/README.md CHANGED
@@ -7,21 +7,30 @@
7
7
 
8
8
  [![Gem Version](https://badge.fury.io/rb/git.svg)](https://badge.fury.io/rb/git)
9
9
  [![Documentation](https://img.shields.io/badge/Documentation-Latest-green)](https://rubydoc.info/gems/git/)
10
- [![Change Log](https://img.shields.io/badge/CHANGELOG-Latest-green)](https://rubydoc.info/gems/git/file/CHANGELOG.md)
11
- [![Build 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)
12
- [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
10
+ [![Change
11
+ 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
+ [![Conventional
15
+ 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)
13
17
 
14
18
  - [Summary](#summary)
15
19
  - [Install](#install)
16
- - [Major Objects](#major-objects)
20
+ - [Quick Start](#quick-start)
21
+ - [Examples](#examples)
22
+ - [Configuration](#configuration)
23
+ - [Read Operations](#read-operations)
24
+ - [Write Operations](#write-operations)
25
+ - [Index and Tree Operations](#index-and-tree-operations)
17
26
  - [Errors Raised By This Gem](#errors-raised-by-this-gem)
18
27
  - [Specifying And Handling Timeouts](#specifying-and-handling-timeouts)
19
28
  - [Deprecations](#deprecations)
20
- - [Examples](#examples)
21
- - [Ruby version support policy](#ruby-version-support-policy)
22
- - [Git version support policy](#git-version-support-policy)
23
- - [License](#license)
29
+ - [Project Policies](#project-policies)
30
+ - [Ruby Version Support Policy](#ruby-version-support-policy)
31
+ - [Git Version Support Policy](#git-version-support-policy)
24
32
  - [📢 Project Announcements 📢](#-project-announcements-)
33
+ - [2026-01-07: AI Policy Introduced](#2026-01-07-ai-policy-introduced)
25
34
  - [2025-07-09: Architectural Redesign](#2025-07-09-architectural-redesign)
26
35
  - [2025-07-07: We Now Use RuboCop](#2025-07-07-we-now-use-rubocop)
27
36
  - [2025-06-06: Default Branch Rename](#2025-06-06-default-branch-rename)
@@ -34,11 +43,15 @@ command line.
34
43
 
35
44
  Get started by obtaining a repository object by:
36
45
 
37
- - opening an existing working copy with [Git.open](https://rubydoc.info/gems/git/Git#open-class_method)
38
- - initializing a new repository with [Git.init](https://rubydoc.info/gems/git/Git#init-class_method)
39
- - cloning a repository with [Git.clone](https://rubydoc.info/gems/git/Git#clone-class_method)
46
+ - opening an existing working copy with
47
+ [Git.open](https://rubydoc.info/gems/git/Git#open-class_method)
48
+ - initializing a new repository with
49
+ [Git.init](https://rubydoc.info/gems/git/Git#init-class_method)
50
+ - cloning a repository with
51
+ [Git.clone](https://rubydoc.info/gems/git/Git#clone-class_method)
40
52
 
41
- Methods that can be called on a repository object are documented in [Git::Base](https://rubydoc.info/gems/git/Git/Base)
53
+ Methods that can be called on a repository object are documented in
54
+ [Git::Base](https://rubydoc.info/gems/git/Git/Base)
42
55
 
43
56
  ## Install
44
57
 
@@ -66,169 +79,92 @@ to install version 1.x:
66
79
  gem install git --version "~> 1.19"
67
80
  ```
68
81
 
69
- ## Major Objects
70
-
71
- **Git::Base** - The object returned from a `Git.open` or `Git.clone`. Most major actions are called from this object.
72
-
73
- **Git::Object** - The base object for your tree, blob and commit objects, returned from `@git.gtree` or `@git.object` calls. the `Git::AbstractObject` will have most of the calls in common for all those objects.
82
+ ## Quick Start
74
83
 
75
- **Git::Diff** - returns from a `@git.diff` command. It is an Enumerable that returns `Git::Diff:DiffFile` objects from which you can get per file patches and insertion/deletion statistics. You can also get total statistics from the Git::Diff object directly.
84
+ All functionality for this gem starts with the top-level
85
+ [`Git`](https://rubydoc.info/gems/git/Git) module. This module can be used to run
86
+ non-repo scoped `git` commands such as `config`.
76
87
 
77
- **Git::Status** - returns from a `@git.status` command. It is an Enumerable that returns
78
- `Git:Status::StatusFile` objects for each object in git, which includes files in the working
79
- directory, in the index and in the repository. Similar to running 'git status' on the command line to determine untracked and changed files.
88
+ The `Git` module also has factory methods such as `open`, `clone`, and `init` which
89
+ return a [`Git::Base`](https://rubydoc.info/gems/git/Git/Base) object. The
90
+ `Git::Base` object is used to run repo-specific `git` commands such as `add`,
91
+ `commit`, `push`, and `log`.
80
92
 
81
- **Git::Branches** - Enumerable object that holds `Git::Branch objects`. You can call .local or .remote on it to filter to just your local or remote branches.
82
-
83
- **Git::Remote**- A reference to a remote repository that is tracked by this repository.
84
-
85
- **Git::Log** - An Enumerable object that references all the `Git::Object::Commit`
86
- objects that encompass your log query, which can be constructed through methods on
87
- the `Git::Log object`, like:
93
+ Clone, read status, and log:
88
94
 
89
95
  ```ruby
90
- git.log
91
- .max_count(:all)
92
- .object('README.md')
93
- .since('10 years ago')
94
- .between('v1.0.7', 'HEAD')
95
- .map { |commit| commit.sha }
96
- ```
97
-
98
- A maximum of 30 commits are returned if `max_count` is not called. To get all commits
99
- that match the log query, call `max_count(:all)`.
100
-
101
- Note that `git.log.all` adds the `--all` option to the underlying `git log` command.
102
- This asks for the logs of all refs (basically all commits reachable by HEAD,
103
- branches, and tags). This does not control the maximum number of commits returned. To
104
- control how many commits are returned, you should call `max_count`.
105
-
106
- **Git::Worktrees** - Enumerable object that holds `Git::Worktree objects`.
107
-
108
- ## Errors Raised By This Gem
109
-
110
- The git gem will only raise an `ArgumentError` or an error that is a subclass of
111
- `Git::Error`. It does not explicitly raise any other types of errors.
112
-
113
- It is recommended to rescue `Git::Error` to catch any runtime error raised by
114
- this gem unless you need more specific error handling.
96
+ require 'git'
115
97
 
116
- ```ruby
117
- begin
118
- # some git operation
119
- rescue Git::Error => e
120
- puts "An error occurred: #{e.message}"
121
- end
98
+ repo = Git.clone('https://github.com/ruby-git/ruby-git.git', 'ruby-git')
99
+ repo.status.changed.each { |f| puts "changed: #{f.path}" }
100
+ repo.log(5).each { |c| puts c.message }
122
101
  ```
123
102
 
124
- See [`Git::Error`](https://rubydoc.info/gems/git/Git/Error) for more information.
125
-
126
- ## Specifying And Handling Timeouts
127
-
128
- The timeout feature was added in git gem version `2.0.0`.
129
-
130
- A timeout for git command line operations can be set either globally or for specific
131
- method calls that accept a `:timeout` parameter.
132
-
133
- The timeout value must be a real, non-negative `Numeric` value that specifies a
134
- number of seconds a `git` command will be given to complete before being sent a KILL
135
- signal. This library may hang if the `git` command does not terminate after receiving
136
- the KILL signal.
137
-
138
- When a command times out, it is killed by sending it the `SIGKILL` signal and a
139
- `Git::TimeoutError` is raised. This error derives from the `Git::SignaledError` and
140
- `Git::Error`.
141
-
142
- If the timeout value is `0` or `nil`, no timeout will be enforced.
143
-
144
- If a method accepts a `:timeout` parameter and a receives a non-nil value, the value
145
- of this parameter will override the global timeout value. In this context, a value of
146
- `nil` (which is usually the default) will use the global timeout value and a value of
147
- `0` will turn off timeout enforcement for that method call no matter what the global
148
- value is.
149
-
150
- To set a global timeout, use the `Git.config` object:
103
+ Open an existing repo and commit:
151
104
 
152
105
  ```ruby
153
- Git.config.timeout = nil # a value of nil or 0 means no timeout is enforced
154
- Git.config.timeout = 1.5 # can be any real, non-negative Numeric interpreted as number of seconds
155
- ```
156
-
157
- The global timeout can be overridden for a specific method if the method accepts a
158
- `:timeout` parameter:
106
+ require 'git'
159
107
 
160
- ```ruby
161
- repo_url = 'https://github.com/ruby-git/ruby-git.git'
162
- Git.clone(repo_url) # Use the global timeout value
163
- Git.clone(repo_url, timeout: nil) # Also uses the global timeout value
164
- Git.clone(repo_url, timeout: 0) # Do not enforce a timeout
165
- Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::SignaledError
108
+ repo = Git.open('/path/to/repo')
109
+ repo.add(all: true)
110
+ repo.commit('chore: update files')
111
+ repo.push
166
112
  ```
167
113
 
168
- If the command takes too long, a `Git::TimeoutError` will be raised:
114
+ Initialize a new repo and make the first commit:
169
115
 
170
116
  ```ruby
171
- begin
172
- Git.clone(repo_url, timeout: 10)
173
- rescue Git::TimeoutError => e
174
- e.result.tap do |r|
175
- r.class #=> Git::CommandLineResult
176
- r.status #=> #<Process::Status: pid 62173 SIGKILL (signal 9)>
177
- r.status.timeout? #=> true
178
- r.git_cmd # The git command ran as an array of strings
179
- r.stdout # The command's output to stdout until it was terminated
180
- r.stderr # The command's output to stderr until it was terminated
181
- end
182
- end
183
- ```
184
-
185
- ## Deprecations
186
-
187
- This gem uses ActiveSupport's deprecation mechanism to report deprecation warnings.
188
-
189
- You can silence deprecation warnings by adding this line to your source code:
117
+ require 'git'
190
118
 
191
- ```ruby
192
- Git::Deprecation.behavior = :silence
119
+ repo = Git.init('my_project')
120
+ repo.add(all: true)
121
+ repo.commit('initial commit')
193
122
  ```
194
123
 
195
- See [the Active Support Deprecation
196
- documentation](https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html)
197
- for more details.
198
-
199
- If deprecation warnings are silenced, you should reenable them before upgrading the
200
- git gem to the next major version. This will make it easier to identify changes
201
- needed for the upgrade.
202
-
203
124
  ## Examples
204
125
 
205
- Here are a bunch of examples of how to use the Ruby/Git package.
126
+ Beyond the basics covered in Quick Start, these examples show the full range of
127
+ options and variations for each operation.
206
128
 
207
- Require the 'git' gem.
129
+ ### Configuration
130
+
131
+ Configure the `git` command line:
208
132
 
209
133
  ```ruby
210
- require 'git'
134
+ # Global config (in ~/.gitconfig)
135
+ settings = Git.global_config # returns a Hash
136
+ username = Git.global_config('user.email')
137
+ Git.global_config('user.email', 'user@example.com')
138
+
139
+ # Repository config
140
+ repo = Git.open('path/to/repo')
141
+ settings = repo.config # returns a Hash
142
+ username = repo.config('user.email')
143
+ repo.config('user.email', 'anotheruser@example.com')
211
144
  ```
212
145
 
213
- Git env config
146
+ Configure the git gem:
214
147
 
215
148
  ```ruby
216
149
  Git.configure do |config|
217
- # If you want to use a custom git binary
218
- config.binary_path = '/git/bin/path'
219
-
220
- # If you need to use a custom SSH script
221
- config.git_ssh = '/path/to/ssh/script'
150
+ config.binary_path = '/usr/local/bin/git'
151
+ config.git_ssh = 'ssh -i ~/.ssh/id_rsa'
222
152
  end
223
- ```
224
153
 
225
- _NOTE: Another way to specify where is the `git` binary is through the environment variable `GIT_PATH`_
154
+ # or
155
+
156
+ Git.config.binary_path = '/usr/local/bin/git'
157
+ Git.config.git_ssh = 'ssh -i ~/.ssh/id_rsa'
158
+ ```
226
159
 
227
160
  **How SSH configuration is determined:**
228
161
 
229
- - If `git_ssh` is not specified in the API call, the global config (`Git.configure { |c| c.git_ssh = ... }`) is used.
230
- - If `git_ssh: nil` is specified, SSH is disabled for that instance (no SSH key or script will be used).
231
- - If `git_ssh` is a non-empty string, it is used for that instance (overriding the global config).
162
+ - If `git_ssh` is not specified in the API call, the global config (`Git.configure {
163
+ |c| c.git_ssh = ... }`) is used.
164
+ - If `git_ssh: nil` is specified, SSH is disabled for that instance (no SSH key or
165
+ script will be used).
166
+ - If `git_ssh` is a non-empty string, it is used for that instance (overriding the
167
+ global config).
232
168
 
233
169
  You can also specify a custom SSH script on a per-repository basis:
234
170
 
@@ -244,43 +180,46 @@ git = Git.clone('git@github.com:user/repo.git', 'local-dir',
244
180
  git = Git.init('new-repo', git_ssh: 'ssh -i /path/to/private_key')
245
181
  ```
246
182
 
247
- This is especially useful in multi-threaded applications where different repositories require different SSH credentials.
183
+ This is especially useful in multi-threaded applications where different repositories
184
+ require different SSH credentials.
248
185
 
249
- Here are the operations that need read permission only.
186
+ ### Read Operations
187
+
188
+ Here are the operations that need read permission only:
250
189
 
251
190
  ```ruby
252
- g = Git.open(working_dir, :log => Logger.new(STDOUT))
191
+ repo = Git.open(working_dir, :log => Logger.new(STDOUT))
253
192
 
254
- g.index
255
- g.index.readable?
256
- g.index.writable?
257
- g.repo
258
- g.dir
193
+ repo.index
194
+ repo.index.readable?
195
+ repo.index.writable?
196
+ repo.repo
197
+ repo.dir
259
198
 
260
199
  # ls-tree with recursion into subtrees (list files)
261
- g.ls_tree("HEAD", recursive: true)
200
+ repo.ls_tree("HEAD", recursive: true)
262
201
 
263
202
  # log - returns a Git::Log object, which is an Enumerator of Git::Commit objects
264
203
  # default configuration returns a max of 30 commits
265
- g.log
266
- g.log(200) # 200 most recent commits
267
- g.log.since('2 weeks ago') # default count of commits since 2 weeks ago.
268
- g.log(200).since('2 weeks ago') # commits since 2 weeks ago, limited to 200.
269
- g.log.between('v2.5', 'v2.6')
270
- g.log.each {|l| puts l.sha }
271
- g.gblob('v2.5:Makefile').log.since('2 weeks ago')
204
+ repo.log
205
+ repo.log(200) # 200 most recent commits
206
+ repo.log.since('2 weeks ago') # default count of commits since 2 weeks ago.
207
+ repo.log(200).since('2 weeks ago') # commits since 2 weeks ago, limited to 200.
208
+ repo.log.between('v2.5', 'v2.6')
209
+ repo.log.each {|l| puts l.sha }
210
+ repo.gblob('v2.5:Makefile').log.since('2 weeks ago')
272
211
 
273
- g.object('HEAD^').to_s # git show / git rev-parse
274
- g.object('HEAD^').contents
275
- g.object('v2.5:Makefile').size
276
- g.object('v2.5:Makefile').sha
212
+ repo.object('HEAD^').to_s # git show / git rev-parse
213
+ repo.object('HEAD^').contents
214
+ repo.object('v2.5:Makefile').size
215
+ repo.object('v2.5:Makefile').sha
277
216
 
278
- g.gtree(treeish)
279
- g.gblob(treeish)
280
- g.gcommit(treeish)
217
+ repo.gtree(treeish)
218
+ repo.gblob(treeish)
219
+ repo.gcommit(treeish)
281
220
 
282
221
 
283
- commit = g.gcommit('1cc8667014381')
222
+ commit = repo.gcommit('1cc8667014381')
284
223
 
285
224
  commit.gtree
286
225
  commit.parent.sha
@@ -292,60 +231,60 @@ commit.committer.name
292
231
  commit.date.strftime("%m-%d-%y")
293
232
  commit.message
294
233
 
295
- tree = g.gtree("HEAD^{tree}")
234
+ tree = repo.gtree("HEAD^{tree}")
296
235
 
297
236
  tree.blobs
298
237
  tree.subtrees
299
238
  tree.children # blobs and subtrees
300
239
 
301
- g.rev_parse('v2.0.0:README.md')
302
-
303
- g.branches # returns Git::Branch objects
304
- g.branches.local
305
- g.current_branch
306
- g.branches.remote
307
- g.branches[:main].gcommit
308
- g.branches['origin/main'].gcommit
309
-
310
- g.grep('hello') # implies HEAD
311
- g.blob('v2.5:Makefile').grep('hello')
312
- g.tag('v2.5').grep('hello', 'docs/')
313
- g.describe()
314
- g.describe('0djf2aa')
315
- g.describe('HEAD', {:all => true, :tags => true})
316
-
317
- g.diff(commit1, commit2).size
318
- g.diff(commit1, commit2).stats
319
- g.diff(commit1, commit2).name_status
320
- g.gtree('v2.5').diff('v2.6').insertions
321
- g.diff('gitsearch1', 'v2.5').path('lib/')
322
- g.diff('gitsearch1', 'v2.5').path('lib/', 'docs/', 'README.md') # multiple paths
323
- g.diff('gitsearch1', @git.gtree('v2.5'))
324
- g.diff('gitsearch1', 'v2.5').path('docs/').patch
325
- g.gtree('v2.5').diff('v2.6').patch
326
-
327
- g.gtree('v2.5').diff('v2.6').each do |file_diff|
240
+ repo.rev_parse('v2.0.0:README.md')
241
+
242
+ repo.branches # returns Git::Branch objects
243
+ repo.branches.local
244
+ repo.current_branch
245
+ repo.branches.remote
246
+ repo.branches[:main].gcommit
247
+ repo.branches['origin/main'].gcommit
248
+
249
+ repo.grep('hello') # implies HEAD
250
+ repo.blob('v2.5:Makefile').grep('hello')
251
+ repo.tag('v2.5').grep('hello', 'docs/')
252
+ repo.describe()
253
+ repo.describe('0djf2aa')
254
+ repo.describe('HEAD', {:all => true, :tags => true})
255
+
256
+ repo.diff(commit1, commit2).size
257
+ repo.diff(commit1, commit2).stats
258
+ repo.diff(commit1, commit2).name_status
259
+ repo.gtree('v2.5').diff('v2.6').insertions
260
+ repo.diff('gitsearch1', 'v2.5').path('lib/')
261
+ repo.diff('gitsearch1', 'v2.5').path('lib/', 'docs/', 'README.md') # multiple paths
262
+ repo.diff('gitsearch1', repo.gtree('v2.5'))
263
+ repo.diff('gitsearch1', 'v2.5').path('docs/').patch
264
+ repo.gtree('v2.5').diff('v2.6').patch
265
+
266
+ repo.gtree('v2.5').diff('v2.6').each do |file_diff|
328
267
  puts file_diff.path
329
268
  puts file_diff.patch
330
269
  puts file_diff.blob(:src).contents
331
270
  end
332
271
 
333
- g.worktrees # returns Git::Worktree objects
334
- g.worktrees.count
335
- g.worktrees.each do |worktree|
272
+ repo.worktrees # returns Git::Worktree objects
273
+ repo.worktrees.count
274
+ repo.worktrees.each do |worktree|
336
275
  worktree.dir
337
276
  worktree.gcommit
338
277
  worktree.to_s
339
278
  end
340
279
 
341
- g.config('user.name') # returns 'Scott Chacon'
342
- g.config # returns whole config hash
280
+ repo.config('user.name') # returns 'Scott Chacon'
281
+ repo.config # returns whole config hash
343
282
 
344
283
  # Configuration can be set when cloning using the :config option.
345
284
  # This option can be an single configuration String or an Array
346
285
  # if multiple config items need to be set.
347
286
  #
348
- g = Git.clone(
287
+ repo = Git.clone(
349
288
  git_uri, destination_path,
350
289
  :config => [
351
290
  'core.sshCommand=ssh -i /home/user/.ssh/id_rsa',
@@ -353,11 +292,11 @@ g = Git.clone(
353
292
  ]
354
293
  )
355
294
 
356
- g.tags # returns array of Git::Tag objects
295
+ repo.tags # returns array of Git::Tag objects
357
296
 
358
- g.show()
359
- g.show('HEAD')
360
- g.show('v2.8', 'README.md')
297
+ repo.show()
298
+ repo.show('HEAD')
299
+ repo.show('v2.8', 'README.md')
361
300
 
362
301
  Git.ls_remote('https://github.com/ruby-git/ruby-git.git') # returns a hash containing the available references of the repo.
363
302
  Git.ls_remote('/path/to/local/repo')
@@ -366,207 +305,316 @@ Git.ls_remote() # same as Git.ls_remote('.')
366
305
  Git.default_branch('https://github.com/ruby-git/ruby-git') #=> 'main'
367
306
  ```
368
307
 
308
+ ### Write Operations
309
+
369
310
  And here are the operations that will need to write to your git repository.
370
311
 
371
312
  ```ruby
372
- g = Git.init
373
- Git.init('project')
374
- Git.init('/home/schacon/proj',
375
- { :repository => '/opt/git/proj.git',
376
- :index => '/tmp/index'} )
313
+ repo = Git.init # default is the current directory
314
+ repo = Git.init('project')
315
+ repo = Git.init(
316
+ '/home/schacon/proj',
317
+ { :repository => '/opt/git/proj.git', :index => '/tmp/index'}
318
+ )
377
319
 
378
320
  # Clone from a git url
379
321
  git_url = 'https://github.com/ruby-git/ruby-git.git'
380
- # Clone into the ruby-git directory
381
- g = Git.clone(git_url)
322
+ repo = Git.clone(git_url)
382
323
 
383
324
  # Clone into /tmp/clone/ruby-git-clean
384
325
  name = 'ruby-git-clean'
385
326
  path = '/tmp/clone'
386
- g = Git.clone(git_url, name, :path => path)
387
- g.dir #=> /tmp/clone/ruby-git-clean
327
+ repo = Git.clone(git_url, name, :path => path)
328
+ repo.dir #=> /tmp/clone/ruby-git-clean
388
329
 
389
- g.config('user.name', 'Scott Chacon')
390
- g.config('user.email', 'email@email.com')
330
+ repo.config('user.name', 'Scott Chacon')
331
+ repo.config('user.email', 'email@email.com')
391
332
 
392
333
  # Clone can take a filter to tell the serve to send a partial clone
393
- g = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
334
+ repo = Git.clone(git_url, name, :path => path, :filter => 'tree:0')
394
335
 
395
336
  # Clone can control single-branch behavior (nil default keeps current git behavior)
396
- g = Git.clone(git_url, name, :path => path, :depth => 1, :single_branch => false)
337
+ repo = Git.clone(git_url, name, :path => path, :depth => 1, :single_branch => false)
397
338
 
398
339
  # Clone can take an optional logger
399
- logger = Logger.new
400
- g = Git.clone(git_url, NAME, :log => logger)
340
+ logger = Logger.new(STDOUT)
341
+ repo = Git.clone(git_url, 'my-repo', :log => logger)
401
342
 
402
- g.add # git add -- "."
403
- g.add(:all=>true) # git add --all -- "."
404
- g.add('file_path') # git add -- "file_path"
405
- g.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2"
343
+ repo.add # git add -- "."
344
+ repo.add(:all=>true) # git add --all -- "."
345
+ repo.add('file_path') # git add -- "file_path"
346
+ repo.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2"
406
347
 
407
- g.remove() # git rm -f -- "."
408
- g.remove('file.txt') # git rm -f -- "file.txt"
409
- g.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt"
410
- g.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt"
411
- g.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt"
348
+ repo.remove() # git rm -f -- "."
349
+ repo.remove('file.txt') # git rm -f -- "file.txt"
350
+ repo.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt"
351
+ repo.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt"
352
+ repo.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt"
412
353
 
413
- g.commit('message')
414
- g.commit_all('message')
354
+ repo.commit('message')
355
+ repo.commit_all('message')
415
356
 
416
357
  # Sign a commit using the gpg key configured in the user.signingkey config setting
417
- g.config('user.signingkey', '0A46826A')
418
- g.commit('message', gpg_sign: true)
358
+ repo.config('user.signingkey', '0A46826A')
359
+ repo.commit('message', gpg_sign: true)
419
360
 
420
361
  # Sign a commit using a specified gpg key
421
362
  key_id = '0A46826A'
422
- g.commit('message', gpg_sign: key_id)
363
+ repo.commit('message', gpg_sign: key_id)
423
364
 
424
365
  # Skip signing a commit (overriding any global gpgsign setting)
425
- g.commit('message', no_gpg_sign: true)
366
+ repo.commit('message', no_gpg_sign: true)
426
367
 
427
- g = Git.clone(repo, 'myrepo')
428
- g.chdir do
429
- new_file('test-file', 'blahblahblah')
430
- g.status.changed.each do |file|
431
- puts file.blob(:index).contents
432
- end
368
+ repo = Git.clone(git_url, 'myrepo')
369
+ repo.chdir do
370
+ File.write('test-file', 'blahblahblah')
371
+ repo.status.changed.each do |file|
372
+ puts file.blob(:index).contents
373
+ end
433
374
  end
434
375
 
435
- g.reset # defaults to HEAD
436
- g.reset_hard(Git::Commit)
376
+ repo.reset # defaults to HEAD
377
+ repo.reset_hard(Git::Commit)
437
378
 
438
- g.branch('new_branch') # creates new or fetches existing
439
- g.branch('new_branch').checkout
440
- g.branch('new_branch').delete
441
- g.branch('existing_branch').checkout
442
- g.branch('main').contains?('existing_branch')
379
+ repo.branch('new_branch') # creates new or fetches existing
380
+ repo.branch('new_branch').checkout
381
+ repo.branch('new_branch').delete
382
+ repo.branch('existing_branch').checkout
383
+ repo.branch('main').contains?('existing_branch')
443
384
 
444
385
  # delete remote branch
445
- g.push('origin', 'remote_branch_name', force: true, delete: true)
386
+ repo.push('origin', 'remote_branch_name', force: true, delete: true)
446
387
 
447
- g.checkout('new_branch')
448
- g.checkout('new_branch', new_branch: true, start_point: 'main')
449
- g.checkout(g.branch('new_branch'))
388
+ repo.checkout('new_branch')
389
+ repo.checkout('new_branch', new_branch: true, start_point: 'main')
390
+ repo.checkout(repo.branch('new_branch'))
450
391
 
451
- g.branch(name).merge(branch2)
452
- g.branch(branch2).merge # merges HEAD with branch2
392
+ repo.branch(name).merge(branch2)
393
+ repo.branch(branch2).merge # merges HEAD with branch2
453
394
 
454
- g.branch(name).in_branch(message) { # add files } # auto-commits
455
- g.merge('new_branch')
456
- g.merge('new_branch', 'merge commit message', no_ff: true)
457
- g.merge('origin/remote_branch')
458
- g.merge(g.branch('main'))
459
- g.merge([branch1, branch2])
395
+ repo.branch(name).in_branch(message) { # add files } # auto-commits
396
+ repo.merge('new_branch')
397
+ repo.merge('new_branch', 'merge commit message', no_ff: true)
398
+ repo.merge('origin/remote_branch')
399
+ repo.merge(repo.branch('main'))
400
+ repo.merge([branch1, branch2])
460
401
 
461
- g.merge_base('branch1', 'branch2')
402
+ repo.merge_base('branch1', 'branch2')
462
403
 
463
- r = g.add_remote(name, uri) # Git::Remote
464
- r = g.add_remote(name, Git::Base) # Git::Remote
404
+ r = repo.add_remote(name, uri) # Git::Remote
405
+ r = repo.add_remote(name, Git::Base) # Git::Remote
465
406
 
466
- g.remotes # array of Git::Remotes
467
- g.remote(name).fetch
468
- g.remote(name).remove
469
- g.remote(name).merge
470
- g.remote(name).merge(branch)
407
+ repo.remotes # array of Git::Remotes
408
+ repo.remote(name).fetch
409
+ repo.remote(name).remove
410
+ repo.remote(name).merge
411
+ repo.remote(name).merge(branch)
471
412
 
472
- g.remote_set_branches('origin', '*', add: true) # append additional fetch refspecs
473
- g.remote_set_branches('origin', 'feature', 'release/*') # replace fetch refspecs
413
+ repo.remote_set_branches('origin', '*', add: true) # append additional fetch refspecs
414
+ repo.remote_set_branches('origin', 'feature', 'release/*') # replace fetch refspecs
474
415
 
475
- g.fetch
476
- g.fetch(g.remotes.first)
477
- g.fetch('origin', {:ref => 'some/ref/head'} )
478
- g.fetch(all: true, force: true, depth: 2)
479
- g.fetch('origin', {:'update-head-ok' => true})
416
+ repo.fetch
417
+ repo.fetch(repo.remotes.first)
418
+ repo.fetch('origin', {:ref => 'some/ref/head'} )
419
+ repo.fetch(all: true, force: true, depth: 2)
420
+ repo.fetch('origin', {:'update-head-ok' => true})
480
421
 
481
- g.pull
482
- g.pull(Git::Repo, Git::Branch) # fetch and a merge
422
+ repo.pull
423
+ repo.pull(Git::Repo, Git::Branch) # fetch and a merge
483
424
 
484
- g.add_tag('tag_name') # returns Git::Tag
485
- g.add_tag('tag_name', 'object_reference')
486
- g.add_tag('tag_name', 'object_reference', {:options => 'here'})
487
- g.add_tag('tag_name', {:options => 'here'})
425
+ repo.add_tag('tag_name') # returns Git::Tag
426
+ repo.add_tag('tag_name', 'object_reference')
427
+ repo.add_tag('tag_name', 'object_reference', {:options => 'here'})
428
+ repo.add_tag('tag_name', {:options => 'here'})
488
429
 
489
- Options:
490
- :a | :annotate
491
- :d
492
- :f
493
- :m | :message
494
- :s
430
+ repo.delete_tag('tag_name')
495
431
 
496
- g.delete_tag('tag_name')
432
+ repo.repack
497
433
 
498
- g.repack
499
-
500
- g.push
501
- g.push(g.remote('name'))
434
+ repo.push
435
+ repo.push(repo.remote('name'))
502
436
 
503
437
  # delete remote branch
504
- g.push('origin', 'remote_branch_name', force: true, delete: true)
438
+ repo.push('origin', 'remote_branch_name', force: true, delete: true)
505
439
 
506
440
  # push all branches to remote at one time
507
- g.push('origin', all: true)
441
+ repo.push('origin', all: true)
508
442
 
509
- g.worktree('/tmp/new_worktree').add
510
- g.worktree('/tmp/new_worktree', 'branch1').add
511
- g.worktree('/tmp/new_worktree').remove
512
- g.worktrees.prune
443
+ repo.worktree('/tmp/new_worktree').add
444
+ repo.worktree('/tmp/new_worktree', 'branch1').add
445
+ repo.worktree('/tmp/new_worktree').remove
446
+ repo.worktrees.prune
513
447
  ```
514
448
 
449
+ ### Index and Tree Operations
450
+
515
451
  Some examples of more low-level index and tree operations
516
452
 
517
453
  ```ruby
518
- g.with_temp_index do
454
+ repo.with_temp_index do
519
455
 
520
- g.read_tree(tree3) # calls self.index.read_tree
521
- g.read_tree(tree1, :prefix => 'hi/')
456
+ repo.read_tree(tree3) # calls self.index.read_tree
457
+ repo.read_tree(tree1, :prefix => 'hi/')
522
458
 
523
- c = g.commit_tree('message')
459
+ c = repo.commit_tree('message')
524
460
  # or #
525
- t = g.write_tree
526
- c = g.commit_tree(t, :message => 'message', :parents => [sha1, sha2])
461
+ t = repo.write_tree
462
+ c = repo.commit_tree(t, :message => 'message', :parents => [sha1, sha2])
527
463
 
528
- g.branch('branch_name').update_ref(c)
529
- g.update_ref(branch, c)
464
+ repo.branch('branch_name').update_ref(c)
465
+ repo.update_ref(branch, c)
530
466
 
531
- g.with_temp_working do # new blank working directory
532
- g.checkout
533
- g.checkout(another_index)
534
- g.commit # commits to temp_index
467
+ repo.with_temp_working do # new blank working directory
468
+ repo.checkout
469
+ repo.checkout(another_index)
470
+ repo.commit # commits to temp_index
535
471
  end
536
472
  end
537
473
 
538
- g.set_index('/path/to/index')
474
+ repo.set_index('/path/to/index')
539
475
 
540
-
541
- g.with_index(path) do
476
+ repo.with_index(path) do
542
477
  # calls set_index, then switches back after
543
478
  end
544
479
 
545
- g.with_working(dir) do
480
+ repo.with_working(dir) do
546
481
  # calls set_working, then switches back after
547
482
  end
548
483
 
549
- g.with_temp_working(dir) do
550
- g.checkout_index(:prefix => dir, :path_limiter => path)
484
+ repo.with_temp_working(dir) do
485
+ repo.checkout_index(:prefix => dir, :path_limiter => path)
551
486
  # do file work
552
- g.commit # commits to index
487
+ repo.commit # commits to index
488
+ end
489
+ ```
490
+
491
+ ## Errors Raised By This Gem
492
+
493
+ The git gem will only raise an `ArgumentError` or an error that is a subclass of
494
+ `Git::Error`. It does not explicitly raise any other types of errors.
495
+
496
+ It is recommended to rescue `Git::Error` to catch any runtime error raised by this
497
+ gem unless you need more specific error handling.
498
+
499
+ ```ruby
500
+ begin
501
+ # some git operation
502
+ rescue Git::Error => e
503
+ puts "An error occurred: #{e.message}"
553
504
  end
554
505
  ```
555
506
 
556
- ## Ruby version support policy
507
+ See [`Git::Error`](https://rubydoc.info/gems/git/Git/Error) for more information.
508
+
509
+ ## Specifying And Handling Timeouts
510
+
511
+ The timeout feature was added in git gem version `2.0.0`.
512
+
513
+ A timeout for git command line operations can be set either globally or for specific
514
+ method calls that accept a `:timeout` parameter.
515
+
516
+ The timeout value must be a real, non-negative `Numeric` value that specifies a
517
+ number of seconds a `git` command will be given to complete before being sent a KILL
518
+ signal. This library may hang if the `git` command does not terminate after receiving
519
+ the KILL signal.
557
520
 
558
- This gem will be expected to function correctly on:
521
+ When a command times out, it is killed by sending it the `SIGKILL` signal and a
522
+ `Git::TimeoutError` is raised. This error derives from the `Git::SignaledError` and
523
+ `Git::Error`.
524
+
525
+ If the timeout value is `0` or `nil`, no timeout will be enforced.
559
526
 
560
- - All non-EOL versions of the MRI Ruby on Mac, Linux, and Windows
561
- - The latest version of JRuby on Linux
562
- - The latest version of Truffle Ruby on Linus
527
+ If a method accepts a `:timeout` parameter and a receives a non-nil value, the value
528
+ of this parameter will override the global timeout value. In this context, a value of
529
+ `nil` (which is usually the default) will use the global timeout value and a value of
530
+ `0` will turn off timeout enforcement for that method call no matter what the global
531
+ value is.
563
532
 
564
- It is this project's intent to support the latest version of JRuby on Windows
565
- once the following JRuby bug is fixed:
533
+ To set a global timeout, use the `Git.config` object:
566
534
 
567
- jruby/jruby#7515
535
+ ```ruby
536
+ Git.config.timeout = nil # a value of nil or 0 means no timeout is enforced
537
+ Git.config.timeout = 1.5 # can be any real, non-negative Numeric interpreted as number of seconds
538
+ ```
568
539
 
569
- ## Git version support policy
540
+ The global timeout can be overridden for a specific method if the method accepts a
541
+ `:timeout` parameter:
542
+
543
+ ```ruby
544
+ repo_url = 'https://github.com/ruby-git/ruby-git.git'
545
+ Git.clone(repo_url) # Use the global timeout value
546
+ Git.clone(repo_url, timeout: nil) # Also uses the global timeout value
547
+ Git.clone(repo_url, timeout: 0) # Do not enforce a timeout
548
+ Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::SignaledError
549
+ ```
550
+
551
+ If the command takes too long, a `Git::TimeoutError` will be raised:
552
+
553
+ ```ruby
554
+ begin
555
+ Git.clone(repo_url, timeout: 10)
556
+ rescue Git::TimeoutError => e
557
+ e.result.tap do |r|
558
+ r.class #=> Git::CommandLineResult
559
+ r.status #=> #<Process::Status: pid 62173 SIGKILL (signal 9)>
560
+ r.status.timeout? #=> true
561
+ r.git_cmd # The git command ran as an array of strings
562
+ r.stdout # The command's output to stdout until it was terminated
563
+ r.stderr # The command's output to stderr until it was terminated
564
+ end
565
+ end
566
+ ```
567
+
568
+ ## Deprecations
569
+
570
+ This gem uses ActiveSupport's deprecation mechanism to report deprecation warnings.
571
+
572
+ You can silence deprecation warnings by adding this line to your source code:
573
+
574
+ ```ruby
575
+ Git::Deprecation.behavior = :silence
576
+ ```
577
+
578
+ See [the Active Support Deprecation
579
+ documentation](https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html)
580
+ for more details.
581
+
582
+ If deprecation warnings are silenced, you should reenable them before upgrading the
583
+ git gem to the next major version. This will make it easier to identify changes
584
+ needed for the upgrade.
585
+
586
+ ## Project Policies
587
+
588
+ These documents set expectations for behavior, contribution workflows, AI-assisted
589
+ changes, decision making, maintainer roles, and licensing. Please review them before
590
+ opening issues or pull requests.
591
+
592
+ | Document | Description |
593
+ | -------- | ----------- |
594
+ | [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) | We follow the Ruby community Code of Conduct; expect respectful, harassment-free participation and report concerns to maintainers. |
595
+ | [CONTRIBUTING](CONTRIBUTING.md) | How to report issues, submit PRs with Conventional Commits, meet coding/testing standards, and follow the Code of Conduct. |
596
+ | [AI_POLICY](AI_POLICY.md) | AI-assisted contributions are welcome. Contributors are expected to read and apply the AI Policy, and ensure any AI-assisted work meets our quality, security, and licensing standards. |
597
+ | [Ruby version support policy](#ruby-version-support-policy) | Supported Ruby runtimes and platforms; bump decisions and CI coverage expectations. |
598
+ | [Git version support policy](#git-version-support-policy) | Minimum supported git version and how version bumps are communicated and enforced. |
599
+ | [GOVERNANCE](GOVERNANCE.md) | Principles-first governance defining maintainer/project lead roles, least-privilege access, consensus/majority decisions, and nomination/emeritus steps. |
600
+ | [MAINTAINERS](MAINTAINERS.md) | Lists active maintainers (Project Lead noted) and emeritus alumni with links; see governance for role scope. |
601
+ | [LICENSE](LICENSE) | MIT License terms for using, modifying, and redistributing this project. |
602
+
603
+ ### Ruby Version Support Policy
604
+
605
+ This gem is expected to function correctly on:
606
+
607
+ - All [non-EOL versions](https://www.ruby-lang.org/en/downloads/branches/) of the MRI
608
+ Ruby on Mac, Linux, and Windows
609
+ - The latest version of JRuby 9.4+ on Linux
610
+ - The latest version of TruffleRuby 24+ on Linux
611
+
612
+ It is this project's intent to support the latest version of JRuby on Windows once
613
+ the [process_executer](https://github.com/main-branch/process_executer) gem properly
614
+ supports subprocess status reporting on JRuby for Windows (see
615
+ [main-branch/process_executer#156](https://github.com/main-branch/process_executer/issues/156)).
616
+
617
+ ### Git Version Support Policy
570
618
 
571
619
  This gem requires git version 2.28.0 or greater as specified in the gemspec. This
572
620
  requirement reflects:
@@ -585,12 +633,18 @@ gem as new git features are adopted or as maintaining backward compatibility bec
585
633
  impractical. Such changes will be clearly documented in the CHANGELOG and release
586
634
  notes.
587
635
 
588
- ## License
636
+ ## 📢 Project Announcements 📢
589
637
 
590
- Licensed under MIT License Copyright (c) 2008 Scott Chacon. See LICENSE for further
591
- details.
638
+ ### 2026-01-07: AI Policy Introduced
592
639
 
593
- ## 📢 Project Announcements 📢
640
+ We have adopted a formal [AI Policy](AI_POLICY.md) to clarify expectations for
641
+ AI-assisted contributions. Please review it before opening a PR to ensure your
642
+ changes are fully understood, meet our quality bar, and respect licensing
643
+ requirements.
644
+
645
+ We chose a principles-based policy to respect contributors’ time and expertise. It’s
646
+ quick to read, easy to remember, and avoids unnecessary policy overhead while still
647
+ setting clear expectations.
594
648
 
595
649
  ### 2025-07-09: Architectural Redesign
596
650
 
@@ -643,11 +697,12 @@ rake rubocop
643
697
  RuboCop is also run as part of the default rake task (by running `rake`) that is run
644
698
  in our Continuous Integration workflow.
645
699
 
646
- Going forward, any PRs that have any Robocop offenses will not be merged. In
647
- certain rare cases, it might be acceptable to disable a RuboCop check for the most
648
- limited scope possible.
700
+ Going forward, any PRs that have any Robocop offenses will not be merged. In certain
701
+ rare cases, it might be acceptable to disable a RuboCop check for the most limited
702
+ scope possible.
649
703
 
650
- If you have a problem fixing a RuboCop offense, don't be afraid to ask a contributor.
704
+ If you have a problem fixing a RuboCop offense, don't be afraid to ask a
705
+ contributor.
651
706
 
652
707
  ### 2025-06-06: Default Branch Rename
653
708
 
data/lib/git/log.rb CHANGED
@@ -1,9 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Git
4
- # Builds and executes a `git log` query.
4
+ # Builds and executes a `git log` query
5
5
  #
6
6
  # This class provides a fluent interface for building complex `git log` queries.
7
+ #
8
+ # Queries default to returning 30 commits; call {#max_count} with `:all` to
9
+ # return every matching commit. Calling {#all} adds the `--all` flag to include
10
+ # all refs in the search but does not change the number of commits returned.
11
+ #
7
12
  # The query is lazily executed when results are requested either via the modern
8
13
  # `#execute` method or the deprecated Enumerable methods.
9
14
  #
data/lib/git/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  module Git
4
4
  # The current gem version
5
5
  # @return [String] the current gem version.
6
- VERSION = '4.1.0'
6
+ VERSION = '4.1.1'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon and others
@@ -250,8 +250,11 @@ files:
250
250
  - ".rubocop.yml"
251
251
  - ".rubocop_todo.yml"
252
252
  - ".yardopts"
253
+ - AI_POLICY.md
253
254
  - CHANGELOG.md
255
+ - CODE_OF_CONDUCT.md
254
256
  - CONTRIBUTING.md
257
+ - GOVERNANCE.md
255
258
  - Gemfile
256
259
  - LICENSE
257
260
  - MAINTAINERS.md
@@ -305,8 +308,8 @@ licenses:
305
308
  metadata:
306
309
  homepage_uri: http://github.com/ruby-git/ruby-git
307
310
  source_code_uri: http://github.com/ruby-git/ruby-git
308
- changelog_uri: https://rubydoc.info/gems/git/4.1.0/file/CHANGELOG.md
309
- documentation_uri: https://rubydoc.info/gems/git/4.1.0
311
+ changelog_uri: https://rubydoc.info/gems/git/4.1.1/file/CHANGELOG.md
312
+ documentation_uri: https://rubydoc.info/gems/git/4.1.1
310
313
  rubygems_mfa_required: 'true'
311
314
  rdoc_options: []
312
315
  require_paths: