git 5.6.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -16
- data/CONTRIBUTING.md +44 -31
- data/README.md +135 -67
- data/UPGRADING.md +915 -268
- data/git.gemspec +6 -8
- data/lib/git/author_info.rb +1 -2
- data/lib/git/commands/base.rb +22 -2
- data/lib/git/commands/cat_file/raw.rb +0 -68
- data/lib/git/commands/maintenance/register.rb +0 -4
- data/lib/git/commands/maintenance/run.rb +0 -4
- data/lib/git/commands/maintenance/start.rb +0 -4
- data/lib/git/commands/maintenance/stop.rb +0 -4
- data/lib/git/commands/maintenance/unregister.rb +0 -4
- data/lib/git/commands/maintenance.rb +0 -2
- data/lib/git/commands/show_ref/exclude_existing.rb +1 -1
- data/lib/git/commands/show_ref/exists.rb +0 -5
- data/lib/git/commands/show_ref/list.rb +1 -1
- data/lib/git/commands/show_ref/verify.rb +1 -1
- data/lib/git/commands/show_ref.rb +1 -1
- data/lib/git/commands/worktree/repair.rb +0 -5
- data/lib/git/diff_path_status.rb +2 -2
- data/lib/git/encoding_utils.rb +25 -0
- data/lib/git/errors.rb +23 -5
- data/lib/git/factories.rb +361 -125
- data/lib/git/log.rb +3 -75
- data/lib/git/object.rb +4 -185
- data/lib/git/path_resolver.rb +104 -36
- data/lib/git/repository/branching.rb +21 -189
- data/lib/git/repository/committing.rb +0 -25
- data/lib/git/repository/context_helpers.rb +249 -155
- data/lib/git/repository/diffing.rb +2 -44
- data/lib/git/repository/merging.rb +32 -54
- data/lib/git/repository/object_operations.rb +121 -338
- data/lib/git/repository/remote_operations.rb +7 -219
- data/lib/git/repository/staging.rb +6 -184
- data/lib/git/repository/stashing.rb +126 -130
- data/lib/git/repository/status_operations.rb +1 -54
- data/lib/git/repository/worktree_operations.rb +31 -118
- data/lib/git/repository.rb +20 -299
- data/lib/git/system_call_guard.rb +95 -0
- data/lib/git/version.rb +1 -1
- data/lib/git.rb +47 -364
- metadata +25 -19
- data/lib/git/author.rb +0 -46
- data/lib/git/branch.rb +0 -693
- data/lib/git/branches.rb +0 -194
- data/lib/git/remote.rb +0 -191
- data/lib/git/stash.rb +0 -124
- data/lib/git/stashes.rb +0 -198
- data/lib/git/status.rb +0 -384
- data/lib/git/worktree.rb +0 -180
- data/lib/git/worktrees.rb +0 -152
data/UPGRADING.md
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
# Upgrading the `git`
|
|
1
|
+
# Upgrading the `git` gem
|
|
2
2
|
|
|
3
3
|
This document covers breaking changes and migration steps when upgrading the
|
|
4
4
|
`git` gem to a new major version. Each section describes what changed and how
|
|
5
5
|
to update your code when upgrading from the preceding major version.
|
|
6
6
|
|
|
7
|
-
- [Upgrading to v6.
|
|
7
|
+
- [Upgrading to v6.x](#upgrading-to-v6x)
|
|
8
|
+
- [Before you upgrade](#before-you-upgrade)
|
|
9
|
+
- [Minimum Ruby version](#minimum-ruby-version)
|
|
10
|
+
- [Minimum git version](#minimum-git-version)
|
|
11
|
+
- [Minimum addressable version](#minimum-addressable-version)
|
|
12
|
+
- [Minimum activesupport version](#minimum-activesupport-version)
|
|
13
|
+
- [Changes the deprecation run does not catch or does not explain](#changes-the-deprecation-run-does-not-catch-or-does-not-explain)
|
|
14
|
+
- [Filesystem errors raised as `Git::Error`](#filesystem-errors-raised-as-giterror)
|
|
15
|
+
- [Gzip failures in `archive` raised as `Git::Error`](#gzip-failures-in-archive-raised-as-giterror)
|
|
16
|
+
- [Relative `:repository` and `:index` paths](#relative-repository-and-index-paths)
|
|
17
|
+
- [Tilde expansion in `Git.init` and `Git.clone` paths](#tilde-expansion-in-gitinit-and-gitclone-paths)
|
|
18
|
+
- [Context helpers yield a separate repository](#context-helpers-yield-a-separate-repository)
|
|
19
|
+
- [`Git.init`, `Git.open`, and `Git.bare` reject unknown options](#gitinit-gitopen-and-gitbare-reject-unknown-options)
|
|
20
|
+
- [`tag_create` raises when the created tag is missing](#tag_create-raises-when-the-created-tag-is-missing)
|
|
21
|
+
- [`stash_list` returns an Array of `Git::StashInfo`](#stash_list-returns-an-array-of-gitstashinfo)
|
|
22
|
+
- [`stash_store` raises when the stored entry is missing](#stash_store-raises-when-the-stored-entry-is-missing)
|
|
23
|
+
- [`worktree_add` returns `Git::WorktreeInfo` and raises when the worktree is missing](#worktree_add-returns-gitworktreeinfo-and-raises-when-the-worktree-is-missing)
|
|
24
|
+
- [`Git::Deprecation` horizon is prose](#gitdeprecation-horizon-is-prose)
|
|
25
|
+
- [Removed APIs](#removed-apis)
|
|
26
|
+
- [Deprecated in v6.0.0](#deprecated-in-v600)
|
|
27
|
+
- [`set_index` and `set_working` deprecated](#set_index-and-set_working-deprecated)
|
|
28
|
+
- [`Git::GitExecuteError` deprecated](#gitgitexecuteerror-deprecated)
|
|
8
29
|
- [Upgrading to v5.x](#upgrading-to-v5x)
|
|
9
30
|
- [Overview](#overview)
|
|
10
31
|
- [Breaking changes](#breaking-changes)
|
|
@@ -17,6 +38,7 @@ to update your code when upgrading from the preceding major version.
|
|
|
17
38
|
- [Deprecated methods](#deprecated-methods)
|
|
18
39
|
- [Facade method renames](#facade-method-renames)
|
|
19
40
|
- [`Git::Repository` method renames](#gitrepository-method-renames)
|
|
41
|
+
- [`Git::Repository` alias renames](#gitrepository-alias-renames)
|
|
20
42
|
- [`Git::Repository` option renames](#gitrepository-option-renames)
|
|
21
43
|
- [v4.x-style configuration methods](#v4x-style-configuration-methods)
|
|
22
44
|
- [`Git` module mixin deprecations](#git-module-mixin-deprecations)
|
|
@@ -35,24 +57,628 @@ to update your code when upgrading from the preceding major version.
|
|
|
35
57
|
- [`Git::Log` Enumerable interface deprecated](#gitlog-enumerable-interface-deprecated)
|
|
36
58
|
- [`Git::Object::Commit#set_commit` deprecated](#gitobjectcommitset_commit-deprecated)
|
|
37
59
|
- [`Git.export` `:remote` option deprecated](#gitexport-remote-option-deprecated)
|
|
38
|
-
- [Context helper blocks that declare no parameter deprecated](#context-helper-blocks-that-declare-no-parameter-deprecated)
|
|
39
60
|
|
|
40
|
-
## Upgrading to v6.
|
|
41
|
-
|
|
42
|
-
v6.0.0 is not yet released. This section will be completed when it ships.
|
|
61
|
+
## Upgrading to v6.x
|
|
43
62
|
|
|
44
63
|
v6.0.0 removes the APIs deprecated during v5.x under the project's
|
|
45
|
-
[deprecation policy](README.md#deprecation-policy)
|
|
46
|
-
|
|
64
|
+
[deprecation policy](README.md#deprecation-policy), raises the Ruby, git, and
|
|
65
|
+
dependency floors, and changes a small number of behaviors that had no deprecation
|
|
66
|
+
path. [Issue 1717](https://github.com/ruby-git/ruby-git/issues/1717) tracks its scope.
|
|
67
|
+
|
|
68
|
+
This section is organized by what you have to do rather than by what changed:
|
|
69
|
+
|
|
70
|
+
- [Before you upgrade](#before-you-upgrade) gives the version floors and the upgrade
|
|
71
|
+
procedure. Read it first.
|
|
72
|
+
- [Changes the deprecation run does not catch or does not
|
|
73
|
+
explain](#changes-the-deprecation-run-does-not-catch-or-does-not-explain) covers
|
|
74
|
+
every change that a clean run under `GIT_DEPRECATION_BEHAVIOR=raise` does not find,
|
|
75
|
+
and the two warnings whose fix is not a removed API's replacement. Read each entry.
|
|
76
|
+
- [Removed APIs](#removed-apis) is one table of every API removed in v6.0.0 and its
|
|
77
|
+
replacement. Every one of them warned in v5.x when called, constructed, or used, so
|
|
78
|
+
the raise behavior finds each call, and the table links to the entry under
|
|
79
|
+
"Upgrading to v5.x" that maps each call shape to its replacement. A bare reference
|
|
80
|
+
to a removed constant did not warn, so step 8 has you search for those.
|
|
81
|
+
- [Deprecated in v6.0.0](#deprecated-in-v600) covers the APIs that warn in v6.0.0 and
|
|
82
|
+
are removed in a later major release.
|
|
83
|
+
|
|
84
|
+
If you are upgrading from v4.x directly, the v5.x warnings never ran against your
|
|
85
|
+
code, so also read [Upgrading to v5.x](#upgrading-to-v5x). Its entries map each v4.x
|
|
86
|
+
call to its replacement, and the [Removed APIs](#removed-apis) table tells you which of
|
|
87
|
+
those replacements are now the only option.
|
|
88
|
+
|
|
89
|
+
### Before you upgrade
|
|
90
|
+
|
|
91
|
+
1. Upgrade to Ruby 3.3 or later if you are still on Ruby 3.2 (see
|
|
92
|
+
[Minimum Ruby version](#minimum-ruby-version)).
|
|
93
|
+
2. Check that `git --version` reports 2.43.0 or later everywhere the gem runs (see
|
|
94
|
+
[Minimum git version](#minimum-git-version)).
|
|
95
|
+
3. Run `bundle update addressable` and confirm the lockfile resolves addressable
|
|
96
|
+
2.9.0 or later (see [Minimum addressable version](#minimum-addressable-version)).
|
|
97
|
+
4. Run `bundle update activesupport` and confirm the lockfile resolves activesupport
|
|
98
|
+
7.0.9 or later (see [Minimum activesupport version](#minimum-activesupport-version)).
|
|
99
|
+
5. Upgrade to the latest v5.x release.
|
|
100
|
+
6. Set `GIT_DEPRECATION_BEHAVIOR=raise` (or `Git::Deprecation.behavior = :raise`) in
|
|
101
|
+
your test suite and, if possible, staging.
|
|
102
|
+
7. Fix each deprecation until the suite is clean. The [Removed APIs](#removed-apis)
|
|
103
|
+
table links each removed API's replacement. Three warnings are not removals:
|
|
104
|
+
- `stash_list` keeps its name and changes its return type (see [`stash_list`
|
|
105
|
+
returns an Array of `Git::StashInfo`](#stash_list-returns-an-array-of-gitstashinfo)).
|
|
106
|
+
- A context-helper block with no positional parameter, which v5.6.0 and later
|
|
107
|
+
warn about (see [Context helpers yield a separate
|
|
108
|
+
repository](#context-helpers-yield-a-separate-repository)).
|
|
109
|
+
- `Git::GitExecuteError`, which still warns in v6.0.0 (see
|
|
110
|
+
[`Git::GitExecuteError` deprecated](#gitgitexecuteerror-deprecated)).
|
|
111
|
+
8. Search your code for each constant in the [Removed APIs](#removed-apis) table. A
|
|
112
|
+
bare reference such as `is_a?(Git::Base)`, `rescue Git::Status`, or
|
|
113
|
+
`case ... when Git::Author` never warned in v5.x, so the raise behavior does not
|
|
114
|
+
find it, and it raises `NameError` in v6.0.0.
|
|
115
|
+
9. Work through each entry under [Changes the deprecation run does not catch or does
|
|
116
|
+
not explain](#changes-the-deprecation-run-does-not-catch-or-does-not-explain). The two
|
|
117
|
+
that affect the most code:
|
|
118
|
+
- Replace any `rescue Errno::*` around gem calls with `rescue Git::Error` (see
|
|
119
|
+
[Filesystem errors raised as `Git::Error`](#filesystem-errors-raised-as-giterror)).
|
|
120
|
+
- Give every `with_index`, `with_temp_index`, `with_working`, and
|
|
121
|
+
`with_temp_working` block a parameter and call methods on it rather than on the
|
|
122
|
+
outer repository; v5.6.0 and later warn for a block with no positional parameter
|
|
123
|
+
(see [Context helpers yield a separate
|
|
124
|
+
repository](#context-helpers-yield-a-separate-repository)).
|
|
125
|
+
10. Upgrade to v6.0.0.
|
|
126
|
+
|
|
127
|
+
#### Minimum Ruby version
|
|
128
|
+
|
|
129
|
+
v6.0.0 requires Ruby 3.3.0 or later. v5.x supports Ruby 3.2, which reached end of
|
|
130
|
+
life on 2026-03-31. The
|
|
131
|
+
[Ruby version support policy](README.md#ruby-version-support-policy) commits the
|
|
132
|
+
gem to the MRI versions that are still maintained, so the floor moves when a Ruby
|
|
133
|
+
version leaves maintenance rather than with the gem's major version. Ruby 3.3 is
|
|
134
|
+
in security maintenance until about 2027-03-31, so it stays supported in v6.0.0.
|
|
135
|
+
A 3.4 floor can land in a later v6.x release once 3.3 reaches end of life.
|
|
136
|
+
|
|
137
|
+
JRuby and TruffleRuby support is unchanged.
|
|
138
|
+
|
|
139
|
+
If your application still runs on Ruby 3.2, upgrade Ruby before upgrading the gem,
|
|
140
|
+
or stay on the latest v5.x release.
|
|
141
|
+
|
|
142
|
+
#### Minimum git version
|
|
143
|
+
|
|
144
|
+
v6.0.0 requires git 2.43.0 or later. v5.x required 2.28.0.
|
|
145
|
+
|
|
146
|
+
Git 2.43.0 was released on November 20, 2023, and is the version shipped by
|
|
147
|
+
Ubuntu 24.04, RHEL 8.10 and 9.4, SLES 15 SP6, openSUSE Leap 15.6, and Alpine 3.19.
|
|
148
|
+
Ubuntu 22.04 (git 2.34) and Debian 12 (git 2.39) are the supported platforms whose
|
|
149
|
+
stock git falls below the new floor. On Ubuntu 22.04, install a newer git (for
|
|
150
|
+
example from the [git-core PPA](https://launchpad.net/~git-core/+archive/ubuntu/ppa));
|
|
151
|
+
on Debian 12, install it from
|
|
152
|
+
[bookworm-backports](https://backports.debian.org/Instructions/); or stay on v5.x.
|
|
153
|
+
Apple's git 2.39 from Xcode 16 also falls below the floor; Xcode 26 ships git 2.50.
|
|
154
|
+
|
|
155
|
+
Features that need a git newer than 2.43.0 stay gated per command and raise
|
|
156
|
+
`Git::VersionError` on older installations, as `git am --retry` (2.46.0) does today.
|
|
157
|
+
|
|
158
|
+
#### Minimum addressable version
|
|
159
|
+
|
|
160
|
+
v6.0.0 depends on `addressable ~> 2.9`. v5.x accepts `~> 2.8`.
|
|
161
|
+
|
|
162
|
+
Addressable 2.9.0 (released in April 2026) fixes the ReDoS vulnerability in
|
|
163
|
+
`Addressable::Template#match`
|
|
164
|
+
([GHSA-h27x-rffw-24p4](https://github.com/sporkmonger/addressable/security/advisories/GHSA-h27x-rffw-24p4)).
|
|
165
|
+
Addressable 2.8.10 mitigates only part of it, and the advisory lists every release
|
|
166
|
+
below 2.9.0 as affected. The gem never calls `Addressable::Template`, so v5.x is not
|
|
167
|
+
affected and keeps the wider constraint. v6.0.0 raises the floor to the 2.9 series so
|
|
168
|
+
that dependency scanners stop flagging the gem's resolved dependency tree.
|
|
169
|
+
|
|
170
|
+
The `~> 2.8` constraint already permits 2.9.0, so most applications resolve it after
|
|
171
|
+
`bundle update addressable`. The upgrade fails only when another gem in the bundle
|
|
172
|
+
caps addressable below 2.9.0. In that case, update or replace that gem, or stay on
|
|
173
|
+
the latest v5.x release.
|
|
174
|
+
|
|
175
|
+
#### Minimum activesupport version
|
|
176
|
+
|
|
177
|
+
v6.0.0 depends on `activesupport >= 7.0.9`. v5.x accepts `>= 5.0`.
|
|
178
|
+
|
|
179
|
+
Two things set the floor. The `Git::GitExecuteError` deprecation warning passes its
|
|
180
|
+
text to ActiveSupport's `DeprecatedConstantProxy` through the `message:` keyword, which
|
|
181
|
+
no release before 6.0.3 accepts on Ruby 3. Separately, activesupport requires
|
|
182
|
+
`base64`, `bigdecimal`, `drb`, and `mutex_m` from the standard library, and Ruby 3.4
|
|
183
|
+
removed those from the default gems, so on Ruby 3.4 or later `require 'git'` fails
|
|
184
|
+
under Bundler unless a gem in the bundle declares them. Activesupport 7.0.9 is the
|
|
185
|
+
first 7.0.x release that declares them as dependencies; every 7.1.0 and later release
|
|
186
|
+
does too. The floor applies on every Ruby version so that Bundler reports the conflict
|
|
187
|
+
when it resolves the bundle, instead of `require 'git'` failing on Ruby 3.4.
|
|
188
|
+
|
|
189
|
+
Most applications already resolve a newer activesupport. The upgrade fails only when
|
|
190
|
+
another gem in the bundle caps activesupport below 7.0.9. In that case, update or
|
|
191
|
+
replace that gem, or stay on the latest v5.x release.
|
|
192
|
+
|
|
193
|
+
### Changes the deprecation run does not catch or does not explain
|
|
194
|
+
|
|
195
|
+
Most changes below never emitted a warning in v5.x, because the method keeps its name
|
|
196
|
+
and changes what it returns or does, or keeps working after the upgrade with a
|
|
197
|
+
different result. Two of them warned, `stash_list` and the context-helper block form,
|
|
198
|
+
but neither is a removed API, so the [Removed APIs](#removed-apis) table has no row
|
|
199
|
+
for them and their entries live here. A clean run under
|
|
200
|
+
`GIT_DEPRECATION_BEHAVIOR=raise` is therefore not proof that your code is unaffected.
|
|
201
|
+
Search your code for each one before upgrading.
|
|
202
|
+
|
|
203
|
+
#### Filesystem errors raised as `Git::Error`
|
|
204
|
+
|
|
205
|
+
The gem's own filesystem calls used to let a bare `SystemCallError` escape, which
|
|
206
|
+
contradicted the documented contract that the gem raises only `ArgumentError` or a
|
|
207
|
+
`Git::Error` subclass. Those calls now raise `Git::Error`, with the original error
|
|
208
|
+
available through `cause`.
|
|
209
|
+
|
|
210
|
+
The affected methods are `Git.open` (reading a gitdir pointer file), `Git.export`,
|
|
211
|
+
`Git::Repository#chdir`, `#with_index`, `#with_working`, `#with_temp_index`,
|
|
212
|
+
`#with_temp_working`, `#set_index`, `#set_working`, `#cat_file_contents`,
|
|
213
|
+
`#each_conflict`, `#archive`, and `#repo_size`. `Git.init`, `Git.clone`, `Git.bare`,
|
|
214
|
+
and `Git.open` also raise `Git::Error` when the directory argument or a
|
|
215
|
+
`:repository`, `:index`, or `:chdir` option cannot be expanded to an absolute path,
|
|
216
|
+
which happens when the process working directory has been removed.
|
|
47
217
|
|
|
48
|
-
|
|
218
|
+
```ruby
|
|
219
|
+
# v5.x
|
|
220
|
+
begin
|
|
221
|
+
Git.open('/path/to/repo')
|
|
222
|
+
rescue Errno::EACCES => e
|
|
223
|
+
handle_permission_problem(e)
|
|
224
|
+
end
|
|
49
225
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
226
|
+
# v6.x
|
|
227
|
+
begin
|
|
228
|
+
Git.open('/path/to/repo')
|
|
229
|
+
rescue Git::Error => e
|
|
230
|
+
raise unless e.cause.is_a?(Errno::EACCES)
|
|
231
|
+
|
|
232
|
+
handle_permission_problem(e.cause)
|
|
233
|
+
end
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Code that already rescues `Git::Error` needs no change. A `SystemCallError` raised by
|
|
237
|
+
your own block inside `chdir`, `with_working`, `with_temp_index`, `with_temp_working`,
|
|
238
|
+
or the block form of `cat_file_contents` still propagates unchanged, so the gem never
|
|
239
|
+
relabels an error raised by your code.
|
|
240
|
+
|
|
241
|
+
#### Gzip failures in `archive` raised as `Git::Error`
|
|
242
|
+
|
|
243
|
+
`Git::Repository#archive` with `format: 'tgz'` or `add_gzip: true` used to let a
|
|
244
|
+
`Zlib::Error` subclass escape when compression failed. It now raises `Git::Error`, with
|
|
245
|
+
the `Zlib::Error` available through `cause`. Code that already rescues `Git::Error`
|
|
246
|
+
needs no change.
|
|
247
|
+
|
|
248
|
+
#### Relative `:repository` and `:index` paths
|
|
249
|
+
|
|
250
|
+
A relative `:repository` option of `Git.open` or `Git.init`, and a relative `:index`
|
|
251
|
+
option of `Git.open`, `Git.init`, or `Git.clone`, is now expanded against the process
|
|
252
|
+
working directory, the same way the positional directory argument, `set_index`, and
|
|
253
|
+
`set_working` treat a relative path. A relative `:repository` used to be expanded
|
|
254
|
+
against the working directory, and a relative `:index` against the git directory.
|
|
255
|
+
For `Git.clone` with the `:chdir` option, a relative `:index` is expanded against
|
|
256
|
+
`:chdir` instead, like the clone directory itself.
|
|
257
|
+
|
|
258
|
+
Omitted options resolve as before: `:repository` defaults to `<working_dir>/.git` and
|
|
259
|
+
`:index` to `<git_dir>/index`. Absolute paths are unaffected. A relative `:repository`
|
|
260
|
+
option of `Git.clone` keeps its meaning: it is relative to `:chdir` when given and to
|
|
261
|
+
the process working directory otherwise, which is where git already resolved it.
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
# v5.x: the index is bound to /path/to/repo/.git/scratch.index
|
|
265
|
+
repo = Git.open('/path/to/repo', index: 'scratch.index')
|
|
266
|
+
|
|
267
|
+
# v6.x: the index is bound to scratch.index in the process working directory.
|
|
268
|
+
# Join the path yourself to keep the v5.x location.
|
|
269
|
+
repo = Git.open('/path/to/repo', index: '/path/to/repo/.git/scratch.index')
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Tilde expansion in `Git.init` and `Git.clone` paths
|
|
273
|
+
|
|
274
|
+
`Git.init` and `Git.clone` now expand the directory argument and the `:repository` and
|
|
275
|
+
`:index` options before handing the path to git, so `~` is the home directory, as it
|
|
276
|
+
already is for `Git.bare`, `set_index`, and `set_working`. `Git.clone` expands its
|
|
277
|
+
`:chdir` option the same way, and `Git.open` expands its directory argument before
|
|
278
|
+
checking that it exists, so `Git.open('~/scratch')` opens the repository instead of
|
|
279
|
+
raising `ArgumentError`. git does no tilde expansion on its arguments, so a `~`-prefixed
|
|
280
|
+
path used to make git create a directory literally named `~` under the process working
|
|
281
|
+
directory, or under `:chdir` for `Git.clone`. For `Git.init('~/scratch')` the returned
|
|
282
|
+
repository then pointed at `$HOME/scratch`, which git had not created, and the first
|
|
283
|
+
command run on it failed. For a `~`-prefixed `:repository` or `:chdir` option of
|
|
284
|
+
`Git.clone`, git failed before cloning anything.
|
|
285
|
+
|
|
286
|
+
A caller who passed a `~`-prefixed path and wanted a directory named `~` must anchor
|
|
287
|
+
the path to keep it. Expanding before git runs is also visible in three other ways:
|
|
288
|
+
|
|
289
|
+
- git receives absolute paths, so a `:log` that recorded `Cloning into 'my-repo'...` now
|
|
290
|
+
records the absolute path.
|
|
291
|
+
- A `:repository`, `:index`, or `:chdir` that cannot be expanded raises before git runs,
|
|
292
|
+
with nothing on disk, instead of after the clone or init completed: `Git::Error` when
|
|
293
|
+
the process working directory has been removed, and `ArgumentError` for a `~user`
|
|
294
|
+
prefix that names no user.
|
|
295
|
+
- `..` is normalized lexically before git sees the path. `Git.init('a/../b')` creates
|
|
296
|
+
only `b`, where `git init a/../b` at a shell prompt also created `a`, and a path
|
|
297
|
+
through a symlinked directory resolves to where the link appears rather than where it
|
|
298
|
+
points.
|
|
299
|
+
|
|
300
|
+
The rule these methods now share is recorded in
|
|
301
|
+
[ADR-0010](docs/adr/0010-a-repository-locating-path-means-what-it-would-mean-at-a-shell-prompt.md).
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
# v5.x: git creates ./~/scratch; the returned repository points at $HOME/scratch
|
|
305
|
+
repo = Git.init('~/scratch')
|
|
306
|
+
|
|
307
|
+
# v6.x: git creates $HOME/scratch and the returned repository is bound to it
|
|
308
|
+
repo = Git.init('~/scratch')
|
|
309
|
+
|
|
310
|
+
# v6.x: anchor the path to keep a directory literally named ~
|
|
311
|
+
repo = Git.init('./~/scratch')
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### Context helpers yield a separate repository
|
|
315
|
+
|
|
316
|
+
`Git::Repository#with_index`, `#with_temp_index`, `#with_working`, and
|
|
317
|
+
`#with_temp_working` used to rebind the receiver to the other index or working tree
|
|
318
|
+
for the duration of the block and yield the receiver itself. They now build a second
|
|
319
|
+
repository of the receiver's class bound to that index or working tree, yield it,
|
|
320
|
+
and leave the receiver bound to its original index and working tree.
|
|
321
|
+
|
|
322
|
+
Code that uses the block parameter and finishes with it before the block ends needs
|
|
323
|
+
no change. A block that declares no positional parameter, the v5.x form, now raises
|
|
324
|
+
`ArgumentError` before the block runs. Starting in v5.6.0 that form warns through
|
|
325
|
+
`Git::Deprecation`, so clear the warning on the latest v5.x release before upgrading.
|
|
326
|
+
A call with no block raises `ArgumentError` instead of `LocalJumpError`. Code that
|
|
327
|
+
declares the parameter but ignores it and calls methods on the outer repository
|
|
328
|
+
inside the block runs those calls against the original index or working tree. Use the
|
|
329
|
+
block parameter instead:
|
|
330
|
+
|
|
331
|
+
```ruby
|
|
332
|
+
# v5.x
|
|
333
|
+
repo.with_temp_index do
|
|
334
|
+
repo.read_tree('HEAD')
|
|
335
|
+
repo.write_tree
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# v6.x
|
|
339
|
+
repo.with_temp_index do |indexed|
|
|
340
|
+
indexed.read_tree('HEAD')
|
|
341
|
+
indexed.write_tree
|
|
342
|
+
end
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The same applies to reading `index` or `dir` inside the block to find the temporary
|
|
346
|
+
path: read them on the block parameter. A block that needs only the changed process
|
|
347
|
+
directory, such as one that writes files inside `with_temp_working`, still declares
|
|
348
|
+
the parameter (`do |_scratch|`).
|
|
349
|
+
|
|
350
|
+
A helper nested inside another must also be called on the block parameter. A nested
|
|
351
|
+
call on the outer repository derives from the outer repository's original index and
|
|
352
|
+
working tree, so it does not see the outer block's temporary location:
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
# v5.x
|
|
356
|
+
repo.with_temp_working do
|
|
357
|
+
repo.with_temp_index do
|
|
358
|
+
repo.add('.')
|
|
359
|
+
repo.write_tree
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# v6.x
|
|
364
|
+
repo.with_temp_working do |scratch|
|
|
365
|
+
scratch.with_temp_index do |indexed|
|
|
366
|
+
indexed.add('.')
|
|
367
|
+
indexed.write_tree
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Calling `set_index` or `set_working` on the outer repository inside the block is no
|
|
373
|
+
longer undone when the block ends. In v5.x the block restored the receiver's
|
|
374
|
+
original index and working tree on exit; in v6.x there is no restore step, so the
|
|
375
|
+
receiver stays bound to whatever `set_index` or `set_working` gave it. Both methods
|
|
376
|
+
are deprecated in v6.0.0 (see [`set_index` and `set_working`
|
|
377
|
+
deprecated](#set_index-and-set_working-deprecated)).
|
|
378
|
+
|
|
379
|
+
The repository yielded by `with_temp_index` or `with_temp_working` stays bound to
|
|
380
|
+
the temporary path after the block removes it. This is the one case where code that
|
|
381
|
+
already used the block parameter has to change. If the yielded repository escapes
|
|
382
|
+
the block, directly or inside an object that holds it and later runs commands, calls
|
|
383
|
+
against the removed working tree raise `Git::Error`. Against the removed index,
|
|
384
|
+
reads do not raise: git treats the missing index file as an empty index, so
|
|
385
|
+
`ls_files` returns nothing and `status_info` reports every tracked file both as
|
|
386
|
+
deleted and as untracked. Writes such as `add` do raise `Git::Error`. Reads from
|
|
387
|
+
the object database, such as `Git::Object::AbstractObject#contents`, still work. In
|
|
388
|
+
v5.x an escaped object held the outer repository, which had been rebound to the
|
|
389
|
+
original path by then.
|
|
390
|
+
|
|
391
|
+
The yielded repository is built with `self.class.new(execution_context:)`, so a
|
|
392
|
+
subclass of `Git::Repository` has to accept that call. A subclass whose `initialize`
|
|
393
|
+
takes different keywords raises `ArgumentError` from these helpers. One that takes a
|
|
394
|
+
positional argument instead receives the keywords as a Hash and yields a
|
|
395
|
+
misconfigured repository, so check the constructor rather than waiting for an
|
|
396
|
+
exception.
|
|
397
|
+
|
|
398
|
+
`with_working` and `with_temp_working` still change the process working directory
|
|
399
|
+
with `Dir.chdir` for the duration of the block, so they remain unsafe to call from
|
|
400
|
+
more than one thread at a time.
|
|
401
|
+
|
|
402
|
+
#### `Git.init`, `Git.open`, and `Git.bare` reject unknown options
|
|
403
|
+
|
|
404
|
+
`Git.init`, `Git.open`, and `Git.bare` now raise `ArgumentError` when the options
|
|
405
|
+
hash contains a key they do not accept, the same way `Git.ls_remote` already does.
|
|
406
|
+
v5.x ignored unknown keys, so a typo such as `respository:` or an unsupported key
|
|
407
|
+
silently returned a repository bound to paths the caller did not ask for, and
|
|
408
|
+
`Git.init` created the repository in the default location instead of the one
|
|
409
|
+
the mistyped key was meant to name.
|
|
410
|
+
|
|
411
|
+
For the APIs that did validate option names in v5.x, see
|
|
412
|
+
[Unsupported options raise `ArgumentError`](#unsupported-options-raise-argumenterror).
|
|
413
|
+
|
|
414
|
+
The accepted keys are:
|
|
415
|
+
|
|
416
|
+
- `Git.init`: `:bare`, `:initial_branch`, `:repository`, `:separate_git_dir`,
|
|
417
|
+
`:index`, `:log`, `:git_ssh`, and `:binary_path`
|
|
418
|
+
- `Git.open`: `:repository`, `:index`, `:log`, `:git_ssh`, and `:binary_path`
|
|
419
|
+
- `Git.bare`: `:index`, `:log`, `:git_ssh`, and `:binary_path`
|
|
420
|
+
|
|
421
|
+
The check runs before any filesystem or git call, so a bad key fails fast. To fix a
|
|
422
|
+
call that now raises, drop the key.
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
# v5.x: the typo is ignored and the .git directory is auto-detected
|
|
426
|
+
# v6.x: raises ArgumentError, "Unknown options: respository"
|
|
427
|
+
repo = Git.open('/path/to/worktree', respository: '/srv/repo.git')
|
|
428
|
+
|
|
429
|
+
# v6.x: the corrected call opens the repository
|
|
430
|
+
repo = Git.open('/path/to/worktree', repository: '/srv/repo.git')
|
|
431
|
+
|
|
432
|
+
# v5.x: the typo is ignored and the repository is created at /path/to/worktree/.git
|
|
433
|
+
# v6.x: raises ArgumentError, "Unknown options: separate_gitdir"
|
|
434
|
+
repo = Git.init('/path/to/worktree', separate_gitdir: '/srv/repo.git')
|
|
435
|
+
|
|
436
|
+
# v6.x: the corrected call creates the repository at /srv/repo.git
|
|
437
|
+
repo = Git.init('/path/to/worktree', separate_git_dir: '/srv/repo.git')
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
#### `tag_create` raises when the created tag is missing
|
|
441
|
+
|
|
442
|
+
In v5.x, `g.tag_create` returned `nil` when the tag it had just created was missing from
|
|
443
|
+
the tag list (for example, another process deleted it before the lookup). It never
|
|
444
|
+
emitted a deprecation warning, since the method keeps its name. In v6.0.0 it raises
|
|
445
|
+
`Git::UnexpectedResultError` instead, so its return value is always a `Git::TagInfo`.
|
|
446
|
+
Search for `tag_create` before upgrading and remove any check for a `nil` result.
|
|
447
|
+
|
|
448
|
+
#### `stash_list` returns an Array of `Git::StashInfo`
|
|
449
|
+
|
|
450
|
+
In v5.x, `g.stash_list` returned the `git stash list` text as a `String` and emitted a
|
|
451
|
+
`Git::Deprecation` warning on every call. A project that silences or ignores deprecation
|
|
452
|
+
warnings never acts on that notice, and in v6.0.0 the call keeps working with a
|
|
453
|
+
different return type: `Array<Git::StashInfo>`, newest first, the same value as
|
|
454
|
+
`Git::Repository#stash_infos`, which stays as a permanent alias. Search for `stash_list`
|
|
455
|
+
before upgrading. Code that needs the text builds it from the entries:
|
|
456
|
+
`g.stash_list.map { |s| "#{s.name}: #{s.message}" }.join("\n")`.
|
|
457
|
+
|
|
458
|
+
#### `stash_store` raises when the stored entry is missing
|
|
459
|
+
|
|
460
|
+
In v5.x, `g.stash_store` returned the top entry of the stash list after the store, so it
|
|
461
|
+
returned `nil` when the list was empty and another process's entry when one had been
|
|
462
|
+
pushed in between. It never emitted a deprecation warning, since the method keeps its
|
|
463
|
+
name. In v6.0.0 it returns the entry for the commit it stored and raises
|
|
464
|
+
`Git::UnexpectedResultError` when that entry is missing, so its return value is always a
|
|
465
|
+
`Git::StashInfo`. A commit that does not resolve raises `Git::FailedError` before
|
|
466
|
+
anything is stored. A `nil` commit or one that begins with `-` raises `ArgumentError` as
|
|
467
|
+
in v5.x, with a different message; one that begins with `^` raises `ArgumentError` where
|
|
468
|
+
v5.x raised `Git::FailedError`. An annotated tag name now stores the tagged commit; v5.x
|
|
469
|
+
stored the tag object, which hid every entry from `git stash list`. Search for
|
|
470
|
+
`stash_store` before upgrading and remove any check for a `nil` result.
|
|
471
|
+
|
|
472
|
+
#### `worktree_add` returns `Git::WorktreeInfo` and raises when the worktree is missing
|
|
473
|
+
|
|
474
|
+
In v4.x and v5.x, `g.worktree_add` returned the `git worktree add` output
|
|
475
|
+
(`"HEAD is now at …"`) as a `String` and never emitted a deprecation warning, since the
|
|
476
|
+
method keeps its name. In v6.0.0 it returns the new worktree's `Git::WorktreeInfo`, the
|
|
477
|
+
same entry `g.worktree_list` reports for it, and raises `Git::UnexpectedResultError`
|
|
478
|
+
when that entry is missing after the add, as `tag_create` and `stash_store` do. A
|
|
479
|
+
`rescue Git::FailedError` around the call no longer covers every error it can raise.
|
|
480
|
+
Search for `worktree_add` before upgrading.
|
|
481
|
+
Code that used the return value as a `String` reads `info.path`, `info.head`, and
|
|
482
|
+
`info.branch` instead; `Git::WorktreeInfo#to_s` is the path, so string interpolation of
|
|
483
|
+
the result yields the worktree path.
|
|
484
|
+
|
|
485
|
+
#### `Git::Deprecation` horizon is prose
|
|
486
|
+
|
|
487
|
+
v6.0.0 constructs `Git::Deprecation` with the horizon `"in a future major release"`.
|
|
488
|
+
v5.x used `"6.0.0"`. The gem never puts the horizon into a warning, so the warnings
|
|
489
|
+
themselves do not change. The horizon reaches your code through the
|
|
490
|
+
`Git::Deprecation.deprecation_horizon` reader, the `deprecation_horizon` key of the
|
|
491
|
+
payload the `:notify` behavior publishes, and the third argument of a custom
|
|
492
|
+
`behavior` or `disallowed_behavior` proc declared with four parameters. Code that
|
|
493
|
+
parses that value as a version, for example with `Gem::Version.new`, now raises; read
|
|
494
|
+
the removal version from the warning text instead, which names it once it is decided.
|
|
495
|
+
|
|
496
|
+
### Removed APIs
|
|
497
|
+
|
|
498
|
+
Every API in this table emitted a deprecation warning in v5.x that named its
|
|
499
|
+
replacement when it was called, constructed, or used, and each row links to the entry
|
|
500
|
+
under "Upgrading to v5.x" that maps every call shape, reader, and option to its
|
|
501
|
+
replacement, including return shape differences. A bare reference to a removed
|
|
502
|
+
constant (`is_a?`, `rescue`, `case ... when`, `defined?`) did not warn, except for
|
|
503
|
+
`Git::CommandLineResult`, so search for each constant in the table as well as
|
|
504
|
+
clearing the warnings. In v6.0.0 a removed constant raises `NameError` when
|
|
505
|
+
referenced, a removed method raises `NoMethodError` when called, and a removed option
|
|
506
|
+
raises `ArgumentError` like any other unsupported option (see [Unsupported options
|
|
507
|
+
raise `ArgumentError`](#unsupported-options-raise-argumenterror)).
|
|
508
|
+
|
|
509
|
+
| Removed in v6.0.0 | Use instead | Migration entry |
|
|
510
|
+
| --- | --- | --- |
|
|
511
|
+
| `Git::Repository#add_remote`, `#remove_remote`, `#set_remote_url`, `#add_tag`, `#delete_tag` | `remote_add`, `remote_remove`, `remote_set_url`, `tag_create`, `tag_delete` | [Facade method renames](#facade-method-renames) |
|
|
512
|
+
| `Git::Repository#empty?`, `#reset_hard`, `#conflicts`, `#is_local_branch?`, `#is_remote_branch?`, `#is_branch?`, `#branches_all` | `no_commits?`, `reset(commitish, hard: true)`, `each_conflict`, `local_branch?`, `remote_branch?`, `branch?`, `branch_list` | [`Git::Repository` method renames](#gitrepository-method-renames) |
|
|
513
|
+
| `Git::Repository#object_contents`, `#object_size`, `#object_type`, `#commit_data`, `#tag_data`, `#revparse`, `#namerev`, `#diff_name_status` | `cat_file_contents`, `cat_file_size`, `cat_file_type`, `cat_file_commit`, `cat_file_tag`, `rev_parse`, `name_rev`, `diff_path_status` | [`Git::Repository` alias renames](#gitrepository-alias-renames) |
|
|
514
|
+
| `clean(ff: true)` and `clean(force_force: true)`; `diff_path_status(path: ...)`; `commit(add_all: true)`; the positional `check` argument of `set_working` and `set_index` | `force: 2`; `:path_limiter`; `:all`; `must_exist:` | [`Git::Repository` option renames](#gitrepository-option-renames) |
|
|
515
|
+
| `Git::Repository#config` and `#global_config`; `Git.global_config`; `config` and `global_config` as instance methods of the `Git` module | `config_get`, `config_set`, and `config_list` on `Git::Repository` or `Git`, with `global: true` for the global scope | [v4.x-style configuration methods](#v4x-style-configuration-methods), [`Git` module mixin deprecations](#git-module-mixin-deprecations) |
|
|
516
|
+
| `Git.binary_version`; `Git.ls_remote(nil)` | `Git.git_version` (`.to_a` for the Array); `Git.ls_remote` with no argument or `'.'` | [Module-level `Git` function deprecations](#module-level-git-function-deprecations) |
|
|
517
|
+
| `Git.clone` options `:path`, `:recursive`, and `:remote` | `:chdir`, `:recurse_submodules`, and `:origin` | [`Git.clone` option renames](#gitclone-option-renames) |
|
|
518
|
+
| `Git.export` option `:remote` | Delete the option; it has no replacement | [`Git.export` `:remote` option deprecated](#gitexport-remote-option-deprecated) |
|
|
519
|
+
| `Git::Base` | Include an application-owned module into `Git::Repository` | [`Git::Base` removed](#gitbase-removed) |
|
|
520
|
+
| `Git::Repository#lib` | Call the facade method directly on the repository | [`Git::Lib` removed](#gitlib-removed) |
|
|
521
|
+
| `Git::CommandLineResult` | `Git::CommandLine::Result` | [`Git::CommandLineResult` deprecated](#gitcommandlineresult-deprecated) |
|
|
522
|
+
| `Git::Log#each`, `#size`, `#to_s`, `#first`, `#last`, `#[]`, and every other `Enumerable` method on `Git::Log` | `Git::Log#execute`, which returns a `Git::Log::Result` with the same methods | [`Git::Log` Enumerable interface deprecated](#gitlog-enumerable-interface-deprecated) |
|
|
523
|
+
| `Git::Object::Commit#set_commit` | `from_data` | [`Git::Object::Commit#set_commit` deprecated](#gitobjectcommitset_commit-deprecated) |
|
|
524
|
+
| `Git::Author` | `Git::AuthorInfo` (`parse` to build one, `with` in place of the writers) | [`Git::Author` deprecated](#gitauthor-deprecated) |
|
|
525
|
+
| `Git::Branch#stashes` | `Git::Repository#stash_infos` | [`Git::Branch#stashes` deprecated](#gitbranchstashes-deprecated) |
|
|
526
|
+
| `Git::Stash`, `Git::Stashes`, `Git::Repository#stashes_all`, `#stash_save` | `stash_list` (or its alias `stash_infos`), `stash_push`, and the name-based stash operations | [Legacy stash API deprecated](#legacy-stash-api-deprecated) |
|
|
527
|
+
| `Git::Repository#remotes` | `remote_list`, or `remote_names` for the names alone | [`Git::Repository#remotes` deprecated](#gitrepositoryremotes-deprecated) |
|
|
528
|
+
| `Git::Remote`, `Git::Repository#remote`, `#config_remote` | `remote_list`, which returns `Git::RemoteInfo` objects; filter `config_list` on the `remote.<name>.` prefix for keys it does not model | [`Git::Remote` deprecated](#gitremote-deprecated) |
|
|
529
|
+
| The `allow_unknown_type:` option of `Git::Commands::CatFile::Raw` | No replacement | [`Git::Commands::CatFile::Raw` `allow_unknown_type` option deprecated](#gitcommandscatfileraw-allow_unknown_type-option-deprecated) |
|
|
530
|
+
| `Git::Branch`, `Git::Branches`, `Git::Repository#branch`, `#branches` | `branch_list`, which returns `Git::BranchInfo` objects, and the name-based branch operations | [`Git::Branch` and `Git::Branches` deprecated](#gitbranch-and-gitbranches-deprecated) |
|
|
531
|
+
| `Git::Object::Tag`, `Git::Repository#tag`, `#tags`, `#tag_add`, and the `is_tag` argument of `Git::Object.new` | `tag_list` and `tag_create`, which return `Git::TagInfo` objects | [`Git::Object::Tag` deprecated](#gitobjecttag-deprecated) |
|
|
532
|
+
| `Git::Status`, `Git::Status::StatusFile`, `Git::Repository#status` | `status_info`, which returns a `Git::StatusInfo` | [`Git::Status` deprecated](#gitstatus-deprecated) |
|
|
533
|
+
| `Git::Worktree`, `Git::Worktrees`, `Git::Repository#worktree`, `#worktrees`, `#worktrees_all` | `worktree_list`, which returns `Git::WorktreeInfo` objects, and the path-based worktree operations | [`Git::Worktree` and `Git::Worktrees` deprecated](#gitworktree-and-gitworktrees-deprecated) |
|
|
534
|
+
|
|
535
|
+
Notes on specific rows:
|
|
536
|
+
|
|
537
|
+
- `add_tag`: go straight to `tag_create`. The `tag_add` that the v5.x warning names is
|
|
538
|
+
removed too.
|
|
539
|
+
- `diff_name_status` callers that passed `:path` must also switch to `:path_limiter`.
|
|
540
|
+
- `cat_file` is unaffected and stays as a legacy name for `cat_file_contents`, and
|
|
541
|
+
`stash_infos` stays as an alias of `stash_list`.
|
|
542
|
+
- `set_working` and `set_index`: a positional `check` argument raises `ArgumentError`
|
|
543
|
+
for the wrong number of arguments. Pass `must_exist:` instead; it defaults to
|
|
544
|
+
`true`. An explicit `must_exist: nil` no longer means "not given". v5.x treated it
|
|
545
|
+
as `true`, and v6.0.0 treats it as `false` like any other falsy value. Omit the
|
|
546
|
+
keyword to get the default. Both methods are deprecated in v6.0.0 (see [`set_index`
|
|
547
|
+
and `set_working` deprecated](#set_index-and-set_working-deprecated)), so consider
|
|
548
|
+
replacing the call instead of updating its arguments.
|
|
549
|
+
- `Git.ls_remote(nil)`: an explicit `nil` repository argument raises `ArgumentError`
|
|
550
|
+
with the message `repository must not be nil`. Omitting the argument still defaults
|
|
551
|
+
to `'.'`, so `Git.ls_remote` and `Git.ls_remote('.', opts)` are unchanged.
|
|
552
|
+
- `Git.config` (the gem-configuration accessor used as `Git.config.binary_path`) and
|
|
553
|
+
`Git.configure` are not part of the configuration API removal and are unchanged.
|
|
554
|
+
- `Git.export` `:remote` renamed the clone's remote, and `Git.export` deletes the `.git`
|
|
555
|
+
directory before returning, so the name was never observable.
|
|
556
|
+
- `allow_unknown_type`: git 2.50 removed the unknown-type feature and accepts the flag
|
|
557
|
+
as a no-op, and on git 2.43 through 2.49 the ability to query the type and size of an
|
|
558
|
+
object of unknown type goes with the option.
|
|
559
|
+
- `status` to `status_info`: the `changed`, `added`, `deleted`, and `untracked` readers
|
|
560
|
+
keep their names, but the categories are derived from both porcelain status
|
|
561
|
+
characters and clean tracked paths are no longer listed. Read the v5.x entry before
|
|
562
|
+
changing the call.
|
|
563
|
+
- `g.branch(name)`: the string constructor could mis-split a remote-tracking name when
|
|
564
|
+
the remote name itself contains a slash (`remotes/team/upstream/main`). `branch_list`
|
|
565
|
+
resolves configured remote names and has no such limitation.
|
|
566
|
+
|
|
567
|
+
### Deprecated in v6.0.0
|
|
568
|
+
|
|
569
|
+
Both APIs below keep working in v6.0.0 and warn through `Git::Deprecation` every time
|
|
570
|
+
they are used. A later major release removes them.
|
|
571
|
+
|
|
572
|
+
#### `set_index` and `set_working` deprecated
|
|
573
|
+
|
|
574
|
+
`Git::Repository#set_index` and `#set_working` rebind the receiver to another index
|
|
575
|
+
file or working tree. They are the last mutable state on `Git::Repository`. Once
|
|
576
|
+
they are gone, a repository object is bound at construction and never changes.
|
|
577
|
+
Until then, the rebind retargets every object that holds the receiver, such as a
|
|
578
|
+
`Git::Object`, a `Git::Log`, or a second caller that was handed the same
|
|
579
|
+
repository. v6.0.0 keeps both methods but warns on every call through
|
|
580
|
+
`Git::Deprecation`, and a later major release removes them. The warnings are:
|
|
581
|
+
|
|
582
|
+
- `Git::Repository#set_index is deprecated and will be removed in a future major
|
|
583
|
+
release. Open a repository bound to the index instead: Git.open(dir, index: path)
|
|
584
|
+
or Git.bare(git_dir, index: path).`
|
|
585
|
+
- `Git::Repository#set_working is deprecated and will be removed in a future major
|
|
586
|
+
release. Open a repository bound to the working tree instead: Git.open(work_dir,
|
|
587
|
+
repository: git_dir).`
|
|
588
|
+
|
|
589
|
+
Open a repository bound to the index or working tree up front instead of rebinding
|
|
590
|
+
it afterward. `Git.open` accepts `:index` and `:repository`, and `Git.bare` accepts
|
|
591
|
+
`:index`:
|
|
592
|
+
|
|
593
|
+
```ruby
|
|
594
|
+
# instead of
|
|
595
|
+
repo = Git.open('/path/to/repo')
|
|
596
|
+
repo.set_index('/path/to/custom.index')
|
|
597
|
+
|
|
598
|
+
# open the bound repository
|
|
599
|
+
repo = Git.open('/path/to/repo', index: '/path/to/custom.index')
|
|
600
|
+
|
|
601
|
+
# instead of
|
|
602
|
+
repo = Git.bare('/srv/repo.git')
|
|
603
|
+
repo.set_index('/tmp/scratch.index')
|
|
604
|
+
|
|
605
|
+
# open the bound bare repository
|
|
606
|
+
repo = Git.bare('/srv/repo.git', index: '/tmp/scratch.index')
|
|
607
|
+
|
|
608
|
+
# instead of
|
|
609
|
+
repo.set_working('/path/to/worktree')
|
|
610
|
+
|
|
611
|
+
# open the bound repository
|
|
612
|
+
repo = Git.open('/path/to/worktree', repository: '/path/to/repo/.git')
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
`Git.open` and `Git.bare` build the repository from scratch and carry over nothing
|
|
616
|
+
the caller does not pass. A receiver opened with a custom `:index`, `:git_ssh`,
|
|
617
|
+
`:binary_path`, or `:log` passes the same values again; `set_working` kept the
|
|
618
|
+
receiver's index, so its replacement needs `:index` whenever that index was custom.
|
|
619
|
+
When `:repository` is given without `:index`, the index resolves to
|
|
620
|
+
`<repository>/index`.
|
|
621
|
+
|
|
622
|
+
A replacement built from an existing object reads the paths back from it.
|
|
623
|
+
`repo.repo`, `repo.dir`, and `repo.index` return the `.git` directory, working tree,
|
|
624
|
+
and index file as `Pathname`s. A repository opened without `:index` has `repo.index`
|
|
625
|
+
pointing at `<git dir>/index`, so passing it back is harmless. The repository exposes
|
|
626
|
+
no public reader for `:git_ssh`, `:binary_path`, or `:log`, so a caller that opened
|
|
627
|
+
with any of them passes the same values again from wherever they were first built:
|
|
628
|
+
|
|
629
|
+
```ruby
|
|
630
|
+
# instead of
|
|
631
|
+
repo.set_working('/path/to/worktree')
|
|
632
|
+
|
|
633
|
+
# rebind from an existing object, keeping its .git directory and index
|
|
634
|
+
rebound = Git.open('/path/to/worktree',
|
|
635
|
+
repository: repo.repo.to_s, index: repo.index.to_s,
|
|
636
|
+
git_ssh: ssh_command, binary_path: git_binary, log: logger)
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
A caller that needs a copy of an existing object for the duration of a block, with
|
|
640
|
+
every setting intact, uses `with_index` or `with_working` and the block parameter.
|
|
641
|
+
The yielded repository keeps every setting the call does not replace: the logger,
|
|
642
|
+
`git_ssh`, `binary_path`, and the receiver's working tree under `with_index` or its
|
|
643
|
+
index under `with_working`:
|
|
644
|
+
|
|
645
|
+
```ruby
|
|
646
|
+
repo.with_working('/path/to/worktree') do |bound|
|
|
647
|
+
bound.add('.')
|
|
648
|
+
end
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
`set_working(dir, must_exist: false)` has no replacement. `Git.open` and
|
|
652
|
+
`with_working` both raise `ArgumentError` when the working directory does not exist,
|
|
653
|
+
so a repository can no longer be bound to a directory that is created later. When the
|
|
654
|
+
missing directory's parent exists, git runs commands that do not read the working
|
|
655
|
+
tree, such as `rev_parse` or `current_branch`, and only commands that need the
|
|
656
|
+
working tree fail until it exists; when the parent is missing too, git rejects every
|
|
657
|
+
command with an invalid path error. Create the directory, then call `Git.open`. If
|
|
658
|
+
your code needs the deferred bind, open an issue describing the use case; under
|
|
659
|
+
ADR-0007 that becomes a feature request. `set_index(path, must_exist: false)` has no
|
|
660
|
+
gap: the `:index` option is not checked for existence.
|
|
661
|
+
|
|
662
|
+
#### `Git::GitExecuteError` deprecated
|
|
663
|
+
|
|
664
|
+
`Git::GitExecuteError` has been a deprecated alias for `Git::Error` since v2.0.0 and
|
|
665
|
+
has warned whenever it is rescued or instantiated since then. The warning now follows
|
|
666
|
+
the project's deprecation policy: it names the replacement and says the alias is
|
|
667
|
+
removed in a future major release, and this entry records it. The warning is:
|
|
668
|
+
|
|
669
|
+
- `Git::GitExecuteError is deprecated and will be removed in a future major release.
|
|
670
|
+
Use Git::Error instead.`
|
|
671
|
+
|
|
672
|
+
Replace every reference with `Git::Error`. The two constants name the same class, so a
|
|
673
|
+
`rescue Git::Error` clause catches everything a `rescue Git::GitExecuteError` clause did.
|
|
674
|
+
|
|
675
|
+
```ruby
|
|
676
|
+
# instead of
|
|
677
|
+
rescue Git::GitExecuteError => e
|
|
678
|
+
|
|
679
|
+
# rescue the class directly
|
|
680
|
+
rescue Git::Error => e
|
|
681
|
+
```
|
|
56
682
|
|
|
57
683
|
---
|
|
58
684
|
|
|
@@ -60,25 +686,24 @@ To prepare:
|
|
|
60
686
|
|
|
61
687
|
### Overview
|
|
62
688
|
|
|
63
|
-
v5.0.0
|
|
64
|
-
for
|
|
65
|
-
v5.x.
|
|
689
|
+
v5.0.0 replaces the internal architecture while keeping the v4.x API working
|
|
690
|
+
for most users. Most v4.x code runs on v5.x without changes.
|
|
66
691
|
|
|
67
692
|
The new architecture introduces a layered design (`Git::Commands`,
|
|
68
|
-
`Git::Repository`, and associated parsers). Compatibility shims
|
|
69
|
-
forwarding methods that map old call patterns to the new API
|
|
70
|
-
|
|
71
|
-
|
|
693
|
+
`Git::Repository`, and associated parsers). Compatibility shims, deprecated
|
|
694
|
+
forwarding methods that map old call patterns to the new API, keep v4.x code
|
|
695
|
+
working. These shims emit deprecation warnings that tell you what to change and
|
|
696
|
+
what v6.0.0 removes.
|
|
72
697
|
|
|
73
|
-
Hard breaks are limited to
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
698
|
+
Hard breaks are limited to the few things that had no safe migration path.
|
|
699
|
+
The [Breaking changes](#breaking-changes) section describes them, followed by
|
|
700
|
+
[Deprecated methods](#deprecated-methods) that still work in v5.x but are
|
|
701
|
+
removed in v6.0.0.
|
|
77
702
|
|
|
78
|
-
|
|
79
|
-
|
|
703
|
+
To suppress or configure deprecation warnings, see the [Deprecations](README.md#deprecations)
|
|
704
|
+
section of the README.
|
|
80
705
|
|
|
81
|
-
|
|
706
|
+
Changes at a glance:
|
|
82
707
|
|
|
83
708
|
| Change | Type | Impact | Action required |
|
|
84
709
|
|--------|------|--------|-----------------|
|
|
@@ -95,59 +720,57 @@ For information on how to suppress or configure deprecation warnings, see the
|
|
|
95
720
|
|
|
96
721
|
#### `Git::Base` removed
|
|
97
722
|
|
|
98
|
-
`Git::Base
|
|
99
|
-
|
|
100
|
-
`Git::Repository`, which
|
|
101
|
-
same public API.
|
|
723
|
+
`Git::Base`, the class that `Git.open`, `Git.clone`, `Git.init`, and `Git.bare`
|
|
724
|
+
returned, is removed in v5.0.0. All four entry points now return
|
|
725
|
+
`Git::Repository`, which exposes the same public API.
|
|
102
726
|
|
|
103
|
-
|
|
727
|
+
Code that must be updated:
|
|
104
728
|
|
|
105
729
|
```ruby
|
|
106
|
-
# v4.x
|
|
730
|
+
# v4.x: explicit Git::Base reference (raises NameError in v5.x)
|
|
107
731
|
repo = Git::Base.new(working_directory: '/path/to/repo')
|
|
108
732
|
|
|
109
|
-
# v5.x
|
|
733
|
+
# v5.x: use the entry-point methods; do not construct Git::Repository directly
|
|
110
734
|
repo = Git.open('/path/to/repo')
|
|
111
735
|
```
|
|
112
736
|
|
|
113
737
|
```ruby
|
|
114
|
-
# v4.x
|
|
738
|
+
# v4.x: type-checking against Git::Base (raises NameError in v5.x because Git::Base is removed)
|
|
115
739
|
raise unless repo.is_a?(Git::Base)
|
|
116
740
|
|
|
117
|
-
# v5.x
|
|
741
|
+
# v5.x: check against Git::Repository
|
|
118
742
|
raise unless repo.is_a?(Git::Repository)
|
|
119
743
|
```
|
|
120
744
|
|
|
121
745
|
```ruby
|
|
122
|
-
# v4.x
|
|
746
|
+
# v4.x: requiring the internal file (raises LoadError in v5.x)
|
|
123
747
|
require 'git/base'
|
|
124
748
|
|
|
125
|
-
# v5.x
|
|
749
|
+
# v5.x: the public entry point is git itself; no internal require needed
|
|
126
750
|
require 'git'
|
|
127
751
|
```
|
|
128
752
|
|
|
129
|
-
**
|
|
130
|
-
`Git::Base` did. Code that
|
|
131
|
-
|
|
132
|
-
changes.
|
|
753
|
+
**The public API is unchanged.** `Git::Repository` provides every method that
|
|
754
|
+
`Git::Base` did. Code that calls methods on the object returned by `Git.open`
|
|
755
|
+
(e.g., `repo.commit`, `repo.status`, `repo.add`) requires no changes.
|
|
133
756
|
|
|
134
|
-
**Monkeypatching `Git::Base` is deprecated
|
|
757
|
+
**Monkeypatching `Git::Base` is deprecated.** v5.x includes a temporary
|
|
135
758
|
compatibility shim for applications that define instance methods on `Git::Base`.
|
|
136
|
-
|
|
137
|
-
definition emits a deprecation warning and
|
|
759
|
+
The shim makes those methods available on `Git::Repository` instances, but each
|
|
760
|
+
method definition emits a deprecation warning, and v6.0.0 removes the shim.
|
|
138
761
|
|
|
139
762
|
Move custom repository helpers to an application-owned extension module and
|
|
140
763
|
include or prepend that module into `Git::Repository` during application setup:
|
|
141
764
|
|
|
142
765
|
```ruby
|
|
143
|
-
# Deprecated in v5.x and
|
|
766
|
+
# Deprecated in v5.x and removed in v6.0.0
|
|
144
767
|
module Git::Base
|
|
145
768
|
def worktree_clean?
|
|
146
769
|
status.changed.empty?
|
|
147
770
|
end
|
|
148
771
|
end
|
|
149
772
|
|
|
150
|
-
# v5.x
|
|
773
|
+
# v5.x: keep the extension in application-owned code
|
|
151
774
|
module MyAppGitRepositoryExtensions
|
|
152
775
|
def worktree_clean?
|
|
153
776
|
status.changed.empty?
|
|
@@ -164,9 +787,9 @@ Git::Repository.include(MyAppGitRepositoryExtensions)
|
|
|
164
787
|
`Git.open`, `Git.clone`, `Git.init`, and `Git.bare` now return
|
|
165
788
|
`Git::Repository` instead of `Git::Base`.
|
|
166
789
|
|
|
167
|
-
For most callers this is transparent
|
|
168
|
-
methods.
|
|
169
|
-
tests
|
|
790
|
+
For most callers this is transparent, because the returned object responds to
|
|
791
|
+
the same methods. Update code that checks `is_a?(Git::Base)` or `be_a(Git::Base)`
|
|
792
|
+
in tests:
|
|
170
793
|
|
|
171
794
|
```ruby
|
|
172
795
|
# v4.x
|
|
@@ -184,20 +807,26 @@ construct a repository object.
|
|
|
184
807
|
|
|
185
808
|
#### Unsupported options raise `ArgumentError`
|
|
186
809
|
|
|
187
|
-
v5.x
|
|
188
|
-
|
|
189
|
-
`ArgumentError
|
|
190
|
-
|
|
191
|
-
|
|
810
|
+
In v5.x, only some APIs reject unknown options: `Git.clone`, `Git.ls_remote`,
|
|
811
|
+
and most `Git::Repository` methods that accept an options hash (for example,
|
|
812
|
+
`#add`) raise `ArgumentError` for option names they do not recognize. The
|
|
813
|
+
factory methods `Git.init`, `Git.open`, and `Git.bare` do not validate option
|
|
814
|
+
names in v5.x. All three reject unknown keys in v6.0.0 (see
|
|
815
|
+
[`Git.init`, `Git.open`, and `Git.bare` reject unknown options](#gitinit-gitopen-and-gitbare-reject-unknown-options)).
|
|
816
|
+
|
|
817
|
+
For APIs that validate options, names that v4.x silently ignored may raise
|
|
818
|
+
`ArgumentError` in v5.x. Check option names against the documented API when
|
|
819
|
+
upgrading, especially for calls that pass keyword options through helper
|
|
820
|
+
methods or shared option hashes.
|
|
192
821
|
|
|
193
822
|
For example, `Git.clone` supports `log:`, not `logger:`. A misspelled or
|
|
194
823
|
unsupported option that v4.x ignored must be corrected:
|
|
195
824
|
|
|
196
825
|
```ruby
|
|
197
|
-
# v4.x
|
|
826
|
+
# v4.x: silently ignored; did not configure clone logging
|
|
198
827
|
Git.clone(url, path, logger: logger)
|
|
199
828
|
|
|
200
|
-
# v5.x
|
|
829
|
+
# v5.x: use the documented option name
|
|
201
830
|
Git.clone(url, path, log: logger)
|
|
202
831
|
```
|
|
203
832
|
|
|
@@ -210,31 +839,29 @@ exposed a `#lib` method that gave access to `Git::Lib`, the gem's internal
|
|
|
210
839
|
implementation class. `Git::Lib` is removed in v5.0.0.
|
|
211
840
|
|
|
212
841
|
In v5.x, calling `#lib` on a repo object returns `self` with a deprecation
|
|
213
|
-
warning
|
|
214
|
-
`
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
is removed in v6.0.0.
|
|
842
|
+
warning, so `g.lib.some_method(args)` calls `g.some_method(args)`, but only if
|
|
843
|
+
`some_method` exists on `Git::Repository`. Methods that were unique to `Git::Lib`
|
|
844
|
+
and have no counterpart on `Git::Repository` raise `NoMethodError` immediately.
|
|
845
|
+
The `#lib` method itself is removed in v6.0.0.
|
|
218
846
|
|
|
219
|
-
Most
|
|
220
|
-
|
|
221
|
-
method.
|
|
847
|
+
Most of what `g.lib.*` exposed is available directly on the repository object
|
|
848
|
+
(`g.*`). See the tables below for every affected method.
|
|
222
849
|
|
|
223
|
-
##### Methods that work
|
|
850
|
+
##### Methods that work through the `#lib` shim (with deprecation warning)
|
|
224
851
|
|
|
225
852
|
The following v4.x `g.lib.*` call shapes are forwarded to their `Git::Repository`
|
|
226
|
-
counterpart by the `#lib
|
|
227
|
-
to the replacement shown to silence it.
|
|
853
|
+
counterpart by the `#lib` shim, which returns `self`. They emit a deprecation
|
|
854
|
+
warning; migrate to the replacement shown to silence it.
|
|
228
855
|
|
|
229
|
-
> **
|
|
856
|
+
> **Config return type change.** `g.lib.config_get(name)` returned a
|
|
230
857
|
> `String`; `g.lib.config_list` returned a `Hash`.
|
|
231
858
|
> The v5.x replacements `config_get` and `config_list` return
|
|
232
|
-
> `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>` respectively
|
|
233
|
-
> objects
|
|
859
|
+
> `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>` respectively. Those
|
|
860
|
+
> objects expose `.value` (the String), `.key`, `.scope`, and `.origin`.
|
|
234
861
|
>
|
|
235
862
|
> If you only need the String value:
|
|
236
|
-
> - `g.config_get(name)&.value`
|
|
237
|
-
> - `g.config_list.to_h { |e| [e.key, e.value] }`
|
|
863
|
+
> - `g.config_get(name)&.value` replaces `g.lib.config_get(name)`
|
|
864
|
+
> - `g.config_list.to_h { |e| [e.key, e.value] }` replaces `g.lib.config_list`
|
|
238
865
|
>
|
|
239
866
|
> If your code was using the v4.x public `g.config(name)` API (not `g.lib.*`),
|
|
240
867
|
> that deprecated bridge still returns a `String` in v5.x and continues to work
|
|
@@ -242,17 +869,17 @@ to the replacement shown to silence it.
|
|
|
242
869
|
|
|
243
870
|
| v4.x call | Replacement in v5.x |
|
|
244
871
|
|-----------|---------------------|
|
|
245
|
-
| `g.lib.config_get(name)` | `g.config_get(name)
|
|
246
|
-
| `g.lib.config_list` | `g.config_list
|
|
872
|
+
| `g.lib.config_get(name)` | `g.config_get(name)`. Returns `Git::ConfigEntryInfo`; use `.value` for the String |
|
|
873
|
+
| `g.lib.config_list` | `g.config_list`. Returns `Array<Git::ConfigEntryInfo>` |
|
|
247
874
|
| `g.lib.config_set(name, value)` | `g.config_set(name, value)` |
|
|
248
875
|
| `g.lib.git_version` | `g.git_version` |
|
|
249
|
-
| `g.lib.stash_list` | `g.stash_infos
|
|
876
|
+
| `g.lib.stash_list` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
250
877
|
| `g.lib.unmerged` | `g.unmerged` |
|
|
251
878
|
| `g.lib.change_head_branch(name)` | `g.change_head_branch(name)` |
|
|
252
879
|
| `g.lib.ls_remote(location, opts)` | `g.ls_remote(location, opts)` |
|
|
253
880
|
| `g.lib.current_branch_state` | `g.current_branch_state` |
|
|
254
881
|
|
|
255
|
-
>
|
|
882
|
+
> **`current_branch_state` return type change.** `g.lib.current_branch_state`
|
|
256
883
|
> returned a `Git::Lib::HeadState` (a mutable `Struct`). `g.current_branch_state`
|
|
257
884
|
> returns a `Git::Repository::Branching::HeadState` (an immutable `Data` object).
|
|
258
885
|
> Both expose `.state` (`:active`, `:unborn`, or `:detached`) and `.name`. If your
|
|
@@ -263,8 +890,8 @@ to the replacement shown to silence it.
|
|
|
263
890
|
##### Methods that raise `NoMethodError` in v5.x
|
|
264
891
|
|
|
265
892
|
These `Git::Lib` method names have no counterpart on `Git::Repository`, so
|
|
266
|
-
`g.lib.method_name` raises `NoMethodError` even in v5.x
|
|
267
|
-
|
|
893
|
+
`g.lib.method_name` raises `NoMethodError` even in v5.x because the `#lib` shim
|
|
894
|
+
has nothing to forward them to. Update call sites directly:
|
|
268
895
|
|
|
269
896
|
| v4.x call | Replacement in v5.x |
|
|
270
897
|
|-----------|---------------------|
|
|
@@ -282,8 +909,8 @@ shim cannot forward them). Update call sites directly:
|
|
|
282
909
|
|
|
283
910
|
##### Internal plumbing methods (no replacement)
|
|
284
911
|
|
|
285
|
-
The following methods were
|
|
286
|
-
helpers with no plausible external use
|
|
912
|
+
The following methods were public on `Git::Lib` in name only. They are internal
|
|
913
|
+
helpers with no plausible external use and have no replacement in v5.0.0:
|
|
287
914
|
|
|
288
915
|
- `assert_args_are_not_options`
|
|
289
916
|
- `assert_valid_opts`
|
|
@@ -307,15 +934,15 @@ filter log output by path when combined with `#between` or other revision range
|
|
|
307
934
|
options. This relied on ambiguous `git log` argument handling and was not the
|
|
308
935
|
intended API for path filtering.
|
|
309
936
|
|
|
310
|
-
In v5.x, `Git::Log#object`
|
|
311
|
-
`#
|
|
312
|
-
|
|
937
|
+
In v5.x, `Git::Log#object` is a revision expression. When both `#object` and
|
|
938
|
+
`#between` are specified, `#between` takes precedence. Code that used `#object`
|
|
939
|
+
to limit commits to a path should use `#path` instead.
|
|
313
940
|
|
|
314
941
|
```ruby
|
|
315
|
-
# v4.x
|
|
942
|
+
# v4.x: ambiguous; could appear to filter commits touching this path
|
|
316
943
|
git.log(500).object('cookbooks/mycookbook').between('1.0.0', 'HEAD').execute
|
|
317
944
|
|
|
318
|
-
# v5.x
|
|
945
|
+
# v5.x: use #path for path filtering
|
|
319
946
|
git.log(500).path('cookbooks/mycookbook').between('1.0.0', 'HEAD').execute
|
|
320
947
|
|
|
321
948
|
# #object remains appropriate for revision expressions
|
|
@@ -339,19 +966,25 @@ result.is_a?(Git::CommandLine::Result)
|
|
|
339
966
|
```
|
|
340
967
|
|
|
341
968
|
This change is only relevant if your code references `Git::CommandLineResult`
|
|
342
|
-
by name (typically in type checks or documentation). Code that
|
|
343
|
-
|
|
969
|
+
by name (typically in type checks or documentation). Code that uses the result
|
|
970
|
+
object returned by git commands is unaffected.
|
|
344
971
|
|
|
345
972
|
---
|
|
346
973
|
|
|
347
974
|
### Deprecated methods
|
|
348
975
|
|
|
349
976
|
The following methods are available in v5.x with deprecation warnings and are
|
|
350
|
-
removed in v6.0.0. Migrate to the replacement shown to silence the warnings.
|
|
977
|
+
removed in v6.0.0. Migrate to the replacement shown to silence the warnings. The
|
|
978
|
+
[Removed APIs](#removed-apis) table under "Upgrading to v6.x" indexes these entries.
|
|
979
|
+
|
|
980
|
+
`Git::GitExecuteError` is not listed here because v6.0.0 keeps it. It has warned since
|
|
981
|
+
v2.0.0 and still warns in v6.0.0; see [`Git::GitExecuteError`
|
|
982
|
+
deprecated](#gitgitexecuteerror-deprecated) under "Upgrading to v6.x" for the
|
|
983
|
+
replacement.
|
|
351
984
|
|
|
352
985
|
#### Facade method renames
|
|
353
986
|
|
|
354
|
-
|
|
987
|
+
v5.x renamed five methods to follow the project's `noun_verb` naming convention.
|
|
355
988
|
The old names continue to work but emit deprecation warnings:
|
|
356
989
|
|
|
357
990
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
@@ -364,11 +997,11 @@ The old names continue to work but emit deprecation warnings:
|
|
|
364
997
|
|
|
365
998
|
#### `Git::Repository` method renames
|
|
366
999
|
|
|
367
|
-
|
|
368
|
-
|
|
1000
|
+
v5.x renamed seven more `Git::Repository` methods. The old names continue to work
|
|
1001
|
+
but emit deprecation warnings. Each old name returns exactly what its
|
|
369
1002
|
replacement returns, except `branches_all`.
|
|
370
1003
|
|
|
371
|
-
> **Return shape change
|
|
1004
|
+
> **Return shape change.** `g.branches_all` returns an `Array` of 4-element
|
|
372
1005
|
> tuples `[refname, current, worktree, symref]`, where `refname` is the short
|
|
373
1006
|
> form (`main` or `remotes/origin/main`), `current` and `worktree` are booleans,
|
|
374
1007
|
> and `symref` is the symbolic-ref target or `nil`. `g.branch_list` returns
|
|
@@ -386,14 +1019,36 @@ replacement returns, except `branches_all`.
|
|
|
386
1019
|
|
|
387
1020
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
388
1021
|
|-----------------------------------------------------|-------------|
|
|
389
|
-
| `g.empty?` | `g.no_commits
|
|
390
|
-
| `g.reset_hard` | `g.reset(nil, hard: true)
|
|
391
|
-
| `g.reset_hard(commitish)` | `g.reset(commitish, hard: true)
|
|
392
|
-
| `g.conflicts { \|file, yours, theirs\| ... }` | `g.each_conflict { \|file, yours, theirs\| ... }
|
|
1022
|
+
| `g.empty?` | `g.no_commits?`. `true` when the repository has no commits |
|
|
1023
|
+
| `g.reset_hard` | `g.reset(nil, hard: true)`. `reset` takes the commitish positionally, so pass `nil` before the options; returns git's stdout, as `reset_hard` did |
|
|
1024
|
+
| `g.reset_hard(commitish)` | `g.reset(commitish, hard: true)`. `reset_hard` ignored any `:hard` option passed to it and always reset with `--hard` |
|
|
1025
|
+
| `g.conflicts { \|file, yours, theirs\| ... }` | `g.each_conflict { \|file, yours, theirs\| ... }`. Same block arguments; returns the unmerged paths |
|
|
393
1026
|
| `g.is_local_branch?(name)` | `g.local_branch?(name)` |
|
|
394
1027
|
| `g.is_remote_branch?(name)` | `g.remote_branch?(name)` |
|
|
395
1028
|
| `g.is_branch?(name)` | `g.branch?(name)` |
|
|
396
|
-
| `g.branches_all` | `g.branch_list
|
|
1029
|
+
| `g.branches_all` | `g.branch_list`. Returns `Array<Git::BranchInfo>`; see the return shape change above |
|
|
1030
|
+
|
|
1031
|
+
#### `Git::Repository` alias renames
|
|
1032
|
+
|
|
1033
|
+
Eight `Git::Repository` methods have a second, older name carried over from v4.x.
|
|
1034
|
+
Releases before v5.7.0 kept the older names as aliases with no warning. From
|
|
1035
|
+
v5.7.0 on, each old name emits a deprecation warning. Each old name takes the
|
|
1036
|
+
same arguments and returns exactly what its replacement returns.
|
|
1037
|
+
|
|
1038
|
+
> **`diff_name_status`:** a `:path` option emits its own deprecation warning
|
|
1039
|
+
> after the method-name warning. Pass `:path_limiter` instead, as described
|
|
1040
|
+
> under [`Git::Repository` option renames](#gitrepository-option-renames) below.
|
|
1041
|
+
|
|
1042
|
+
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1043
|
+
|-----------------------------------------------------|-------------|
|
|
1044
|
+
| `g.object_contents(object)` | `g.cat_file_contents(object)` |
|
|
1045
|
+
| `g.object_size(object)` | `g.cat_file_size(object)` |
|
|
1046
|
+
| `g.object_type(object)` | `g.cat_file_type(object)` |
|
|
1047
|
+
| `g.commit_data(object)` | `g.cat_file_commit(object)` |
|
|
1048
|
+
| `g.tag_data(object)` | `g.cat_file_tag(object)` |
|
|
1049
|
+
| `g.revparse(objectish)` | `g.rev_parse(objectish)` |
|
|
1050
|
+
| `g.namerev(commit_ish)` | `g.name_rev(commit_ish)` |
|
|
1051
|
+
| `g.diff_name_status(from, to, opts)` | `g.diff_path_status(from, to, opts)` |
|
|
397
1052
|
|
|
398
1053
|
#### `Git::Repository` option renames
|
|
399
1054
|
|
|
@@ -401,7 +1056,7 @@ Five methods accept a v4.x option or positional argument under its old name.
|
|
|
401
1056
|
The old form still works in v5.x but emits a deprecation warning and is
|
|
402
1057
|
translated to the v5.x form shown below.
|
|
403
1058
|
|
|
404
|
-
> **`clean
|
|
1059
|
+
> **`clean`.** `force: 2` runs `git clean -ff`, which also removes untracked
|
|
405
1060
|
> nested git repositories. A `false` or `nil` value for `:ff` or `:force_force`
|
|
406
1061
|
> still warns and has no effect; a value other than `true`, `false`, or `nil`
|
|
407
1062
|
> raises `ArgumentError`. When the deprecated key is `true` and a valid
|
|
@@ -410,11 +1065,11 @@ translated to the v5.x form shown below.
|
|
|
410
1065
|
> unchanged and still raises `ArgumentError`; the deprecated key does not mask
|
|
411
1066
|
> it.
|
|
412
1067
|
|
|
413
|
-
> **`diff_path_status
|
|
1068
|
+
> **`diff_path_status`.** `:path_limiter` accepts the same values as `:path`
|
|
414
1069
|
> (a `String`, a `Pathname`, or an `Array` of them). When both keys are given,
|
|
415
1070
|
> `:path_limiter` wins and no warning is emitted.
|
|
416
1071
|
|
|
417
|
-
> **`set_working` and `set_index
|
|
1072
|
+
> **`set_working` and `set_index`.** `must_exist:` defaults to `true`. When
|
|
418
1073
|
> both the positional argument and `must_exist:` are given, they are OR'ed so
|
|
419
1074
|
> the more restrictive value wins.
|
|
420
1075
|
|
|
@@ -423,39 +1078,39 @@ translated to the v5.x form shown below.
|
|
|
423
1078
|
| `g.clean(ff: true)` | `g.clean(force: 2)` |
|
|
424
1079
|
| `g.clean(force_force: true)` | `g.clean(force: 2)` |
|
|
425
1080
|
| `g.diff_path_status(ref1, ref2, path: p)` | `g.diff_path_status(ref1, ref2, path_limiter: p)` |
|
|
426
|
-
| `g.commit(message, add_all: true)` | `g.commit(message, all: true)
|
|
1081
|
+
| `g.commit(message, add_all: true)` | `g.commit(message, all: true)`. Runs `git commit -a` |
|
|
427
1082
|
| `g.set_working(dir, check)` | `g.set_working(dir, must_exist: check)` |
|
|
428
1083
|
| `g.set_index(file, check)` | `g.set_index(file, must_exist: check)` |
|
|
429
1084
|
|
|
430
1085
|
#### v4.x-style configuration methods
|
|
431
1086
|
|
|
432
1087
|
The v4.x `config` and `global_config` methods accepted varying argument shapes
|
|
433
|
-
to read, write, or list configuration.
|
|
1088
|
+
to read, write, or list configuration. v5.x replaces them with separate,
|
|
434
1089
|
purpose-named methods. The same applies to the module-level
|
|
435
|
-
`Git.global_config`,
|
|
1090
|
+
`Git.global_config`, whose replacements are `Git.config_get`, `Git.config_set`,
|
|
436
1091
|
and `Git.config_list` called with `global: true`.
|
|
437
1092
|
|
|
438
|
-
> **Return type change
|
|
1093
|
+
> **Return type change.** The v4.x `g.config(name)` and `Git.global_config(name)`
|
|
439
1094
|
> returned a `String`; `g.config` and `Git.global_config` returned a `Hash`. The
|
|
440
1095
|
> v5.x replacements `config_get` and `config_list` return `Git::ConfigEntryInfo`
|
|
441
1096
|
> (or `nil` when the key is not set) and `Array<Git::ConfigEntryInfo>`
|
|
442
1097
|
> respectively. Use `.value` to get the String value:
|
|
443
|
-
> - `g.config_get(name)&.value`
|
|
444
|
-
> - `g.config_list.to_h { |e| [e.key, e.value] }`
|
|
1098
|
+
> - `g.config_get(name)&.value` returns a String or nil
|
|
1099
|
+
> - `g.config_list.to_h { |e| [e.key, e.value] }` returns a Hash of key to value
|
|
445
1100
|
>
|
|
446
1101
|
> The setters `g.config(name, value)` and `Git.global_config(name, value)`
|
|
447
1102
|
> returned the raw command result; `config_set` returns `nil`.
|
|
448
1103
|
|
|
449
1104
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
450
1105
|
|-----------------------------------------------------|-------------|
|
|
451
|
-
| `g.config(name)` | `g.config_get(name)
|
|
452
|
-
| `g.config` | `g.config_list
|
|
1106
|
+
| `g.config(name)` | `g.config_get(name)`. Returns `Git::ConfigEntryInfo`; use `.value` for the String |
|
|
1107
|
+
| `g.config` | `g.config_list`. Returns `Array<Git::ConfigEntryInfo>` |
|
|
453
1108
|
| `g.config(name, value)` | `g.config_set(name, value)` |
|
|
454
1109
|
| `g.global_config(name)` | `g.config_get(name, global: true)` |
|
|
455
1110
|
| `g.global_config` | `g.config_list(global: true)` |
|
|
456
1111
|
| `g.global_config(name, value)` | `g.config_set(name, value, global: true)` |
|
|
457
|
-
| `Git.global_config(name)` | `Git.config_get(name, global: true)
|
|
458
|
-
| `Git.global_config` | `Git.config_list(global: true)
|
|
1112
|
+
| `Git.global_config(name)` | `Git.config_get(name, global: true)`. Returns `Git::ConfigEntryInfo` or `nil`; use `.value` for the String |
|
|
1113
|
+
| `Git.global_config` | `Git.config_list(global: true)`. Returns `Array<Git::ConfigEntryInfo>` |
|
|
459
1114
|
| `Git.global_config(name, value)` | `Git.config_set(name, value, global: true)` |
|
|
460
1115
|
|
|
461
1116
|
#### `Git` module mixin deprecations
|
|
@@ -489,7 +1144,7 @@ legacy type that is deprecated:
|
|
|
489
1144
|
- `Git.binary_version` is replaced by `Git.git_version`, which keeps the
|
|
490
1145
|
optional binary path argument.
|
|
491
1146
|
|
|
492
|
-
> **Return type change
|
|
1147
|
+
> **Return type change.** `Git.binary_version` returned an `Array<Integer>` of
|
|
493
1148
|
> `[major, minor, patch]`. `Git.git_version` returns a `Git::Version`, which
|
|
494
1149
|
> supports comparison and exposes `major`, `minor`, and `patch`.
|
|
495
1150
|
> `Git.git_version.to_a` reproduces the legacy array. The return value of
|
|
@@ -499,19 +1154,20 @@ legacy type that is deprecated:
|
|
|
499
1154
|
|-----------------------------------------------------|-------------|
|
|
500
1155
|
| `Git.ls_remote(nil)` | `Git.ls_remote` or `Git.ls_remote('.')` |
|
|
501
1156
|
| `Git.ls_remote(nil, opts)` | `Git.ls_remote('.', opts)` |
|
|
502
|
-
| `Git.binary_version` | `Git.git_version
|
|
1157
|
+
| `Git.binary_version` | `Git.git_version`. Returns `Git::Version`; use `.to_a` for the `[major, minor, patch]` Array |
|
|
503
1158
|
| `Git.binary_version(binary_path)` | `Git.git_version(binary_path)` |
|
|
504
1159
|
|
|
505
1160
|
#### `Git::Author` deprecated
|
|
506
1161
|
|
|
507
|
-
Starting in v5.3.0, methods that return author, committer, or tagger data
|
|
508
|
-
`Git::
|
|
509
|
-
`Git::
|
|
510
|
-
`Git::
|
|
1162
|
+
Starting in v5.3.0, the methods that return author, committer, or tagger data
|
|
1163
|
+
return an immutable `Git::AuthorInfo` value object instead of the mutable
|
|
1164
|
+
`Git::Author`. Those methods are `Git::Object::Commit#author`,
|
|
1165
|
+
`Git::Object::Commit#committer`, `Git::Object::Tag#tagger`, and
|
|
1166
|
+
`Git::TagInfo#tagger`.
|
|
511
1167
|
|
|
512
1168
|
`Git::AuthorInfo` exposes the same `name`, `email`, and `date` readers, so code
|
|
513
1169
|
that only reads these attributes needs no changes. Code that mutated a
|
|
514
|
-
`Git::Author`
|
|
1170
|
+
`Git::Author` through `name=`, `email=`, or `date=` has to change.
|
|
515
1171
|
`Git::AuthorInfo` is frozen, and `#with` returns a modified copy rather than
|
|
516
1172
|
updating in place (e.g. `info = info.with(name: 'New Name')`).
|
|
517
1173
|
|
|
@@ -530,7 +1186,7 @@ in the repository, so `g.branch('feature').stashes` and `g.branch('main').stashe
|
|
|
530
1186
|
return the same entries. Call `Git::Repository#stash_infos` instead; it is the
|
|
531
1187
|
query `Git::Branch#stashes` was already running.
|
|
532
1188
|
|
|
533
|
-
> **Return type change
|
|
1189
|
+
> **Return type change.** `Git::Branch#stashes` returns a `Git::Stashes`
|
|
534
1190
|
> collection of `Git::Stash` objects. `g.stash_infos` returns an array of
|
|
535
1191
|
> `Git::StashInfo` values. Both are newest first, so indexes carry over unchanged.
|
|
536
1192
|
> `Git::Stash#message` strips the `WIP on <branch>:` or `On <branch>:` prefix;
|
|
@@ -546,15 +1202,15 @@ its methods.
|
|
|
546
1202
|
|
|
547
1203
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
548
1204
|
|-----------------------------------------------------|-------------|
|
|
549
|
-
| `g.branch(name).stashes` | `g.stash_infos
|
|
1205
|
+
| `g.branch(name).stashes` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
550
1206
|
| `g.branch(name).stashes.each { \|s\| puts s.message }` | `g.stash_infos.each { \|info\| puts info.message }` |
|
|
551
|
-
| `g.branch(name).stashes.all` (`[index, message]` pairs, oldest first) | `g.stash_infos.reverse
|
|
1207
|
+
| `g.branch(name).stashes.all` (`[index, message]` pairs, oldest first) | `g.stash_infos.reverse`. See the ordering note in [Legacy stash API deprecated](#legacy-stash-api-deprecated) |
|
|
552
1208
|
| `g.branch(name).stashes.size` | `g.stash_infos.size` |
|
|
553
1209
|
| `g.branch(name).stashes[i].message` (`0` = newest, `i` coerced with `to_i`) | `g.stash_infos[i.to_i].message` |
|
|
554
1210
|
| `g.branch(name).stashes.save(message)` | `g.stash_push(message: message)` |
|
|
555
1211
|
| `g.branch(name).stashes.apply` | `g.stash_apply` |
|
|
556
1212
|
| `g.branch(name).stashes.apply(i)` (`0` = newest) | `g.stash_apply(i)` |
|
|
557
|
-
| `g.branch(name).stashes.clear` | `g.stash_clear
|
|
1213
|
+
| `g.branch(name).stashes.clear` | `g.stash_clear`. Returns git's stdout (normally `""`, which is truthy) where `Git::Stashes#clear` returned `nil` |
|
|
558
1214
|
|
|
559
1215
|
#### Legacy stash API deprecated
|
|
560
1216
|
|
|
@@ -571,14 +1227,14 @@ The legacy methods and classes are deprecated and removed in v6.0.0:
|
|
|
571
1227
|
`Git::Repository#stash_list`, `Git::Stash`, and `Git::Stashes`. Constructing a
|
|
572
1228
|
`Git::Stash` or `Git::Stashes` emits one warning per object.
|
|
573
1229
|
|
|
574
|
-
> **Ordering flip
|
|
1230
|
+
> **Ordering flip.** `g.stashes_all` returns entries oldest first with a
|
|
575
1231
|
> sequential index of its own (`0` is the oldest). `g.stash_infos` returns entries
|
|
576
|
-
>
|
|
1232
|
+
> newest first, the order `git stash list` uses, and `Git::StashInfo#index` is
|
|
577
1233
|
> git's own `stash@{N}` number (`0` is the newest). `g.stashes_all.first` is
|
|
578
1234
|
> `g.stash_infos.last`. Code that reads an entry by position must reverse the
|
|
579
1235
|
> array or the index.
|
|
580
1236
|
|
|
581
|
-
> **Message difference
|
|
1237
|
+
> **Message difference.** `g.stashes_all` strips the `WIP on <branch>:` or
|
|
582
1238
|
> `On <branch>:` prefix from each message. `Git::StashInfo#message` keeps the full
|
|
583
1239
|
> message git stores, and `Git::StashInfo#branch` holds the branch name. A stash
|
|
584
1240
|
> created from a detached HEAD has the branch `"(no branch)"`, the label git writes
|
|
@@ -591,32 +1247,38 @@ new `Git::StashInfo`, or `nil` when there were no local changes, so a truthiness
|
|
|
591
1247
|
check such as `if g.stash_push(message: 'WIP')` still works.
|
|
592
1248
|
|
|
593
1249
|
`g.stash_list` returned the `git stash list` text as a String. Build that text from
|
|
594
|
-
`g.stash_infos` if you need it. In v6.0.0
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
upgrading so the return type change
|
|
1250
|
+
`g.stash_infos` if you need it. In v6.0.0 `stash_list` returns what `stash_infos`
|
|
1251
|
+
returns (see [`stash_list` returns an Array of
|
|
1252
|
+
`Git::StashInfo`](#stash_list-returns-an-array-of-gitstashinfo)), so move String
|
|
1253
|
+
callers of `stash_list` to `stash_infos` before upgrading so the return type change
|
|
1254
|
+
cannot go unnoticed.
|
|
1255
|
+
|
|
1256
|
+
> **`stash_store` in v6.0.0.** On v5.x, `g.stash_store` returns the top entry of
|
|
1257
|
+
> the stash list after the store, which is `nil` when the list is empty. v6.0.0
|
|
1258
|
+
> changes that; see [`stash_store` raises when the stored entry is
|
|
1259
|
+
> missing](#stash_store-raises-when-the-stored-entry-is-missing).
|
|
598
1260
|
|
|
599
1261
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
600
1262
|
|-----------------------------------------------------|-------------|
|
|
601
|
-
| `g.stashes_all` | `g.stash_infos
|
|
1263
|
+
| `g.stashes_all` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
602
1264
|
| `g.stashes_all.each { \|index, message\| ... }` | `g.stash_infos.reverse_each.with_index { \|info, index\| ... info.message }` |
|
|
603
1265
|
| `g.stashes_all[i]` (`0` = oldest) | `g.stash_infos.reverse[i]` |
|
|
604
1266
|
| `g.stashes_all.last` | `g.stash_infos.first` |
|
|
605
|
-
| `g.stash_save(message)` | `g.stash_push(message: message)
|
|
1267
|
+
| `g.stash_save(message)` | `g.stash_push(message: message)`. Returns `Git::StashInfo` or `nil` |
|
|
606
1268
|
| `g.stash_list` (String) | `g.stash_infos.map { \|s\| "#{s.name}: #{s.message}" }.join("\n")` |
|
|
607
1269
|
| `Git::Stash.new(g, message)` | `info = g.stash_push(message: message)` |
|
|
608
|
-
| `Git::Stash.new(g, message, existing: true)` | `message
|
|
1270
|
+
| `Git::Stash.new(g, message, existing: true)` | `message`. `existing: true` only wrapped the String and never looked an entry up; code that needs a real entry picks one from `g.stash_infos` by index or name |
|
|
609
1271
|
| `stash.save` | `info = g.stash_push(message: message)` |
|
|
610
|
-
| `stash.saved?` | `!info.nil
|
|
611
|
-
| `stash.message` / `stash.to_s` | `info.message
|
|
1272
|
+
| `stash.saved?` | `!info.nil?`. Check the value `stash_push` returned rather than pushing again |
|
|
1273
|
+
| `stash.message` / `stash.to_s` | `info.message`. Keeps the branch prefix; see the note above |
|
|
612
1274
|
| `Git::Stashes.new(g)` | `g.stash_infos` |
|
|
613
|
-
| `stashes.all` (`[index, message]` pairs, oldest first) | `g.stash_infos.reverse
|
|
1275
|
+
| `stashes.all` (`[index, message]` pairs, oldest first) | `g.stash_infos.reverse`. See the ordering note above |
|
|
614
1276
|
| `stashes.each { \|s\| ... }` (newest first) | `g.stash_infos.each { \|info\| ... }` |
|
|
615
1277
|
| `stashes[i]` (`0` = newest, `i` coerced with `to_i`) | `g.stash_infos[i.to_i]` |
|
|
616
1278
|
| `stashes.size` | `g.stash_infos.size` |
|
|
617
1279
|
| `stashes.save(message)` | `g.stash_push(message: message)` |
|
|
618
1280
|
| `stashes.apply` / `stashes.apply(i)` | `g.stash_apply` / `g.stash_apply(i)` |
|
|
619
|
-
| `stashes.clear` | `g.stash_clear
|
|
1281
|
+
| `stashes.clear` | `g.stash_clear`. Returns git's stdout (normally `""`, which is truthy) where `Git::Stashes#clear` returned `nil` |
|
|
620
1282
|
|
|
621
1283
|
#### `Git::Repository#remotes` deprecated
|
|
622
1284
|
|
|
@@ -626,10 +1288,10 @@ one deprecation warning for itself plus one `Git::Remote` constructor warning fo
|
|
|
626
1288
|
each remote it returns (see the `Git::Remote` deprecation below), so a repository
|
|
627
1289
|
with N remotes produces N + 1 warnings per call.
|
|
628
1290
|
|
|
629
|
-
> **Return type change
|
|
1291
|
+
> **Return type change.** `remotes` returns `Array<Git::Remote>`, mutable
|
|
630
1292
|
> objects with `name`, `url`, and `fetch_opts` accessors and `fetch`, `merge`,
|
|
631
1293
|
> `branch`, and `remove` operations. `remote_list` returns
|
|
632
|
-
> `Array<Git::RemoteInfo
|
|
1294
|
+
> `Array<Git::RemoteInfo>`, immutable value objects read from the repository's
|
|
633
1295
|
> git config, with fields such as `name`, `url`, `push_url`, `fetch`, and `push`.
|
|
634
1296
|
> Because a remote may carry more than one URL or refspec, `url`, `push_url`,
|
|
635
1297
|
> `fetch`, and `push` are always frozen `Array<String>`. When a remote has more
|
|
@@ -637,27 +1299,28 @@ with N remotes produces N + 1 warnings per call.
|
|
|
637
1299
|
> the last one configured, so use `r.url.last` to reproduce that exact value.
|
|
638
1300
|
> Likewise, `Git::Remote#fetch_opts` returned only the last configured fetch
|
|
639
1301
|
> refspec, while `fetch` holds all of them. Operations that lived on
|
|
640
|
-
> `Git::Remote` are called on the repository
|
|
1302
|
+
> `Git::Remote` are called on the repository instead; the table below shows
|
|
1303
|
+
> the argument each one takes.
|
|
641
1304
|
>
|
|
642
|
-
> **Order change
|
|
1305
|
+
> **Order change.** `remotes` lists remotes in the order `git remote` prints
|
|
643
1306
|
> them, while `remote_list` keeps the order in which remotes first appear in the
|
|
644
1307
|
> config. When the legacy order matters, iterate `g.remote_names` (the same
|
|
645
1308
|
> `git remote` order) or sort `g.remote_list` explicitly.
|
|
646
1309
|
|
|
647
1310
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
648
1311
|
|-----------------------------------------------------|-------------|
|
|
649
|
-
| `g.remotes` | `g.remote_list
|
|
1312
|
+
| `g.remotes` | `g.remote_list`. Returns `Array<Git::RemoteInfo>` |
|
|
650
1313
|
| `g.remotes.map(&:name)` | `g.remote_list.map(&:name)` or `g.remote_names` |
|
|
651
|
-
| `g.remotes.map(&:to_s)` | `g.remote_list.map(&:name)
|
|
652
|
-
| `g.remotes.map(&:url)` | `g.remote_list.map { \|r\| r.url.first }
|
|
653
|
-
| `g.remotes.map(&:fetch_opts)` | `g.remote_list.map { \|r\| r.fetch.last }
|
|
654
|
-
| `g.remotes.each(&:fetch)` | `g.remote_names.each { \|name\| g.fetch(name) }
|
|
1314
|
+
| `g.remotes.map(&:to_s)` | `g.remote_list.map(&:name)`. `Git::RemoteInfo#to_s` is not the name |
|
|
1315
|
+
| `g.remotes.map(&:url)` | `g.remote_list.map { \|r\| r.url.first }`. `url` is an `Array<String>` |
|
|
1316
|
+
| `g.remotes.map(&:fetch_opts)` | `g.remote_list.map { \|r\| r.fetch.last }`. `fetch` holds every refspec |
|
|
1317
|
+
| `g.remotes.each(&:fetch)` | `g.remote_names.each { \|name\| g.fetch(name) }`. Same order as `remotes` |
|
|
655
1318
|
| `remote.fetch` | `g.fetch(remote.name)` |
|
|
656
|
-
| `remote.fetch(opts)` | `g.fetch(remote.name, opts)
|
|
1319
|
+
| `remote.fetch(opts)` | `g.fetch(remote.name, opts)`. Same options hash |
|
|
657
1320
|
| `remote.merge` | `g.merge("#{remote.name}/#{g.current_branch}")` |
|
|
658
1321
|
| `remote.merge(branch)` | `g.merge("#{remote.name}/#{branch}")` |
|
|
659
|
-
| `remote.branch` | `g.branch_list("#{remote.name}/#{g.current_branch}").
|
|
660
|
-
| `remote.branch(name)` | `g.branch_list("#{remote.name}/#{name}").
|
|
1322
|
+
| `remote.branch` | `g.branch_list("#{remote.name}/#{g.current_branch}").find(&:remote?)`. Returns a `Git::BranchInfo` |
|
|
1323
|
+
| `remote.branch(name)` | `g.branch_list("#{remote.name}/#{name}").find(&:remote?)`. Returns a `Git::BranchInfo` |
|
|
661
1324
|
| `remote.remove` | `g.remote_remove(remote.name)` |
|
|
662
1325
|
|
|
663
1326
|
#### `Git::Remote` deprecated
|
|
@@ -665,15 +1328,15 @@ with N remotes produces N + 1 warnings per call.
|
|
|
665
1328
|
`Git::Remote`, `Git::Repository#remote`, and `Git::Repository#config_remote` are
|
|
666
1329
|
deprecated and are removed in v6.0.0. Read a remote's configuration through
|
|
667
1330
|
`Git::Repository#remote_list`, which returns one `Git::RemoteInfo` value object per
|
|
668
|
-
remote
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
`
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
> **Return type changes
|
|
1331
|
+
remote; the table below shows the replacement for each operation. Return values
|
|
1332
|
+
are unchanged. Constructing a `Git::Remote` directly emits one deprecation warning,
|
|
1333
|
+
and so does calling `g.config_remote`. Calling `g.remote` emits two: one for
|
|
1334
|
+
`Git::Repository#remote` and one for the `Git::Remote` it constructs. Likewise
|
|
1335
|
+
`g.remotes` emits one warning for itself plus one per `Git::Remote` it returns
|
|
1336
|
+
(N + 1 for N remotes). The extra warnings from `g.remote` and `g.remotes` are
|
|
1337
|
+
expected, not a bug.
|
|
1338
|
+
|
|
1339
|
+
> **Return type changes.** `Git::RemoteInfo#url` and `Git::RemoteInfo#fetch` are
|
|
677
1340
|
> frozen `Array<String>` because a remote may carry more than one URL or fetch
|
|
678
1341
|
> refspec. The legacy `Git::Remote#url` and `Git::Remote#fetch_opts` returned only
|
|
679
1342
|
> the last configured value, so `r.url.last` and `r.fetch.last` reproduce them
|
|
@@ -686,26 +1349,27 @@ warnings from `g.remote` and `g.remotes` are expected, not a bug.
|
|
|
686
1349
|
> Code that reads custom keys should filter `g.config_list` instead (see the
|
|
687
1350
|
> table); that yields the same `Hash{String => String}` as `config_remote`.
|
|
688
1351
|
> `Git::Remote#branch` returned a `Git::Branch`. Its replacement,
|
|
689
|
-
> `g.branch_list("#{name}/#{branch}").
|
|
690
|
-
> object, or `nil` when the remote-tracking branch does
|
|
1352
|
+
> `g.branch_list("#{name}/#{branch}").find(&:remote?)`, returns a
|
|
1353
|
+
> `Git::BranchInfo` value object, or `nil` when the remote-tracking branch does
|
|
1354
|
+
> not exist.
|
|
691
1355
|
|
|
692
1356
|
In the table, `name` is the remote name (`g.remote` defaults it to `'origin'`).
|
|
693
1357
|
|
|
694
1358
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
695
1359
|
|-----------------------------------------------------|-------------|
|
|
696
|
-
| `g.remote` | `g.remote_list.find { \|r\| r.name == 'origin' }
|
|
697
|
-
| `g.remote(name)` | `g.remote_list.find { \|r\| r.name == name }
|
|
698
|
-
| `g.config_remote(name)` for `url`, `fetch`, and the other modeled fields | `g.remote_list.find { \|r\| r.name == name }
|
|
699
|
-
| `g.config_remote(name)` for every key, including custom ones | `g.config_list.select { \|e\| e.key.start_with?("remote.#{name}.") }.to_h { \|e\| [e.key.delete_prefix("remote.#{name}."), e.value] }
|
|
1360
|
+
| `g.remote` | `g.remote_list.find { \|r\| r.name == 'origin' }`. Returns a `Git::RemoteInfo`; the deprecated call emits two warnings |
|
|
1361
|
+
| `g.remote(name)` | `g.remote_list.find { \|r\| r.name == name }`. Returns a `Git::RemoteInfo`; the deprecated call emits two warnings |
|
|
1362
|
+
| `g.config_remote(name)` for `url`, `fetch`, and the other modeled fields | `g.remote_list.find { \|r\| r.name == name }`. A `Git::RemoteInfo`, not a `Hash` |
|
|
1363
|
+
| `g.config_remote(name)` for every key, including custom ones | `g.config_list.select { \|e\| e.key.start_with?("remote.#{name}.") }.to_h { \|e\| [e.key.delete_prefix("remote.#{name}."), e.value] }`. The same `Hash{String => String}` |
|
|
700
1364
|
| `remote.name`, `remote.to_s` | `g.remote_list.find { \|r\| r.name == name }.name` or `g.remote_names` |
|
|
701
|
-
| `remote.url` | `g.remote_list.find { \|r\| r.name == name }.url
|
|
702
|
-
| `remote.fetch_opts` | `g.remote_list.find { \|r\| r.name == name }.fetch
|
|
1365
|
+
| `remote.url` | `g.remote_list.find { \|r\| r.name == name }.url`. `Array<String>`; `.first` for the single-URL case |
|
|
1366
|
+
| `remote.fetch_opts` | `g.remote_list.find { \|r\| r.name == name }.fetch`. `Array<String>` of refspecs |
|
|
703
1367
|
| `remote.fetch` | `g.fetch(name)` |
|
|
704
|
-
| `remote.fetch(opts)` | `g.fetch(name, opts)
|
|
1368
|
+
| `remote.fetch(opts)` | `g.fetch(name, opts)`. Same option keys |
|
|
705
1369
|
| `remote.merge` | `g.merge("#{name}/#{g.current_branch}")` |
|
|
706
1370
|
| `remote.merge(branch)` | `g.merge("#{name}/#{branch}")` |
|
|
707
|
-
| `remote.branch` | `g.branch_list("#{name}/#{g.current_branch}").
|
|
708
|
-
| `remote.branch(branch)` | `g.branch_list("#{name}/#{branch}").
|
|
1371
|
+
| `remote.branch` | `g.branch_list("#{name}/#{g.current_branch}").find(&:remote?)`. Returns a `Git::BranchInfo` |
|
|
1372
|
+
| `remote.branch(branch)` | `g.branch_list("#{name}/#{branch}").find(&:remote?)`. Returns a `Git::BranchInfo` |
|
|
709
1373
|
| `remote.remove` | `g.remote_remove(name)` |
|
|
710
1374
|
|
|
711
1375
|
#### `Git::Commands::CatFile::Raw` `allow_unknown_type` option deprecated
|
|
@@ -735,12 +1399,14 @@ that constructs the command class directly is affected.
|
|
|
735
1399
|
data through `Git::Repository#branch_list`, which returns one `Git::BranchInfo`
|
|
736
1400
|
value object per local and remote-tracking branch, and call the repository-level
|
|
737
1401
|
operations (`checkout`, `branch_new`, `branch_delete`, `merge`, `merge_into`,
|
|
738
|
-
`in_branch`, and so on) with the branch name.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1402
|
+
`in_branch`, and so on) with the branch name. For a remote-tracking branch the
|
|
1403
|
+
argument differs by operation; the table below shows the form each one takes.
|
|
1404
|
+
Calling `g.branch` or `g.branches`, constructing a `Git::Branches`, and calling
|
|
1405
|
+
any operation on a `Git::Branch` each emit a deprecation warning; their return
|
|
1406
|
+
values are unchanged. The `full`, `name`, `remote`, `to_s`, and `to_a` readers
|
|
1407
|
+
on `Git::Branch` do not warn.
|
|
1408
|
+
|
|
1409
|
+
> **Return shape change.** `Git::Branch` exposes `full` (`main` or
|
|
744
1410
|
> `remotes/origin/main`), `name`, and `remote` (a `Git::Remote`, or `nil`).
|
|
745
1411
|
> `Git::BranchInfo` exposes `refname` (always the full ref: `refs/heads/main` or
|
|
746
1412
|
> `refs/remotes/origin/main`), `short_name` (`main` for both), `remote_name` (a
|
|
@@ -751,7 +1417,7 @@ emit a deprecation warning; their return values are unchanged. The `full`,
|
|
|
751
1417
|
> `'origin/main'` matches the remote-tracking branch. The `remotes/origin/main`
|
|
752
1418
|
> and `refs/...` forms that `g.branches[...]` accepted match nothing.
|
|
753
1419
|
>
|
|
754
|
-
> **`checkout` no longer creates the branch
|
|
1420
|
+
> **`checkout` no longer creates the branch.** `g.branch('x').checkout` created
|
|
755
1421
|
> `x` when it did not exist, ignoring any error from that attempt, and then
|
|
756
1422
|
> checked it out. `g.checkout('x')` does not create a missing local branch,
|
|
757
1423
|
> with one exception that is git's own: when exactly one remote has a branch
|
|
@@ -797,33 +1463,33 @@ can resolve a local branch of that name and is only used where git expects it
|
|
|
797
1463
|
|
|
798
1464
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
799
1465
|
|-----------------------------------------------------|-------------|
|
|
800
|
-
| `g.branch(name)` | `g.branch_list(name).first` for a local branch, or `g.branch_list("#{remote}/#{name}").find(&:remote?)` for a remote-tracking one
|
|
801
|
-
| `g.branch` | `g.branch_list(g.current_branch).first
|
|
802
|
-
| `g.branches` | `g.branch_list
|
|
1466
|
+
| `g.branch(name)` | `g.branch_list(name).first` for a local branch, or `g.branch_list("#{remote}/#{name}").find(&:remote?)` for a remote-tracking one. A `Git::BranchInfo`, or `nil` when the branch does not exist; the `remotes/` and `refs/` forms match nothing |
|
|
1467
|
+
| `g.branch` | `g.branch_list(g.current_branch).first`. `nil` when HEAD is detached or unborn; use `g.current_branch_state` there |
|
|
1468
|
+
| `g.branches` | `g.branch_list`. Returns `Array<Git::BranchInfo>` |
|
|
803
1469
|
| `g.branches[name]` | `g.branch_list(name).first`, or `g.branch_list("#{remote}/#{name}").find(&:remote?)` for a remote-tracking branch |
|
|
804
1470
|
| `g.branches.local` | `g.branch_list.reject(&:remote?)` |
|
|
805
1471
|
| `g.branches.remote` | `g.branch_list.select(&:remote?)` |
|
|
806
1472
|
| `g.branches.size` | `g.branch_list.size` |
|
|
807
1473
|
| `g.branches.each { \|b\| ... }` | `g.branch_list.each { \|info\| ... }` |
|
|
808
|
-
| `g.branches.to_s` | `g.branch_list.map { \|i\| "#{i.current? ? '* ' : ' '}#{i.refname}\n" }.join
|
|
809
|
-
| `b.full`, `b.to_s` | `info.refname
|
|
1474
|
+
| `g.branches.to_s` | `g.branch_list.map { \|i\| "#{i.current? ? '* ' : ' '}#{i.refname}\n" }.join`. Full refs, not `remotes/...` |
|
|
1475
|
+
| `b.full`, `b.to_s` | `info.refname`. `refs/remotes/origin/main` rather than `remotes/origin/main` |
|
|
810
1476
|
| `b.to_a` | `[info.refname]` |
|
|
811
1477
|
| `b.name` | `info.short_name` |
|
|
812
|
-
| `b.remote` | `info.remote_name
|
|
813
|
-
| `b.gcommit` | `g.gcommit(name)
|
|
814
|
-
| `b.checkout` | `g.checkout(name)
|
|
815
|
-
| `b.create` | `g.branch_new(name)
|
|
1478
|
+
| `b.remote` | `info.remote_name`. A `String`, or `nil` for a local branch |
|
|
1479
|
+
| `b.gcommit` | `g.gcommit(name)`. Pass `info.refname` for a remote-tracking branch |
|
|
1480
|
+
| `b.checkout` | `g.checkout(name)`. Does not create the branch (see above); pass `info.refname` for a remote-tracking branch |
|
|
1481
|
+
| `b.create` | `g.branch_new(name)`. Raises when the branch already exists |
|
|
816
1482
|
| `b.delete` (local) | `g.branch_delete(name)` |
|
|
817
1483
|
| `b.delete` (remote-tracking) | `g.branch_delete("#{remote}/#{name}", remotes: true)` |
|
|
818
1484
|
| `b.current` | `g.current_branch == name` |
|
|
819
1485
|
| `b.contains?(commit)` | `!g.branch_contains(commit, name).empty?` |
|
|
820
1486
|
| `b.merge` | `g.merge(name)` |
|
|
821
|
-
| `b.merge(branch, message)` | `g.merge_into(name, branch, message)
|
|
1487
|
+
| `b.merge(branch, message)` | `g.merge_into(name, branch, message)`. Local `b` only; see the differences above |
|
|
822
1488
|
| `b.update_ref(commit)` (local) | `g.update_ref(name, commit)` |
|
|
823
1489
|
| `b.update_ref(commit)` (remote-tracking) | `g.update_ref("remotes/#{remote}/#{name}", commit)` |
|
|
824
|
-
| `b.archive(file, opts)` | `g.archive(name, file, opts)
|
|
825
|
-
| `b.in_branch(message) { ... }` | `g.in_branch(name, message) { ... }
|
|
826
|
-
| `b.stashes` | `g.stash_infos
|
|
1490
|
+
| `b.archive(file, opts)` | `g.archive(name, file, opts)`. Pass `info.refname` for a remote-tracking branch |
|
|
1491
|
+
| `b.in_branch(message) { ... }` | `g.in_branch(name, message) { ... }`. Local `b` only; see the differences above |
|
|
1492
|
+
| `b.stashes` | `g.stash_infos`. See [`Git::Branch#stashes` deprecated](#gitbranchstashes-deprecated) |
|
|
827
1493
|
|
|
828
1494
|
#### `Git::Object::Tag` deprecated
|
|
829
1495
|
|
|
@@ -842,7 +1508,7 @@ for the `g.tag_add` it calls; `g.add_tag(name, d: true)` emits three, adding the
|
|
|
842
1508
|
`:d`/`:delete` warning described below. The readers on a `Git::Object::Tag` do not
|
|
843
1509
|
warn.
|
|
844
1510
|
|
|
845
|
-
> **Return shape change
|
|
1511
|
+
> **Return shape change.** `Git::Object::Tag` exposes `name`, `sha`, `objectish`,
|
|
846
1512
|
> `annotated?`, `message`, and `tagger`. `Git::TagInfo` exposes `name`, `oid`,
|
|
847
1513
|
> `target_oid`, `objecttype`, `annotated?`, `lightweight?`, `message`, and
|
|
848
1514
|
> `tagger`. `name` and `annotated?` are unchanged. `tagger` keeps the same `name`
|
|
@@ -860,18 +1526,23 @@ warn.
|
|
|
860
1526
|
> which kind (`tag` for an annotated tag, or the target's own type such as
|
|
861
1527
|
> `commit` or `blob` for a lightweight one).
|
|
862
1528
|
>
|
|
863
|
-
> **Missing tags
|
|
1529
|
+
> **Missing tags.** `g.tag(name)` raises `Git::UnexpectedResultError` when no tag
|
|
864
1530
|
> has that name. `g.tag_list(name).first` returns `nil`.
|
|
865
1531
|
>
|
|
866
|
-
>
|
|
1532
|
+
> **`tag_create` in v6.0.0.** On v5.x, `g.tag_create` returns `nil` when the tag it
|
|
1533
|
+
> has just created is missing from the tag list. v6.0.0 raises instead; see
|
|
1534
|
+
> [`tag_create` raises when the created tag is
|
|
1535
|
+
> missing](#tag_create-raises-when-the-created-tag-is-missing).
|
|
1536
|
+
>
|
|
1537
|
+
> **Deleting through `tag_add`.** `g.tag_add(name, d: true)`, which was already
|
|
867
1538
|
> deprecated, deletes the tag and emits a second warning pointing at
|
|
868
1539
|
> `g.tag_delete`. `g.tag_create` rejects `:d` and `:delete` with `ArgumentError`.
|
|
869
1540
|
>
|
|
870
|
-
> **Extra positional arguments
|
|
1541
|
+
> **Extra positional arguments.** `g.tag_add(name, target, extra)` ignores
|
|
871
1542
|
> `extra` and tags `target`. `g.tag_create` raises `ArgumentError` when more than
|
|
872
1543
|
> one positional argument follows the name.
|
|
873
1544
|
>
|
|
874
|
-
> **Object identity
|
|
1545
|
+
> **Object identity.** Every `Git::Object::Tag` resolves its tag to an object ID
|
|
875
1546
|
> when it is constructed and runs `size`, `contents`, `grep`, `diff`, `log`, and
|
|
876
1547
|
> `archive` against that ID, so moving or deleting the tag afterwards does not
|
|
877
1548
|
> redirect an existing object. `Git::Object::Tag.new(g, sha, name)` uses the
|
|
@@ -890,26 +1561,26 @@ In the table, `name` is the tag name, `t` is a `Git::Object::Tag`, `info` is the
|
|
|
890
1561
|
|
|
891
1562
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
892
1563
|
|-----------------------------------------------------|-------------|
|
|
893
|
-
| `g.tag(name)` | `g.tag_list(name).first
|
|
894
|
-
| `g.tags` | `g.tag_list
|
|
1564
|
+
| `g.tag(name)` | `g.tag_list(name).first`. A `Git::TagInfo`, or `nil` when the tag does not exist |
|
|
1565
|
+
| `g.tags` | `g.tag_list`. Returns `Array<Git::TagInfo>` |
|
|
895
1566
|
| `g.tags.map(&:name)` | `g.tag_list.map(&:name)` |
|
|
896
|
-
| `g.tag_add(name, opts)` | `g.tag_create(name, opts)
|
|
1567
|
+
| `g.tag_add(name, opts)` | `g.tag_create(name, opts)`. Returns a `Git::TagInfo` |
|
|
897
1568
|
| `g.tag_add(name, target, opts)` | `g.tag_create(name, target, opts)` |
|
|
898
1569
|
| `g.tag_add(name, d: true)` | `g.tag_delete(name)` |
|
|
899
|
-
| `g.add_tag(name, opts)`, `g.add_tag(name, target, opts)` | `g.tag_create(name, ...)
|
|
900
|
-
| `g.add_tag(name, d: true)` | `g.tag_delete(name)
|
|
1570
|
+
| `g.add_tag(name, opts)`, `g.add_tag(name, target, opts)` | `g.tag_create(name, ...)`. Its warning names `g.tag_add`, which is deprecated too; go straight to `g.tag_create` |
|
|
1571
|
+
| `g.add_tag(name, d: true)` | `g.tag_delete(name)`. `g.tag_create` rejects `:d`; see the deletion note above |
|
|
901
1572
|
| `Git::Object::Tag.new(g, name)` | `g.tag_list(name).first` |
|
|
902
|
-
| `Git::Object::Tag.new(g, sha, name)` | `g.tag_list(name).first
|
|
903
|
-
| `Git::Object.new(g, name, nil, true)` | `g.tag_list(name).first
|
|
1573
|
+
| `Git::Object::Tag.new(g, sha, name)` | `g.tag_list(name).first`. Reads the ref rather than `sha`; use `sha` as `id` for the operations below, or read the object with `g.cat_file_tag(sha)`; see the object identity note above |
|
|
1574
|
+
| `Git::Object.new(g, name, nil, true)` | `g.tag_list(name).first`. Its warning names `Git::Object::Tag.new`, which is deprecated too |
|
|
904
1575
|
| `t.name` | `info.name` |
|
|
905
|
-
| `t.sha`, `t.objectish`, `t.to_s` | `info.oid \|\| info.target_oid
|
|
1576
|
+
| `t.sha`, `t.objectish`, `t.to_s` | `info.oid \|\| info.target_oid`. See the return shape change above |
|
|
906
1577
|
| `t.annotated?` | `info.annotated?` |
|
|
907
|
-
| `t.message` | `info.message
|
|
908
|
-
| `t.tagger` | `info.tagger
|
|
1578
|
+
| `t.message` | `info.message`. `nil` rather than `""` for an annotated tag with an empty message |
|
|
1579
|
+
| `t.tagger` | `info.tagger`. `date` keeps the recorded UTC offset; see the return shape change above |
|
|
909
1580
|
| `t.tag?` | not needed; every `Git::TagInfo` is a tag |
|
|
910
|
-
| `t.size` | `g.cat_file_size(id)
|
|
1581
|
+
| `t.size` | `g.cat_file_size(id)`. `id` rather than `name` keeps this and the operations below on the object `t` pinned; see the object identity note above |
|
|
911
1582
|
| `t.contents` | `g.cat_file_contents(id)` |
|
|
912
|
-
| `t.contents { \|file\| ... }` | `g.cat_file_contents(id) { \|file\| ... }
|
|
1583
|
+
| `t.contents { \|file\| ... }` | `g.cat_file_contents(id) { \|file\| ... }`. Streams to a temporary file instead of buffering the object |
|
|
913
1584
|
| `t.contents_array` | `g.cat_file_contents(id).split("\n")` |
|
|
914
1585
|
| `t.grep(string, path, opts)` | `g.grep(string, path, opts.merge(object: id))` |
|
|
915
1586
|
| `t.diff(other)` | `g.diff(id, other)` |
|
|
@@ -919,7 +1590,7 @@ In the table, `name` is the tag name, `t` is a `Git::Object::Tag`, `info` is the
|
|
|
919
1590
|
#### `Git::Status` deprecated
|
|
920
1591
|
|
|
921
1592
|
Starting in v5.4.0, `Git::Status`, `Git::Status::StatusFile`, and
|
|
922
|
-
`Git::Repository#status` are deprecated and
|
|
1593
|
+
`Git::Repository#status` are deprecated and are removed in v6.0.0. Read the
|
|
923
1594
|
index and working tree state through `Git::Repository#status_info`, which
|
|
924
1595
|
returns an immutable `Git::StatusInfo` holding one `Git::StatusFileInfo` per
|
|
925
1596
|
path that `git status --porcelain=v2` reports. Calling `g.status` emits one
|
|
@@ -964,7 +1635,7 @@ reference, so `blob` is gone; fetch the object through the repository instead.
|
|
|
964
1635
|
`stage` is gone too: an unmerged entry carries its stage 1, 2, and 3 modes and
|
|
965
1636
|
SHAs in `unmerged_stages`, and every other entry is at stage 0.
|
|
966
1637
|
|
|
967
|
-
> **Field renames
|
|
1638
|
+
> **Field renames.** The legacy mode and SHA readers were named for the wrong
|
|
968
1639
|
> sides. `sha_index` and `mode_index` held the working-tree side of the diff:
|
|
969
1640
|
> the index blob when the working tree matched the index, and an all-zero SHA
|
|
970
1641
|
> when it did not. `sha_repo` and `mode_repo` held the side git compared the
|
|
@@ -982,12 +1653,12 @@ In the table, `g` is a `Git::Repository`, `status` is the `Git::Status` from
|
|
|
982
1653
|
|
|
983
1654
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
984
1655
|
|-----------------------------------------------------|-------------|
|
|
985
|
-
| `g.status` | `g.status_info
|
|
1656
|
+
| `g.status` | `g.status_info`. Returns a `Git::StatusInfo` |
|
|
986
1657
|
| `Git::Status.new(g)` | `g.status_info` |
|
|
987
|
-
| `status.changed`, `status.added`, `status.deleted`, `status.untracked` | same names on `g.status_info
|
|
1658
|
+
| `status.changed`, `status.added`, `status.deleted`, `status.untracked` | same names on `g.status_info`. Now `Hash{String => Git::StatusFileInfo}` keyed by path |
|
|
988
1659
|
| `status.changed?(path)`, `status.added?(path)`, `status.deleted?(path)`, `status.untracked?(path)` | same names on `g.status_info` |
|
|
989
|
-
| `status[path]` | `g.status_info[path]
|
|
990
|
-
| `status.each { \|file\| ... }` | `g.status_info.files.each { \|info\| ... }
|
|
1660
|
+
| `status[path]` | `g.status_info[path]`. A `Git::StatusFileInfo`, or `nil`; `nil` for a clean tracked path, which `status[path]` reported (see above) |
|
|
1661
|
+
| `status.each { \|file\| ... }` | `g.status_info.files.each { \|info\| ... }`. Does not yield clean tracked paths (see above) |
|
|
991
1662
|
| `status.pretty` | no replacement; format `g.status_info.files` yourself |
|
|
992
1663
|
| `file.path` | `info.path` |
|
|
993
1664
|
| `file.type` | `info.index_status` and `info.worktree_status`, or the `info.changed?`, `info.added?`, and `info.deleted?` predicates |
|
|
@@ -997,8 +1668,8 @@ In the table, `g` is a `Git::Repository`, `status` is the `Git::Status` from
|
|
|
997
1668
|
| `file.mode_repo` | `info.mode_head`, or `info.mode_index` in a repository with no commits |
|
|
998
1669
|
| `file.sha_index` | `info.sha_index` for the staged blob; `info.worktree_status` says whether the working tree differs from it |
|
|
999
1670
|
| `file.mode_index` | `info.mode_worktree` |
|
|
1000
|
-
| `file.blob` | `g.object(info.sha_index)` when `info.sha_index` is set and not all zeros
|
|
1001
|
-
| `file.blob(:repo)` | `g.object(info.sha_head)` when `info.sha_head` is set and not all zeros
|
|
1671
|
+
| `file.blob` | `g.object(info.sha_index)` when `info.sha_index` is set and not all zeros. It is `nil` for untracked, ignored, and unmerged entries and all zeros when the path is not in the index; legacy `blob` returned `nil` without a lookup when no SHA was available and fell back to `sha_repo` when `sha_index` was `nil`. For an unmerged entry read a stage instead: `g.object(info.unmerged_stages[2][:sha])` |
|
|
1672
|
+
| `file.blob(:repo)` | `g.object(info.sha_head)` when `info.sha_head` is set and not all zeros. It is `nil` for untracked, ignored, and unmerged entries and all zeros when the path is not in HEAD |
|
|
1002
1673
|
|
|
1003
1674
|
#### `Git::Worktree` and `Git::Worktrees` deprecated
|
|
1004
1675
|
|
|
@@ -1009,7 +1680,7 @@ and are removed in v6.0.0. Read worktree data through
|
|
|
1009
1680
|
object per worktree, and call the repository-level operations (`worktree_add`,
|
|
1010
1681
|
`worktree_remove`, `worktree_move`, `worktree_lock`, `worktree_unlock`,
|
|
1011
1682
|
`worktree_repair`, and `worktree_prune`) with the worktree path or its
|
|
1012
|
-
`Git::WorktreeInfo`. Return values are unchanged. Calling `g.worktree`,
|
|
1683
|
+
`Git::WorktreeInfo`. Return values are unchanged on v5.x. Calling `g.worktree`,
|
|
1013
1684
|
`g.worktrees`, or `g.worktrees_all`, constructing a `Git::Worktrees`, and calling
|
|
1014
1685
|
`gcommit`, `add`, or `remove` on a `Git::Worktree` each emit a deprecation
|
|
1015
1686
|
warning; the `dir`, `full`, `to_s`, and `to_a` readers on `Git::Worktree` do not.
|
|
@@ -1017,7 +1688,7 @@ warning; the `dir`, `full`, `to_s`, and `to_a` readers on `Git::Worktree` do not
|
|
|
1017
1688
|
it constructs, and `g.worktree(dir).add` emits one for `g.worktree` and one for
|
|
1018
1689
|
`add`.
|
|
1019
1690
|
|
|
1020
|
-
> **Return shape change
|
|
1691
|
+
> **Return shape change.** `worktrees_all` returns `[directory, sha]` pairs and
|
|
1021
1692
|
> omits the main worktree of a bare repository, which has no checked-out commit.
|
|
1022
1693
|
> `worktree_list` returns `Git::WorktreeInfo` objects with `path`, `head`,
|
|
1023
1694
|
> `branch` (the full refname, such as `refs/heads/main`, or `nil` when detached
|
|
@@ -1026,42 +1697,54 @@ it constructs, and `g.worktree(dir).add` emits one for `g.worktree` and one for
|
|
|
1026
1697
|
> `branch` set to `nil`. `Git::WorktreeInfo#to_s` is the path, so an entry can be
|
|
1027
1698
|
> passed to any method that takes a worktree path.
|
|
1028
1699
|
>
|
|
1029
|
-
> **`gcommit` return type
|
|
1700
|
+
> **`gcommit` return type.** `Git::Worktree#gcommit` returned a
|
|
1030
1701
|
> `Git::Object::Commit` for a worktree obtained from `g.worktree(dir)` and a raw
|
|
1031
1702
|
> SHA `String` for one obtained from `g.worktrees`. `info.head` is always a
|
|
1032
1703
|
> `String` (or `nil` for a bare main worktree); call `g.gcommit(info.head)` for
|
|
1033
1704
|
> the commit object.
|
|
1034
1705
|
>
|
|
1035
|
-
> **`full` and `to_s
|
|
1706
|
+
> **`full` and `to_s`.** `Git::Worktree#full` and `#to_s` append the commitish
|
|
1036
1707
|
> given at construction to the path, so entries from `g.worktrees` read
|
|
1037
1708
|
> `"/path/to/wt <sha>"`. `Git::WorktreeInfo#to_s` is the path alone.
|
|
1709
|
+
>
|
|
1710
|
+
> **`worktree_add` in v6.0.0.** On v5.x, `worktree_add` returns the
|
|
1711
|
+
> `git worktree add` output (`"HEAD is now at …"`). In v6.0.0 it returns the new
|
|
1712
|
+
> `Git::WorktreeInfo` instead (see [`worktree_add` returns `Git::WorktreeInfo` and
|
|
1713
|
+
> raises when the worktree is
|
|
1714
|
+
> missing](#worktree_add-returns-gitworktreeinfo-and-raises-when-the-worktree-is-missing)).
|
|
1715
|
+
> To get the entry today, look it up after the add:
|
|
1716
|
+
> `g.worktree_list.find { |w| File.identical?(w.path, dir) }`. Compare with
|
|
1717
|
+
> `File.identical?`, not string equality: git stores worktree paths with
|
|
1718
|
+
> symlinks resolved, so `/tmp/...` on macOS is listed as `/private/tmp/...`,
|
|
1719
|
+
> and on case-insensitive filesystems the listed casing may differ from `dir`.
|
|
1038
1720
|
|
|
1039
1721
|
In the table, `dir` is the worktree path, `wt` is a `Git::Worktree`, and `info`
|
|
1040
1722
|
is the `Git::WorktreeInfo` that replaces it.
|
|
1041
1723
|
|
|
1042
1724
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1043
1725
|
|-----------------------------------------------------|-------------|
|
|
1044
|
-
| `g.worktrees_all` | `g.worktree_list.map { \|w\| [w.path, w.head] }
|
|
1045
|
-
| `g.worktrees` | `g.worktree_list
|
|
1046
|
-
| `g.worktrees[dir]` | `g.worktree_list.find { \|w\| w.path == dir }
|
|
1726
|
+
| `g.worktrees_all` | `g.worktree_list.map { \|w\| [w.path, w.head] }`. Includes a bare main worktree as `[path, nil]`; add `.reject(&:bare?)` before `map` to omit it as `worktrees_all` did |
|
|
1727
|
+
| `g.worktrees` | `g.worktree_list`. Returns `Array<Git::WorktreeInfo>`; the deprecated call emits two warnings |
|
|
1728
|
+
| `g.worktrees[dir]` | `g.worktree_list.find { \|w\| w.path == dir }`. `nil` when not found; `dir` is the path as git reports it (absolute, with symlinks resolved), as before |
|
|
1047
1729
|
| `g.worktrees.size` | `g.worktree_list.size` |
|
|
1048
1730
|
| `g.worktrees.each { \|wt\| ... }` | `g.worktree_list.each { \|info\| ... }` |
|
|
1049
1731
|
| `g.worktrees.to_s` | `g.worktree_list.map { \|w\| "#{w.path} #{w.head}\n" }.join` |
|
|
1050
1732
|
| `g.worktrees.prune` | `g.worktree_prune` |
|
|
1051
1733
|
| `g.worktree(dir).add` | `g.worktree_add(dir)` |
|
|
1052
1734
|
| `g.worktree(dir, commitish).add` | `g.worktree_add(dir, commitish)` |
|
|
1053
|
-
| `g.worktree(dir).remove` | `g.worktree_remove(dir)`
|
|
1054
|
-
| `wt.gcommit` | `info.head
|
|
1735
|
+
| `g.worktree(dir).remove` | `g.worktree_remove(dir)` or `g.worktree_remove(info)` |
|
|
1736
|
+
| `wt.gcommit` | `info.head`. Always a `String`, or `nil` for a bare main worktree; `g.gcommit(info.head)` for the commit object |
|
|
1055
1737
|
| `wt.dir` | `info.path` |
|
|
1056
|
-
| `wt.full`, `wt.to_s` | `info.path`
|
|
1738
|
+
| `wt.full`, `wt.to_s` | `info.path` or `"#{info.path} #{info.head}"` for the descriptor that entries from `g.worktrees` produced |
|
|
1057
1739
|
| `wt.to_a` | `[info.path]` |
|
|
1058
1740
|
|
|
1059
1741
|
#### `Git.clone` option renames
|
|
1060
1742
|
|
|
1061
|
-
Three `Git.clone` options were renamed in v5.x. The v4.x names still work
|
|
1062
|
-
deprecated option present on a call emits its own deprecation
|
|
1063
|
-
that uses two of them warns twice. Each value is passed
|
|
1064
|
-
replacement option, except that `:path` is dropped when `:chdir`
|
|
1743
|
+
Three `Git.clone` options were renamed in v5.x. The v4.x names still work in
|
|
1744
|
+
v5.x. Each deprecated option present on a call emits its own deprecation
|
|
1745
|
+
warning, so a call that uses two of them warns twice. Each value is passed
|
|
1746
|
+
through to the replacement option, except that `:path` is dropped when `:chdir`
|
|
1747
|
+
is also given.
|
|
1065
1748
|
|
|
1066
1749
|
> **Precedence and value notes:**
|
|
1067
1750
|
> - `:path` and `:chdir` both run `git clone` from inside the given directory.
|
|
@@ -1074,7 +1757,7 @@ replacement option, except that `:path` is dropped when `:chdir` is also given.
|
|
|
1074
1757
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1075
1758
|
|-----------------------------------------------------|-------------|
|
|
1076
1759
|
| `Git.clone(url, dir, path: p)` | `Git.clone(url, dir, chdir: p)` |
|
|
1077
|
-
| `Git.clone(url, dir, recursive: true)` | `Git.clone(url, dir, recurse_submodules: true)`
|
|
1760
|
+
| `Git.clone(url, dir, recursive: true)` | `Git.clone(url, dir, recurse_submodules: true)` or a pathspec `String` or `Array<String>` for a subset of submodules |
|
|
1078
1761
|
| `Git.clone(url, dir, remote: name)` | `Git.clone(url, dir, origin: name)` |
|
|
1079
1762
|
|
|
1080
1763
|
#### `Git::Log` Enumerable interface deprecated
|
|
@@ -1091,7 +1774,7 @@ builder (`map`, `select`, `count`, `to_a`, `include?`, and so on) goes through t
|
|
|
1091
1774
|
deprecated `each` and emits its warning. Move those calls to the result as well,
|
|
1092
1775
|
not only the six named methods.
|
|
1093
1776
|
|
|
1094
|
-
> **Snapshot results
|
|
1777
|
+
> **Snapshot results.** `execute` returns a snapshot. The builder re-runs
|
|
1095
1778
|
> `git log` only when a query method (`since`, `max_count`, and so on) has been
|
|
1096
1779
|
> called since the last run, even with the same value as before, so calling
|
|
1097
1780
|
> `execute` twice on an untouched builder returns equal results without a second
|
|
@@ -1104,7 +1787,7 @@ In the table, `g` is a `Git::Repository`.
|
|
|
1104
1787
|
|-----------------------------------------------------|-------------|
|
|
1105
1788
|
| `g.log.each { \|c\| ... }` | `g.log.execute.each { \|c\| ... }` |
|
|
1106
1789
|
| `g.log.size` | `g.log.execute.size` |
|
|
1107
|
-
| `g.log.to_s` | `g.log.execute.to_s
|
|
1790
|
+
| `g.log.to_s` | `g.log.execute.to_s`. Commits joined with newlines, as before |
|
|
1108
1791
|
| `g.log.first`, `g.log.last` | `g.log.execute.first`, `g.log.execute.last` |
|
|
1109
1792
|
| `g.log[i]`, `g.log[range]` | `g.log.execute[i]`, `g.log.execute[range]` |
|
|
1110
1793
|
| any other `Enumerable` method on the log (`map`, `select`, `count`, `to_a`, `include?`, ...) | the same method on `g.log.execute` |
|
|
@@ -1136,40 +1819,4 @@ observable in the result. Delete the option from the call.
|
|
|
1136
1819
|
|--------------------------------------------------------------------|-------------|
|
|
1137
1820
|
| `Git.export(url, dir, remote: name)` | `Git.export(url, dir)` |
|
|
1138
1821
|
|
|
1139
|
-
#### Context helper blocks that declare no parameter deprecated
|
|
1140
|
-
|
|
1141
|
-
`Git::Repository#with_index`, `#with_temp_index`, `#with_working`, and
|
|
1142
|
-
`#with_temp_working` yield `self` in v5.x, so a block could ignore the yielded
|
|
1143
|
-
value and call methods on the receiver. Calling one of these helpers with a block
|
|
1144
|
-
that declares no positional parameter (`do ... end`, `{ }`, `{ || }`, or a block
|
|
1145
|
-
with only keyword or block parameters) now emits a deprecation warning. The
|
|
1146
|
-
behavior is otherwise unchanged: the helpers still yield `self`, and a call with
|
|
1147
|
-
no block still raises `LocalJumpError`.
|
|
1148
|
-
|
|
1149
|
-
In v6.0.0 these helpers yield a separate repository bound to the other index or
|
|
1150
|
-
working tree instead of rebinding the receiver, and they raise `ArgumentError` for
|
|
1151
|
-
a block that declares no positional parameter. A call with no block also raises
|
|
1152
|
-
`ArgumentError` in v6.0.0 instead of `LocalJumpError`. Declare a block parameter
|
|
1153
|
-
and call methods on it. The parameter is required even when the block never uses
|
|
1154
|
-
the repository, for example a `with_temp_working` block that only writes files
|
|
1155
|
-
(`do |_scratch|`). Blocks that already declare a positional parameter (`|repo|`,
|
|
1156
|
-
`|_|`, `|repo = nil|`, `|*args|`, or a symbol-to-proc such as `&:write_tree`) do
|
|
1157
|
-
not warn. Both versions read the block's parameter list rather than its arity, so
|
|
1158
|
-
the v5.x warning and the v6.0.0 error agree on every block form.
|
|
1159
|
-
|
|
1160
|
-
The warning detects only the block's parameter list. Adding an unused parameter
|
|
1161
|
-
(`|_|`) silences it but does not fix a block that still calls methods on the outer
|
|
1162
|
-
repository; that block does not warn and acts on the wrong repository in v6.0.0,
|
|
1163
|
-
so review those blocks by hand.
|
|
1164
|
-
|
|
1165
|
-
| Deprecated call (works in v5.x, raises in v6.0.0) | Replacement |
|
|
1166
|
-
|---------------------------------------------------|-------------|
|
|
1167
|
-
| `g.with_index(path) { g.read_tree('HEAD') }` | `g.with_index(path) { \|r\| r.read_tree('HEAD') }` |
|
|
1168
|
-
| `g.with_temp_index { g.read_tree('HEAD') }` | `g.with_temp_index { \|r\| r.read_tree('HEAD') }` |
|
|
1169
|
-
| `g.with_working(dir) { g.add('.') }` | `g.with_working(dir) { \|r\| r.add('.') }` |
|
|
1170
|
-
| `g.with_temp_working { g.add('.') }` | `g.with_temp_working { \|r\| r.add('.') }` |
|
|
1171
|
-
|
|
1172
|
-
`chdir` is not part of this deprecation. It yields the directory path in both
|
|
1173
|
-
versions.
|
|
1174
|
-
|
|
1175
1822
|
---
|