git 5.7.1 → 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 -42
- data/CONTRIBUTING.md +44 -31
- data/README.md +138 -100
- data/UPGRADING.md +864 -259
- 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 +1 -1
- data/lib/git/encoding_utils.rb +25 -0
- data/lib/git/errors.rb +24 -18
- 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 -72
- data/lib/git/repository/merging.rb +32 -54
- data/lib/git/repository/object_operations.rb +120 -497
- 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 +30 -125
- 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 +24 -18
- 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)
|
|
@@ -36,24 +57,628 @@ to update your code when upgrading from the preceding major version.
|
|
|
36
57
|
- [`Git::Log` Enumerable interface deprecated](#gitlog-enumerable-interface-deprecated)
|
|
37
58
|
- [`Git::Object::Commit#set_commit` deprecated](#gitobjectcommitset_commit-deprecated)
|
|
38
59
|
- [`Git.export` `:remote` option deprecated](#gitexport-remote-option-deprecated)
|
|
39
|
-
- [Context helper blocks that declare no parameter deprecated](#context-helper-blocks-that-declare-no-parameter-deprecated)
|
|
40
60
|
|
|
41
|
-
## Upgrading to v6.
|
|
42
|
-
|
|
43
|
-
v6.0.0 is not yet released. This section will be completed when it ships.
|
|
61
|
+
## Upgrading to v6.x
|
|
44
62
|
|
|
45
63
|
v6.0.0 removes the APIs deprecated during v5.x under the project's
|
|
46
|
-
[deprecation policy](README.md#deprecation-policy)
|
|
47
|
-
|
|
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.
|
|
48
217
|
|
|
49
|
-
|
|
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
|
|
50
225
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
```
|
|
57
682
|
|
|
58
683
|
---
|
|
59
684
|
|
|
@@ -61,25 +686,24 @@ To prepare:
|
|
|
61
686
|
|
|
62
687
|
### Overview
|
|
63
688
|
|
|
64
|
-
v5.0.0
|
|
65
|
-
for
|
|
66
|
-
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.
|
|
67
691
|
|
|
68
692
|
The new architecture introduces a layered design (`Git::Commands`,
|
|
69
|
-
`Git::Repository`, and associated parsers). Compatibility shims
|
|
70
|
-
forwarding methods that map old call patterns to the new API
|
|
71
|
-
|
|
72
|
-
|
|
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.
|
|
73
697
|
|
|
74
|
-
Hard breaks are limited to
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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.
|
|
78
702
|
|
|
79
|
-
|
|
80
|
-
|
|
703
|
+
To suppress or configure deprecation warnings, see the [Deprecations](README.md#deprecations)
|
|
704
|
+
section of the README.
|
|
81
705
|
|
|
82
|
-
|
|
706
|
+
Changes at a glance:
|
|
83
707
|
|
|
84
708
|
| Change | Type | Impact | Action required |
|
|
85
709
|
|--------|------|--------|-----------------|
|
|
@@ -96,59 +720,57 @@ For information on how to suppress or configure deprecation warnings, see the
|
|
|
96
720
|
|
|
97
721
|
#### `Git::Base` removed
|
|
98
722
|
|
|
99
|
-
`Git::Base
|
|
100
|
-
|
|
101
|
-
`Git::Repository`, which
|
|
102
|
-
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.
|
|
103
726
|
|
|
104
|
-
|
|
727
|
+
Code that must be updated:
|
|
105
728
|
|
|
106
729
|
```ruby
|
|
107
|
-
# v4.x
|
|
730
|
+
# v4.x: explicit Git::Base reference (raises NameError in v5.x)
|
|
108
731
|
repo = Git::Base.new(working_directory: '/path/to/repo')
|
|
109
732
|
|
|
110
|
-
# v5.x
|
|
733
|
+
# v5.x: use the entry-point methods; do not construct Git::Repository directly
|
|
111
734
|
repo = Git.open('/path/to/repo')
|
|
112
735
|
```
|
|
113
736
|
|
|
114
737
|
```ruby
|
|
115
|
-
# v4.x
|
|
738
|
+
# v4.x: type-checking against Git::Base (raises NameError in v5.x because Git::Base is removed)
|
|
116
739
|
raise unless repo.is_a?(Git::Base)
|
|
117
740
|
|
|
118
|
-
# v5.x
|
|
741
|
+
# v5.x: check against Git::Repository
|
|
119
742
|
raise unless repo.is_a?(Git::Repository)
|
|
120
743
|
```
|
|
121
744
|
|
|
122
745
|
```ruby
|
|
123
|
-
# v4.x
|
|
746
|
+
# v4.x: requiring the internal file (raises LoadError in v5.x)
|
|
124
747
|
require 'git/base'
|
|
125
748
|
|
|
126
|
-
# v5.x
|
|
749
|
+
# v5.x: the public entry point is git itself; no internal require needed
|
|
127
750
|
require 'git'
|
|
128
751
|
```
|
|
129
752
|
|
|
130
|
-
**
|
|
131
|
-
`Git::Base` did. Code that
|
|
132
|
-
|
|
133
|
-
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.
|
|
134
756
|
|
|
135
|
-
**Monkeypatching `Git::Base` is deprecated
|
|
757
|
+
**Monkeypatching `Git::Base` is deprecated.** v5.x includes a temporary
|
|
136
758
|
compatibility shim for applications that define instance methods on `Git::Base`.
|
|
137
|
-
|
|
138
|
-
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.
|
|
139
761
|
|
|
140
762
|
Move custom repository helpers to an application-owned extension module and
|
|
141
763
|
include or prepend that module into `Git::Repository` during application setup:
|
|
142
764
|
|
|
143
765
|
```ruby
|
|
144
|
-
# Deprecated in v5.x and
|
|
766
|
+
# Deprecated in v5.x and removed in v6.0.0
|
|
145
767
|
module Git::Base
|
|
146
768
|
def worktree_clean?
|
|
147
769
|
status.changed.empty?
|
|
148
770
|
end
|
|
149
771
|
end
|
|
150
772
|
|
|
151
|
-
# v5.x
|
|
773
|
+
# v5.x: keep the extension in application-owned code
|
|
152
774
|
module MyAppGitRepositoryExtensions
|
|
153
775
|
def worktree_clean?
|
|
154
776
|
status.changed.empty?
|
|
@@ -165,9 +787,9 @@ Git::Repository.include(MyAppGitRepositoryExtensions)
|
|
|
165
787
|
`Git.open`, `Git.clone`, `Git.init`, and `Git.bare` now return
|
|
166
788
|
`Git::Repository` instead of `Git::Base`.
|
|
167
789
|
|
|
168
|
-
For most callers this is transparent
|
|
169
|
-
methods.
|
|
170
|
-
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:
|
|
171
793
|
|
|
172
794
|
```ruby
|
|
173
795
|
# v4.x
|
|
@@ -185,20 +807,26 @@ construct a repository object.
|
|
|
185
807
|
|
|
186
808
|
#### Unsupported options raise `ArgumentError`
|
|
187
809
|
|
|
188
|
-
v5.x
|
|
189
|
-
|
|
190
|
-
`ArgumentError
|
|
191
|
-
|
|
192
|
-
|
|
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.
|
|
193
821
|
|
|
194
822
|
For example, `Git.clone` supports `log:`, not `logger:`. A misspelled or
|
|
195
823
|
unsupported option that v4.x ignored must be corrected:
|
|
196
824
|
|
|
197
825
|
```ruby
|
|
198
|
-
# v4.x
|
|
826
|
+
# v4.x: silently ignored; did not configure clone logging
|
|
199
827
|
Git.clone(url, path, logger: logger)
|
|
200
828
|
|
|
201
|
-
# v5.x
|
|
829
|
+
# v5.x: use the documented option name
|
|
202
830
|
Git.clone(url, path, log: logger)
|
|
203
831
|
```
|
|
204
832
|
|
|
@@ -211,31 +839,29 @@ exposed a `#lib` method that gave access to `Git::Lib`, the gem's internal
|
|
|
211
839
|
implementation class. `Git::Lib` is removed in v5.0.0.
|
|
212
840
|
|
|
213
841
|
In v5.x, calling `#lib` on a repo object returns `self` with a deprecation
|
|
214
|
-
warning
|
|
215
|
-
`
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
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.
|
|
219
846
|
|
|
220
|
-
Most
|
|
221
|
-
|
|
222
|
-
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.
|
|
223
849
|
|
|
224
|
-
##### Methods that work
|
|
850
|
+
##### Methods that work through the `#lib` shim (with deprecation warning)
|
|
225
851
|
|
|
226
852
|
The following v4.x `g.lib.*` call shapes are forwarded to their `Git::Repository`
|
|
227
|
-
counterpart by the `#lib
|
|
228
|
-
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.
|
|
229
855
|
|
|
230
|
-
> **
|
|
856
|
+
> **Config return type change.** `g.lib.config_get(name)` returned a
|
|
231
857
|
> `String`; `g.lib.config_list` returned a `Hash`.
|
|
232
858
|
> The v5.x replacements `config_get` and `config_list` return
|
|
233
|
-
> `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>` respectively
|
|
234
|
-
> objects
|
|
859
|
+
> `Git::ConfigEntryInfo` and `Array<Git::ConfigEntryInfo>` respectively. Those
|
|
860
|
+
> objects expose `.value` (the String), `.key`, `.scope`, and `.origin`.
|
|
235
861
|
>
|
|
236
862
|
> If you only need the String value:
|
|
237
|
-
> - `g.config_get(name)&.value`
|
|
238
|
-
> - `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`
|
|
239
865
|
>
|
|
240
866
|
> If your code was using the v4.x public `g.config(name)` API (not `g.lib.*`),
|
|
241
867
|
> that deprecated bridge still returns a `String` in v5.x and continues to work
|
|
@@ -243,17 +869,17 @@ to the replacement shown to silence it.
|
|
|
243
869
|
|
|
244
870
|
| v4.x call | Replacement in v5.x |
|
|
245
871
|
|-----------|---------------------|
|
|
246
|
-
| `g.lib.config_get(name)` | `g.config_get(name)
|
|
247
|
-
| `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>` |
|
|
248
874
|
| `g.lib.config_set(name, value)` | `g.config_set(name, value)` |
|
|
249
875
|
| `g.lib.git_version` | `g.git_version` |
|
|
250
|
-
| `g.lib.stash_list` | `g.stash_infos
|
|
876
|
+
| `g.lib.stash_list` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
251
877
|
| `g.lib.unmerged` | `g.unmerged` |
|
|
252
878
|
| `g.lib.change_head_branch(name)` | `g.change_head_branch(name)` |
|
|
253
879
|
| `g.lib.ls_remote(location, opts)` | `g.ls_remote(location, opts)` |
|
|
254
880
|
| `g.lib.current_branch_state` | `g.current_branch_state` |
|
|
255
881
|
|
|
256
|
-
>
|
|
882
|
+
> **`current_branch_state` return type change.** `g.lib.current_branch_state`
|
|
257
883
|
> returned a `Git::Lib::HeadState` (a mutable `Struct`). `g.current_branch_state`
|
|
258
884
|
> returns a `Git::Repository::Branching::HeadState` (an immutable `Data` object).
|
|
259
885
|
> Both expose `.state` (`:active`, `:unborn`, or `:detached`) and `.name`. If your
|
|
@@ -264,8 +890,8 @@ to the replacement shown to silence it.
|
|
|
264
890
|
##### Methods that raise `NoMethodError` in v5.x
|
|
265
891
|
|
|
266
892
|
These `Git::Lib` method names have no counterpart on `Git::Repository`, so
|
|
267
|
-
`g.lib.method_name` raises `NoMethodError` even in v5.x
|
|
268
|
-
|
|
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:
|
|
269
895
|
|
|
270
896
|
| v4.x call | Replacement in v5.x |
|
|
271
897
|
|-----------|---------------------|
|
|
@@ -283,8 +909,8 @@ shim cannot forward them). Update call sites directly:
|
|
|
283
909
|
|
|
284
910
|
##### Internal plumbing methods (no replacement)
|
|
285
911
|
|
|
286
|
-
The following methods were
|
|
287
|
-
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:
|
|
288
914
|
|
|
289
915
|
- `assert_args_are_not_options`
|
|
290
916
|
- `assert_valid_opts`
|
|
@@ -308,15 +934,15 @@ filter log output by path when combined with `#between` or other revision range
|
|
|
308
934
|
options. This relied on ambiguous `git log` argument handling and was not the
|
|
309
935
|
intended API for path filtering.
|
|
310
936
|
|
|
311
|
-
In v5.x, `Git::Log#object`
|
|
312
|
-
`#
|
|
313
|
-
|
|
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.
|
|
314
940
|
|
|
315
941
|
```ruby
|
|
316
|
-
# v4.x
|
|
942
|
+
# v4.x: ambiguous; could appear to filter commits touching this path
|
|
317
943
|
git.log(500).object('cookbooks/mycookbook').between('1.0.0', 'HEAD').execute
|
|
318
944
|
|
|
319
|
-
# v5.x
|
|
945
|
+
# v5.x: use #path for path filtering
|
|
320
946
|
git.log(500).path('cookbooks/mycookbook').between('1.0.0', 'HEAD').execute
|
|
321
947
|
|
|
322
948
|
# #object remains appropriate for revision expressions
|
|
@@ -340,19 +966,25 @@ result.is_a?(Git::CommandLine::Result)
|
|
|
340
966
|
```
|
|
341
967
|
|
|
342
968
|
This change is only relevant if your code references `Git::CommandLineResult`
|
|
343
|
-
by name (typically in type checks or documentation). Code that
|
|
344
|
-
|
|
969
|
+
by name (typically in type checks or documentation). Code that uses the result
|
|
970
|
+
object returned by git commands is unaffected.
|
|
345
971
|
|
|
346
972
|
---
|
|
347
973
|
|
|
348
974
|
### Deprecated methods
|
|
349
975
|
|
|
350
976
|
The following methods are available in v5.x with deprecation warnings and are
|
|
351
|
-
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.
|
|
352
984
|
|
|
353
985
|
#### Facade method renames
|
|
354
986
|
|
|
355
|
-
|
|
987
|
+
v5.x renamed five methods to follow the project's `noun_verb` naming convention.
|
|
356
988
|
The old names continue to work but emit deprecation warnings:
|
|
357
989
|
|
|
358
990
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
@@ -365,11 +997,11 @@ The old names continue to work but emit deprecation warnings:
|
|
|
365
997
|
|
|
366
998
|
#### `Git::Repository` method renames
|
|
367
999
|
|
|
368
|
-
|
|
369
|
-
|
|
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
|
|
370
1002
|
replacement returns, except `branches_all`.
|
|
371
1003
|
|
|
372
|
-
> **Return shape change
|
|
1004
|
+
> **Return shape change.** `g.branches_all` returns an `Array` of 4-element
|
|
373
1005
|
> tuples `[refname, current, worktree, symref]`, where `refname` is the short
|
|
374
1006
|
> form (`main` or `remotes/origin/main`), `current` and `worktree` are booleans,
|
|
375
1007
|
> and `symref` is the symbolic-ref target or `nil`. `g.branch_list` returns
|
|
@@ -387,14 +1019,14 @@ replacement returns, except `branches_all`.
|
|
|
387
1019
|
|
|
388
1020
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
389
1021
|
|-----------------------------------------------------|-------------|
|
|
390
|
-
| `g.empty?` | `g.no_commits
|
|
391
|
-
| `g.reset_hard` | `g.reset(nil, hard: true)
|
|
392
|
-
| `g.reset_hard(commitish)` | `g.reset(commitish, hard: true)
|
|
393
|
-
| `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 |
|
|
394
1026
|
| `g.is_local_branch?(name)` | `g.local_branch?(name)` |
|
|
395
1027
|
| `g.is_remote_branch?(name)` | `g.remote_branch?(name)` |
|
|
396
1028
|
| `g.is_branch?(name)` | `g.branch?(name)` |
|
|
397
|
-
| `g.branches_all` | `g.branch_list
|
|
1029
|
+
| `g.branches_all` | `g.branch_list`. Returns `Array<Git::BranchInfo>`; see the return shape change above |
|
|
398
1030
|
|
|
399
1031
|
#### `Git::Repository` alias renames
|
|
400
1032
|
|
|
@@ -424,7 +1056,7 @@ Five methods accept a v4.x option or positional argument under its old name.
|
|
|
424
1056
|
The old form still works in v5.x but emits a deprecation warning and is
|
|
425
1057
|
translated to the v5.x form shown below.
|
|
426
1058
|
|
|
427
|
-
> **`clean
|
|
1059
|
+
> **`clean`.** `force: 2` runs `git clean -ff`, which also removes untracked
|
|
428
1060
|
> nested git repositories. A `false` or `nil` value for `:ff` or `:force_force`
|
|
429
1061
|
> still warns and has no effect; a value other than `true`, `false`, or `nil`
|
|
430
1062
|
> raises `ArgumentError`. When the deprecated key is `true` and a valid
|
|
@@ -433,11 +1065,11 @@ translated to the v5.x form shown below.
|
|
|
433
1065
|
> unchanged and still raises `ArgumentError`; the deprecated key does not mask
|
|
434
1066
|
> it.
|
|
435
1067
|
|
|
436
|
-
> **`diff_path_status
|
|
1068
|
+
> **`diff_path_status`.** `:path_limiter` accepts the same values as `:path`
|
|
437
1069
|
> (a `String`, a `Pathname`, or an `Array` of them). When both keys are given,
|
|
438
1070
|
> `:path_limiter` wins and no warning is emitted.
|
|
439
1071
|
|
|
440
|
-
> **`set_working` and `set_index
|
|
1072
|
+
> **`set_working` and `set_index`.** `must_exist:` defaults to `true`. When
|
|
441
1073
|
> both the positional argument and `must_exist:` are given, they are OR'ed so
|
|
442
1074
|
> the more restrictive value wins.
|
|
443
1075
|
|
|
@@ -446,39 +1078,39 @@ translated to the v5.x form shown below.
|
|
|
446
1078
|
| `g.clean(ff: true)` | `g.clean(force: 2)` |
|
|
447
1079
|
| `g.clean(force_force: true)` | `g.clean(force: 2)` |
|
|
448
1080
|
| `g.diff_path_status(ref1, ref2, path: p)` | `g.diff_path_status(ref1, ref2, path_limiter: p)` |
|
|
449
|
-
| `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` |
|
|
450
1082
|
| `g.set_working(dir, check)` | `g.set_working(dir, must_exist: check)` |
|
|
451
1083
|
| `g.set_index(file, check)` | `g.set_index(file, must_exist: check)` |
|
|
452
1084
|
|
|
453
1085
|
#### v4.x-style configuration methods
|
|
454
1086
|
|
|
455
1087
|
The v4.x `config` and `global_config` methods accepted varying argument shapes
|
|
456
|
-
to read, write, or list configuration.
|
|
1088
|
+
to read, write, or list configuration. v5.x replaces them with separate,
|
|
457
1089
|
purpose-named methods. The same applies to the module-level
|
|
458
|
-
`Git.global_config`,
|
|
1090
|
+
`Git.global_config`, whose replacements are `Git.config_get`, `Git.config_set`,
|
|
459
1091
|
and `Git.config_list` called with `global: true`.
|
|
460
1092
|
|
|
461
|
-
> **Return type change
|
|
1093
|
+
> **Return type change.** The v4.x `g.config(name)` and `Git.global_config(name)`
|
|
462
1094
|
> returned a `String`; `g.config` and `Git.global_config` returned a `Hash`. The
|
|
463
1095
|
> v5.x replacements `config_get` and `config_list` return `Git::ConfigEntryInfo`
|
|
464
1096
|
> (or `nil` when the key is not set) and `Array<Git::ConfigEntryInfo>`
|
|
465
1097
|
> respectively. Use `.value` to get the String value:
|
|
466
|
-
> - `g.config_get(name)&.value`
|
|
467
|
-
> - `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
|
|
468
1100
|
>
|
|
469
1101
|
> The setters `g.config(name, value)` and `Git.global_config(name, value)`
|
|
470
1102
|
> returned the raw command result; `config_set` returns `nil`.
|
|
471
1103
|
|
|
472
1104
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
473
1105
|
|-----------------------------------------------------|-------------|
|
|
474
|
-
| `g.config(name)` | `g.config_get(name)
|
|
475
|
-
| `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>` |
|
|
476
1108
|
| `g.config(name, value)` | `g.config_set(name, value)` |
|
|
477
1109
|
| `g.global_config(name)` | `g.config_get(name, global: true)` |
|
|
478
1110
|
| `g.global_config` | `g.config_list(global: true)` |
|
|
479
1111
|
| `g.global_config(name, value)` | `g.config_set(name, value, global: true)` |
|
|
480
|
-
| `Git.global_config(name)` | `Git.config_get(name, global: true)
|
|
481
|
-
| `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>` |
|
|
482
1114
|
| `Git.global_config(name, value)` | `Git.config_set(name, value, global: true)` |
|
|
483
1115
|
|
|
484
1116
|
#### `Git` module mixin deprecations
|
|
@@ -512,7 +1144,7 @@ legacy type that is deprecated:
|
|
|
512
1144
|
- `Git.binary_version` is replaced by `Git.git_version`, which keeps the
|
|
513
1145
|
optional binary path argument.
|
|
514
1146
|
|
|
515
|
-
> **Return type change
|
|
1147
|
+
> **Return type change.** `Git.binary_version` returned an `Array<Integer>` of
|
|
516
1148
|
> `[major, minor, patch]`. `Git.git_version` returns a `Git::Version`, which
|
|
517
1149
|
> supports comparison and exposes `major`, `minor`, and `patch`.
|
|
518
1150
|
> `Git.git_version.to_a` reproduces the legacy array. The return value of
|
|
@@ -522,19 +1154,20 @@ legacy type that is deprecated:
|
|
|
522
1154
|
|-----------------------------------------------------|-------------|
|
|
523
1155
|
| `Git.ls_remote(nil)` | `Git.ls_remote` or `Git.ls_remote('.')` |
|
|
524
1156
|
| `Git.ls_remote(nil, opts)` | `Git.ls_remote('.', opts)` |
|
|
525
|
-
| `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 |
|
|
526
1158
|
| `Git.binary_version(binary_path)` | `Git.git_version(binary_path)` |
|
|
527
1159
|
|
|
528
1160
|
#### `Git::Author` deprecated
|
|
529
1161
|
|
|
530
|
-
Starting in v5.3.0, methods that return author, committer, or tagger data
|
|
531
|
-
`Git::
|
|
532
|
-
`Git::
|
|
533
|
-
`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`.
|
|
534
1167
|
|
|
535
1168
|
`Git::AuthorInfo` exposes the same `name`, `email`, and `date` readers, so code
|
|
536
1169
|
that only reads these attributes needs no changes. Code that mutated a
|
|
537
|
-
`Git::Author`
|
|
1170
|
+
`Git::Author` through `name=`, `email=`, or `date=` has to change.
|
|
538
1171
|
`Git::AuthorInfo` is frozen, and `#with` returns a modified copy rather than
|
|
539
1172
|
updating in place (e.g. `info = info.with(name: 'New Name')`).
|
|
540
1173
|
|
|
@@ -553,7 +1186,7 @@ in the repository, so `g.branch('feature').stashes` and `g.branch('main').stashe
|
|
|
553
1186
|
return the same entries. Call `Git::Repository#stash_infos` instead; it is the
|
|
554
1187
|
query `Git::Branch#stashes` was already running.
|
|
555
1188
|
|
|
556
|
-
> **Return type change
|
|
1189
|
+
> **Return type change.** `Git::Branch#stashes` returns a `Git::Stashes`
|
|
557
1190
|
> collection of `Git::Stash` objects. `g.stash_infos` returns an array of
|
|
558
1191
|
> `Git::StashInfo` values. Both are newest first, so indexes carry over unchanged.
|
|
559
1192
|
> `Git::Stash#message` strips the `WIP on <branch>:` or `On <branch>:` prefix;
|
|
@@ -569,15 +1202,15 @@ its methods.
|
|
|
569
1202
|
|
|
570
1203
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
571
1204
|
|-----------------------------------------------------|-------------|
|
|
572
|
-
| `g.branch(name).stashes` | `g.stash_infos
|
|
1205
|
+
| `g.branch(name).stashes` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
573
1206
|
| `g.branch(name).stashes.each { \|s\| puts s.message }` | `g.stash_infos.each { \|info\| puts info.message }` |
|
|
574
|
-
| `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) |
|
|
575
1208
|
| `g.branch(name).stashes.size` | `g.stash_infos.size` |
|
|
576
1209
|
| `g.branch(name).stashes[i].message` (`0` = newest, `i` coerced with `to_i`) | `g.stash_infos[i.to_i].message` |
|
|
577
1210
|
| `g.branch(name).stashes.save(message)` | `g.stash_push(message: message)` |
|
|
578
1211
|
| `g.branch(name).stashes.apply` | `g.stash_apply` |
|
|
579
1212
|
| `g.branch(name).stashes.apply(i)` (`0` = newest) | `g.stash_apply(i)` |
|
|
580
|
-
| `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` |
|
|
581
1214
|
|
|
582
1215
|
#### Legacy stash API deprecated
|
|
583
1216
|
|
|
@@ -594,14 +1227,14 @@ The legacy methods and classes are deprecated and removed in v6.0.0:
|
|
|
594
1227
|
`Git::Repository#stash_list`, `Git::Stash`, and `Git::Stashes`. Constructing a
|
|
595
1228
|
`Git::Stash` or `Git::Stashes` emits one warning per object.
|
|
596
1229
|
|
|
597
|
-
> **Ordering flip
|
|
1230
|
+
> **Ordering flip.** `g.stashes_all` returns entries oldest first with a
|
|
598
1231
|
> sequential index of its own (`0` is the oldest). `g.stash_infos` returns entries
|
|
599
|
-
>
|
|
1232
|
+
> newest first, the order `git stash list` uses, and `Git::StashInfo#index` is
|
|
600
1233
|
> git's own `stash@{N}` number (`0` is the newest). `g.stashes_all.first` is
|
|
601
1234
|
> `g.stash_infos.last`. Code that reads an entry by position must reverse the
|
|
602
1235
|
> array or the index.
|
|
603
1236
|
|
|
604
|
-
> **Message difference
|
|
1237
|
+
> **Message difference.** `g.stashes_all` strips the `WIP on <branch>:` or
|
|
605
1238
|
> `On <branch>:` prefix from each message. `Git::StashInfo#message` keeps the full
|
|
606
1239
|
> message git stores, and `Git::StashInfo#branch` holds the branch name. A stash
|
|
607
1240
|
> created from a detached HEAD has the branch `"(no branch)"`, the label git writes
|
|
@@ -614,32 +1247,38 @@ new `Git::StashInfo`, or `nil` when there were no local changes, so a truthiness
|
|
|
614
1247
|
check such as `if g.stash_push(message: 'WIP')` still works.
|
|
615
1248
|
|
|
616
1249
|
`g.stash_list` returned the `git stash list` text as a String. Build that text from
|
|
617
|
-
`g.stash_infos` if you need it. In v6.0.0
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
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).
|
|
621
1260
|
|
|
622
1261
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
623
1262
|
|-----------------------------------------------------|-------------|
|
|
624
|
-
| `g.stashes_all` | `g.stash_infos
|
|
1263
|
+
| `g.stashes_all` | `g.stash_infos`. Returns `Array<Git::StashInfo>`, newest first |
|
|
625
1264
|
| `g.stashes_all.each { \|index, message\| ... }` | `g.stash_infos.reverse_each.with_index { \|info, index\| ... info.message }` |
|
|
626
1265
|
| `g.stashes_all[i]` (`0` = oldest) | `g.stash_infos.reverse[i]` |
|
|
627
1266
|
| `g.stashes_all.last` | `g.stash_infos.first` |
|
|
628
|
-
| `g.stash_save(message)` | `g.stash_push(message: message)
|
|
1267
|
+
| `g.stash_save(message)` | `g.stash_push(message: message)`. Returns `Git::StashInfo` or `nil` |
|
|
629
1268
|
| `g.stash_list` (String) | `g.stash_infos.map { \|s\| "#{s.name}: #{s.message}" }.join("\n")` |
|
|
630
1269
|
| `Git::Stash.new(g, message)` | `info = g.stash_push(message: message)` |
|
|
631
|
-
| `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 |
|
|
632
1271
|
| `stash.save` | `info = g.stash_push(message: message)` |
|
|
633
|
-
| `stash.saved?` | `!info.nil
|
|
634
|
-
| `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 |
|
|
635
1274
|
| `Git::Stashes.new(g)` | `g.stash_infos` |
|
|
636
|
-
| `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 |
|
|
637
1276
|
| `stashes.each { \|s\| ... }` (newest first) | `g.stash_infos.each { \|info\| ... }` |
|
|
638
1277
|
| `stashes[i]` (`0` = newest, `i` coerced with `to_i`) | `g.stash_infos[i.to_i]` |
|
|
639
1278
|
| `stashes.size` | `g.stash_infos.size` |
|
|
640
1279
|
| `stashes.save(message)` | `g.stash_push(message: message)` |
|
|
641
1280
|
| `stashes.apply` / `stashes.apply(i)` | `g.stash_apply` / `g.stash_apply(i)` |
|
|
642
|
-
| `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` |
|
|
643
1282
|
|
|
644
1283
|
#### `Git::Repository#remotes` deprecated
|
|
645
1284
|
|
|
@@ -649,10 +1288,10 @@ one deprecation warning for itself plus one `Git::Remote` constructor warning fo
|
|
|
649
1288
|
each remote it returns (see the `Git::Remote` deprecation below), so a repository
|
|
650
1289
|
with N remotes produces N + 1 warnings per call.
|
|
651
1290
|
|
|
652
|
-
> **Return type change
|
|
1291
|
+
> **Return type change.** `remotes` returns `Array<Git::Remote>`, mutable
|
|
653
1292
|
> objects with `name`, `url`, and `fetch_opts` accessors and `fetch`, `merge`,
|
|
654
1293
|
> `branch`, and `remove` operations. `remote_list` returns
|
|
655
|
-
> `Array<Git::RemoteInfo
|
|
1294
|
+
> `Array<Git::RemoteInfo>`, immutable value objects read from the repository's
|
|
656
1295
|
> git config, with fields such as `name`, `url`, `push_url`, `fetch`, and `push`.
|
|
657
1296
|
> Because a remote may carry more than one URL or refspec, `url`, `push_url`,
|
|
658
1297
|
> `fetch`, and `push` are always frozen `Array<String>`. When a remote has more
|
|
@@ -663,25 +1302,25 @@ with N remotes produces N + 1 warnings per call.
|
|
|
663
1302
|
> `Git::Remote` are called on the repository instead; the table below shows
|
|
664
1303
|
> the argument each one takes.
|
|
665
1304
|
>
|
|
666
|
-
> **Order change
|
|
1305
|
+
> **Order change.** `remotes` lists remotes in the order `git remote` prints
|
|
667
1306
|
> them, while `remote_list` keeps the order in which remotes first appear in the
|
|
668
1307
|
> config. When the legacy order matters, iterate `g.remote_names` (the same
|
|
669
1308
|
> `git remote` order) or sort `g.remote_list` explicitly.
|
|
670
1309
|
|
|
671
1310
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
672
1311
|
|-----------------------------------------------------|-------------|
|
|
673
|
-
| `g.remotes` | `g.remote_list
|
|
1312
|
+
| `g.remotes` | `g.remote_list`. Returns `Array<Git::RemoteInfo>` |
|
|
674
1313
|
| `g.remotes.map(&:name)` | `g.remote_list.map(&:name)` or `g.remote_names` |
|
|
675
|
-
| `g.remotes.map(&:to_s)` | `g.remote_list.map(&:name)
|
|
676
|
-
| `g.remotes.map(&:url)` | `g.remote_list.map { \|r\| r.url.first }
|
|
677
|
-
| `g.remotes.map(&:fetch_opts)` | `g.remote_list.map { \|r\| r.fetch.last }
|
|
678
|
-
| `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` |
|
|
679
1318
|
| `remote.fetch` | `g.fetch(remote.name)` |
|
|
680
|
-
| `remote.fetch(opts)` | `g.fetch(remote.name, opts)
|
|
1319
|
+
| `remote.fetch(opts)` | `g.fetch(remote.name, opts)`. Same options hash |
|
|
681
1320
|
| `remote.merge` | `g.merge("#{remote.name}/#{g.current_branch}")` |
|
|
682
1321
|
| `remote.merge(branch)` | `g.merge("#{remote.name}/#{branch}")` |
|
|
683
|
-
| `remote.branch` | `g.branch_list("#{remote.name}/#{g.current_branch}").find(&:remote?)
|
|
684
|
-
| `remote.branch(name)` | `g.branch_list("#{remote.name}/#{name}").find(&:remote?)
|
|
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` |
|
|
685
1324
|
| `remote.remove` | `g.remote_remove(remote.name)` |
|
|
686
1325
|
|
|
687
1326
|
#### `Git::Remote` deprecated
|
|
@@ -697,7 +1336,7 @@ and so does calling `g.config_remote`. Calling `g.remote` emits two: one for
|
|
|
697
1336
|
(N + 1 for N remotes). The extra warnings from `g.remote` and `g.remotes` are
|
|
698
1337
|
expected, not a bug.
|
|
699
1338
|
|
|
700
|
-
> **Return type changes
|
|
1339
|
+
> **Return type changes.** `Git::RemoteInfo#url` and `Git::RemoteInfo#fetch` are
|
|
701
1340
|
> frozen `Array<String>` because a remote may carry more than one URL or fetch
|
|
702
1341
|
> refspec. The legacy `Git::Remote#url` and `Git::Remote#fetch_opts` returned only
|
|
703
1342
|
> the last configured value, so `r.url.last` and `r.fetch.last` reproduce them
|
|
@@ -718,19 +1357,19 @@ In the table, `name` is the remote name (`g.remote` defaults it to `'origin'`).
|
|
|
718
1357
|
|
|
719
1358
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
720
1359
|
|-----------------------------------------------------|-------------|
|
|
721
|
-
| `g.remote` | `g.remote_list.find { \|r\| r.name == 'origin' }
|
|
722
|
-
| `g.remote(name)` | `g.remote_list.find { \|r\| r.name == name }
|
|
723
|
-
| `g.config_remote(name)` for `url`, `fetch`, and the other modeled fields | `g.remote_list.find { \|r\| r.name == name }
|
|
724
|
-
| `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}` |
|
|
725
1364
|
| `remote.name`, `remote.to_s` | `g.remote_list.find { \|r\| r.name == name }.name` or `g.remote_names` |
|
|
726
|
-
| `remote.url` | `g.remote_list.find { \|r\| r.name == name }.url
|
|
727
|
-
| `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 |
|
|
728
1367
|
| `remote.fetch` | `g.fetch(name)` |
|
|
729
|
-
| `remote.fetch(opts)` | `g.fetch(name, opts)
|
|
1368
|
+
| `remote.fetch(opts)` | `g.fetch(name, opts)`. Same option keys |
|
|
730
1369
|
| `remote.merge` | `g.merge("#{name}/#{g.current_branch}")` |
|
|
731
1370
|
| `remote.merge(branch)` | `g.merge("#{name}/#{branch}")` |
|
|
732
|
-
| `remote.branch` | `g.branch_list("#{name}/#{g.current_branch}").find(&:remote?)
|
|
733
|
-
| `remote.branch(branch)` | `g.branch_list("#{name}/#{branch}").find(&:remote?)
|
|
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` |
|
|
734
1373
|
| `remote.remove` | `g.remote_remove(name)` |
|
|
735
1374
|
|
|
736
1375
|
#### `Git::Commands::CatFile::Raw` `allow_unknown_type` option deprecated
|
|
@@ -767,7 +1406,7 @@ any operation on a `Git::Branch` each emit a deprecation warning; their return
|
|
|
767
1406
|
values are unchanged. The `full`, `name`, `remote`, `to_s`, and `to_a` readers
|
|
768
1407
|
on `Git::Branch` do not warn.
|
|
769
1408
|
|
|
770
|
-
> **Return shape change
|
|
1409
|
+
> **Return shape change.** `Git::Branch` exposes `full` (`main` or
|
|
771
1410
|
> `remotes/origin/main`), `name`, and `remote` (a `Git::Remote`, or `nil`).
|
|
772
1411
|
> `Git::BranchInfo` exposes `refname` (always the full ref: `refs/heads/main` or
|
|
773
1412
|
> `refs/remotes/origin/main`), `short_name` (`main` for both), `remote_name` (a
|
|
@@ -778,7 +1417,7 @@ on `Git::Branch` do not warn.
|
|
|
778
1417
|
> `'origin/main'` matches the remote-tracking branch. The `remotes/origin/main`
|
|
779
1418
|
> and `refs/...` forms that `g.branches[...]` accepted match nothing.
|
|
780
1419
|
>
|
|
781
|
-
> **`checkout` no longer creates the branch
|
|
1420
|
+
> **`checkout` no longer creates the branch.** `g.branch('x').checkout` created
|
|
782
1421
|
> `x` when it did not exist, ignoring any error from that attempt, and then
|
|
783
1422
|
> checked it out. `g.checkout('x')` does not create a missing local branch,
|
|
784
1423
|
> with one exception that is git's own: when exactly one remote has a branch
|
|
@@ -824,33 +1463,33 @@ can resolve a local branch of that name and is only used where git expects it
|
|
|
824
1463
|
|
|
825
1464
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
826
1465
|
|-----------------------------------------------------|-------------|
|
|
827
|
-
| `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
|
|
828
|
-
| `g.branch` | `g.branch_list(g.current_branch).first
|
|
829
|
-
| `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>` |
|
|
830
1469
|
| `g.branches[name]` | `g.branch_list(name).first`, or `g.branch_list("#{remote}/#{name}").find(&:remote?)` for a remote-tracking branch |
|
|
831
1470
|
| `g.branches.local` | `g.branch_list.reject(&:remote?)` |
|
|
832
1471
|
| `g.branches.remote` | `g.branch_list.select(&:remote?)` |
|
|
833
1472
|
| `g.branches.size` | `g.branch_list.size` |
|
|
834
1473
|
| `g.branches.each { \|b\| ... }` | `g.branch_list.each { \|info\| ... }` |
|
|
835
|
-
| `g.branches.to_s` | `g.branch_list.map { \|i\| "#{i.current? ? '* ' : ' '}#{i.refname}\n" }.join
|
|
836
|
-
| `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` |
|
|
837
1476
|
| `b.to_a` | `[info.refname]` |
|
|
838
1477
|
| `b.name` | `info.short_name` |
|
|
839
|
-
| `b.remote` | `info.remote_name
|
|
840
|
-
| `b.gcommit` | `g.gcommit(name)
|
|
841
|
-
| `b.checkout` | `g.checkout(name)
|
|
842
|
-
| `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 |
|
|
843
1482
|
| `b.delete` (local) | `g.branch_delete(name)` |
|
|
844
1483
|
| `b.delete` (remote-tracking) | `g.branch_delete("#{remote}/#{name}", remotes: true)` |
|
|
845
1484
|
| `b.current` | `g.current_branch == name` |
|
|
846
1485
|
| `b.contains?(commit)` | `!g.branch_contains(commit, name).empty?` |
|
|
847
1486
|
| `b.merge` | `g.merge(name)` |
|
|
848
|
-
| `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 |
|
|
849
1488
|
| `b.update_ref(commit)` (local) | `g.update_ref(name, commit)` |
|
|
850
1489
|
| `b.update_ref(commit)` (remote-tracking) | `g.update_ref("remotes/#{remote}/#{name}", commit)` |
|
|
851
|
-
| `b.archive(file, opts)` | `g.archive(name, file, opts)
|
|
852
|
-
| `b.in_branch(message) { ... }` | `g.in_branch(name, message) { ... }
|
|
853
|
-
| `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) |
|
|
854
1493
|
|
|
855
1494
|
#### `Git::Object::Tag` deprecated
|
|
856
1495
|
|
|
@@ -869,7 +1508,7 @@ for the `g.tag_add` it calls; `g.add_tag(name, d: true)` emits three, adding the
|
|
|
869
1508
|
`:d`/`:delete` warning described below. The readers on a `Git::Object::Tag` do not
|
|
870
1509
|
warn.
|
|
871
1510
|
|
|
872
|
-
> **Return shape change
|
|
1511
|
+
> **Return shape change.** `Git::Object::Tag` exposes `name`, `sha`, `objectish`,
|
|
873
1512
|
> `annotated?`, `message`, and `tagger`. `Git::TagInfo` exposes `name`, `oid`,
|
|
874
1513
|
> `target_oid`, `objecttype`, `annotated?`, `lightweight?`, `message`, and
|
|
875
1514
|
> `tagger`. `name` and `annotated?` are unchanged. `tagger` keeps the same `name`
|
|
@@ -887,25 +1526,23 @@ warn.
|
|
|
887
1526
|
> which kind (`tag` for an annotated tag, or the target's own type such as
|
|
888
1527
|
> `commit` or `blob` for a lightweight one).
|
|
889
1528
|
>
|
|
890
|
-
> **Missing tags
|
|
1529
|
+
> **Missing tags.** `g.tag(name)` raises `Git::UnexpectedResultError` when no tag
|
|
891
1530
|
> has that name. `g.tag_list(name).first` returns `nil`.
|
|
892
1531
|
>
|
|
893
|
-
> **`tag_create`
|
|
894
|
-
>
|
|
895
|
-
>
|
|
896
|
-
> raises
|
|
897
|
-
> `Git::TagInfo`. A `nil` check on the result keeps working today and becomes
|
|
898
|
-
> unreachable in v6.0.0.
|
|
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).
|
|
899
1536
|
>
|
|
900
|
-
> **Deleting through `tag_add
|
|
1537
|
+
> **Deleting through `tag_add`.** `g.tag_add(name, d: true)`, which was already
|
|
901
1538
|
> deprecated, deletes the tag and emits a second warning pointing at
|
|
902
1539
|
> `g.tag_delete`. `g.tag_create` rejects `:d` and `:delete` with `ArgumentError`.
|
|
903
1540
|
>
|
|
904
|
-
> **Extra positional arguments
|
|
1541
|
+
> **Extra positional arguments.** `g.tag_add(name, target, extra)` ignores
|
|
905
1542
|
> `extra` and tags `target`. `g.tag_create` raises `ArgumentError` when more than
|
|
906
1543
|
> one positional argument follows the name.
|
|
907
1544
|
>
|
|
908
|
-
> **Object identity
|
|
1545
|
+
> **Object identity.** Every `Git::Object::Tag` resolves its tag to an object ID
|
|
909
1546
|
> when it is constructed and runs `size`, `contents`, `grep`, `diff`, `log`, and
|
|
910
1547
|
> `archive` against that ID, so moving or deleting the tag afterwards does not
|
|
911
1548
|
> redirect an existing object. `Git::Object::Tag.new(g, sha, name)` uses the
|
|
@@ -924,26 +1561,26 @@ In the table, `name` is the tag name, `t` is a `Git::Object::Tag`, `info` is the
|
|
|
924
1561
|
|
|
925
1562
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
926
1563
|
|-----------------------------------------------------|-------------|
|
|
927
|
-
| `g.tag(name)` | `g.tag_list(name).first
|
|
928
|
-
| `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>` |
|
|
929
1566
|
| `g.tags.map(&:name)` | `g.tag_list.map(&:name)` |
|
|
930
|
-
| `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` |
|
|
931
1568
|
| `g.tag_add(name, target, opts)` | `g.tag_create(name, target, opts)` |
|
|
932
1569
|
| `g.tag_add(name, d: true)` | `g.tag_delete(name)` |
|
|
933
|
-
| `g.add_tag(name, opts)`, `g.add_tag(name, target, opts)` | `g.tag_create(name, ...)
|
|
934
|
-
| `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 |
|
|
935
1572
|
| `Git::Object::Tag.new(g, name)` | `g.tag_list(name).first` |
|
|
936
|
-
| `Git::Object::Tag.new(g, sha, name)` | `g.tag_list(name).first
|
|
937
|
-
| `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 |
|
|
938
1575
|
| `t.name` | `info.name` |
|
|
939
|
-
| `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 |
|
|
940
1577
|
| `t.annotated?` | `info.annotated?` |
|
|
941
|
-
| `t.message` | `info.message
|
|
942
|
-
| `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 |
|
|
943
1580
|
| `t.tag?` | not needed; every `Git::TagInfo` is a tag |
|
|
944
|
-
| `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 |
|
|
945
1582
|
| `t.contents` | `g.cat_file_contents(id)` |
|
|
946
|
-
| `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 |
|
|
947
1584
|
| `t.contents_array` | `g.cat_file_contents(id).split("\n")` |
|
|
948
1585
|
| `t.grep(string, path, opts)` | `g.grep(string, path, opts.merge(object: id))` |
|
|
949
1586
|
| `t.diff(other)` | `g.diff(id, other)` |
|
|
@@ -953,7 +1590,7 @@ In the table, `name` is the tag name, `t` is a `Git::Object::Tag`, `info` is the
|
|
|
953
1590
|
#### `Git::Status` deprecated
|
|
954
1591
|
|
|
955
1592
|
Starting in v5.4.0, `Git::Status`, `Git::Status::StatusFile`, and
|
|
956
|
-
`Git::Repository#status` are deprecated and
|
|
1593
|
+
`Git::Repository#status` are deprecated and are removed in v6.0.0. Read the
|
|
957
1594
|
index and working tree state through `Git::Repository#status_info`, which
|
|
958
1595
|
returns an immutable `Git::StatusInfo` holding one `Git::StatusFileInfo` per
|
|
959
1596
|
path that `git status --porcelain=v2` reports. Calling `g.status` emits one
|
|
@@ -998,7 +1635,7 @@ reference, so `blob` is gone; fetch the object through the repository instead.
|
|
|
998
1635
|
`stage` is gone too: an unmerged entry carries its stage 1, 2, and 3 modes and
|
|
999
1636
|
SHAs in `unmerged_stages`, and every other entry is at stage 0.
|
|
1000
1637
|
|
|
1001
|
-
> **Field renames
|
|
1638
|
+
> **Field renames.** The legacy mode and SHA readers were named for the wrong
|
|
1002
1639
|
> sides. `sha_index` and `mode_index` held the working-tree side of the diff:
|
|
1003
1640
|
> the index blob when the working tree matched the index, and an all-zero SHA
|
|
1004
1641
|
> when it did not. `sha_repo` and `mode_repo` held the side git compared the
|
|
@@ -1016,12 +1653,12 @@ In the table, `g` is a `Git::Repository`, `status` is the `Git::Status` from
|
|
|
1016
1653
|
|
|
1017
1654
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1018
1655
|
|-----------------------------------------------------|-------------|
|
|
1019
|
-
| `g.status` | `g.status_info
|
|
1656
|
+
| `g.status` | `g.status_info`. Returns a `Git::StatusInfo` |
|
|
1020
1657
|
| `Git::Status.new(g)` | `g.status_info` |
|
|
1021
|
-
| `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 |
|
|
1022
1659
|
| `status.changed?(path)`, `status.added?(path)`, `status.deleted?(path)`, `status.untracked?(path)` | same names on `g.status_info` |
|
|
1023
|
-
| `status[path]` | `g.status_info[path]
|
|
1024
|
-
| `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) |
|
|
1025
1662
|
| `status.pretty` | no replacement; format `g.status_info.files` yourself |
|
|
1026
1663
|
| `file.path` | `info.path` |
|
|
1027
1664
|
| `file.type` | `info.index_status` and `info.worktree_status`, or the `info.changed?`, `info.added?`, and `info.deleted?` predicates |
|
|
@@ -1031,8 +1668,8 @@ In the table, `g` is a `Git::Repository`, `status` is the `Git::Status` from
|
|
|
1031
1668
|
| `file.mode_repo` | `info.mode_head`, or `info.mode_index` in a repository with no commits |
|
|
1032
1669
|
| `file.sha_index` | `info.sha_index` for the staged blob; `info.worktree_status` says whether the working tree differs from it |
|
|
1033
1670
|
| `file.mode_index` | `info.mode_worktree` |
|
|
1034
|
-
| `file.blob` | `g.object(info.sha_index)` when `info.sha_index` is set and not all zeros
|
|
1035
|
-
| `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 |
|
|
1036
1673
|
|
|
1037
1674
|
#### `Git::Worktree` and `Git::Worktrees` deprecated
|
|
1038
1675
|
|
|
@@ -1051,7 +1688,7 @@ warning; the `dir`, `full`, `to_s`, and `to_a` readers on `Git::Worktree` do not
|
|
|
1051
1688
|
it constructs, and `g.worktree(dir).add` emits one for `g.worktree` and one for
|
|
1052
1689
|
`add`.
|
|
1053
1690
|
|
|
1054
|
-
> **Return shape change
|
|
1691
|
+
> **Return shape change.** `worktrees_all` returns `[directory, sha]` pairs and
|
|
1055
1692
|
> omits the main worktree of a bare repository, which has no checked-out commit.
|
|
1056
1693
|
> `worktree_list` returns `Git::WorktreeInfo` objects with `path`, `head`,
|
|
1057
1694
|
> `branch` (the full refname, such as `refs/heads/main`, or `nil` when detached
|
|
@@ -1060,19 +1697,22 @@ it constructs, and `g.worktree(dir).add` emits one for `g.worktree` and one for
|
|
|
1060
1697
|
> `branch` set to `nil`. `Git::WorktreeInfo#to_s` is the path, so an entry can be
|
|
1061
1698
|
> passed to any method that takes a worktree path.
|
|
1062
1699
|
>
|
|
1063
|
-
> **`gcommit` return type
|
|
1700
|
+
> **`gcommit` return type.** `Git::Worktree#gcommit` returned a
|
|
1064
1701
|
> `Git::Object::Commit` for a worktree obtained from `g.worktree(dir)` and a raw
|
|
1065
1702
|
> SHA `String` for one obtained from `g.worktrees`. `info.head` is always a
|
|
1066
1703
|
> `String` (or `nil` for a bare main worktree); call `g.gcommit(info.head)` for
|
|
1067
1704
|
> the commit object.
|
|
1068
1705
|
>
|
|
1069
|
-
> **`full` and `to_s
|
|
1706
|
+
> **`full` and `to_s`.** `Git::Worktree#full` and `#to_s` append the commitish
|
|
1070
1707
|
> given at construction to the path, so entries from `g.worktrees` read
|
|
1071
1708
|
> `"/path/to/wt <sha>"`. `Git::WorktreeInfo#to_s` is the path alone.
|
|
1072
1709
|
>
|
|
1073
|
-
> **`worktree_add`
|
|
1710
|
+
> **`worktree_add` in v6.0.0.** On v5.x, `worktree_add` returns the
|
|
1074
1711
|
> `git worktree add` output (`"HEAD is now at …"`). In v6.0.0 it returns the new
|
|
1075
|
-
> `Git::WorktreeInfo` instead
|
|
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:
|
|
1076
1716
|
> `g.worktree_list.find { |w| File.identical?(w.path, dir) }`. Compare with
|
|
1077
1717
|
> `File.identical?`, not string equality: git stores worktree paths with
|
|
1078
1718
|
> symlinks resolved, so `/tmp/...` on macOS is listed as `/private/tmp/...`,
|
|
@@ -1083,27 +1723,28 @@ is the `Git::WorktreeInfo` that replaces it.
|
|
|
1083
1723
|
|
|
1084
1724
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1085
1725
|
|-----------------------------------------------------|-------------|
|
|
1086
|
-
| `g.worktrees_all` | `g.worktree_list.map { \|w\| [w.path, w.head] }
|
|
1087
|
-
| `g.worktrees` | `g.worktree_list
|
|
1088
|
-
| `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 |
|
|
1089
1729
|
| `g.worktrees.size` | `g.worktree_list.size` |
|
|
1090
1730
|
| `g.worktrees.each { \|wt\| ... }` | `g.worktree_list.each { \|info\| ... }` |
|
|
1091
1731
|
| `g.worktrees.to_s` | `g.worktree_list.map { \|w\| "#{w.path} #{w.head}\n" }.join` |
|
|
1092
1732
|
| `g.worktrees.prune` | `g.worktree_prune` |
|
|
1093
1733
|
| `g.worktree(dir).add` | `g.worktree_add(dir)` |
|
|
1094
1734
|
| `g.worktree(dir, commitish).add` | `g.worktree_add(dir, commitish)` |
|
|
1095
|
-
| `g.worktree(dir).remove` | `g.worktree_remove(dir)`
|
|
1096
|
-
| `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 |
|
|
1097
1737
|
| `wt.dir` | `info.path` |
|
|
1098
|
-
| `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 |
|
|
1099
1739
|
| `wt.to_a` | `[info.path]` |
|
|
1100
1740
|
|
|
1101
1741
|
#### `Git.clone` option renames
|
|
1102
1742
|
|
|
1103
|
-
Three `Git.clone` options were renamed in v5.x. The v4.x names still work
|
|
1104
|
-
deprecated option present on a call emits its own deprecation
|
|
1105
|
-
that uses two of them warns twice. Each value is passed
|
|
1106
|
-
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.
|
|
1107
1748
|
|
|
1108
1749
|
> **Precedence and value notes:**
|
|
1109
1750
|
> - `:path` and `:chdir` both run `git clone` from inside the given directory.
|
|
@@ -1116,7 +1757,7 @@ replacement option, except that `:path` is dropped when `:chdir` is also given.
|
|
|
1116
1757
|
| Deprecated call (works in v5.x, removed in v6.0.0) | Replacement |
|
|
1117
1758
|
|-----------------------------------------------------|-------------|
|
|
1118
1759
|
| `Git.clone(url, dir, path: p)` | `Git.clone(url, dir, chdir: p)` |
|
|
1119
|
-
| `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 |
|
|
1120
1761
|
| `Git.clone(url, dir, remote: name)` | `Git.clone(url, dir, origin: name)` |
|
|
1121
1762
|
|
|
1122
1763
|
#### `Git::Log` Enumerable interface deprecated
|
|
@@ -1133,7 +1774,7 @@ builder (`map`, `select`, `count`, `to_a`, `include?`, and so on) goes through t
|
|
|
1133
1774
|
deprecated `each` and emits its warning. Move those calls to the result as well,
|
|
1134
1775
|
not only the six named methods.
|
|
1135
1776
|
|
|
1136
|
-
> **Snapshot results
|
|
1777
|
+
> **Snapshot results.** `execute` returns a snapshot. The builder re-runs
|
|
1137
1778
|
> `git log` only when a query method (`since`, `max_count`, and so on) has been
|
|
1138
1779
|
> called since the last run, even with the same value as before, so calling
|
|
1139
1780
|
> `execute` twice on an untouched builder returns equal results without a second
|
|
@@ -1146,7 +1787,7 @@ In the table, `g` is a `Git::Repository`.
|
|
|
1146
1787
|
|-----------------------------------------------------|-------------|
|
|
1147
1788
|
| `g.log.each { \|c\| ... }` | `g.log.execute.each { \|c\| ... }` |
|
|
1148
1789
|
| `g.log.size` | `g.log.execute.size` |
|
|
1149
|
-
| `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 |
|
|
1150
1791
|
| `g.log.first`, `g.log.last` | `g.log.execute.first`, `g.log.execute.last` |
|
|
1151
1792
|
| `g.log[i]`, `g.log[range]` | `g.log.execute[i]`, `g.log.execute[range]` |
|
|
1152
1793
|
| any other `Enumerable` method on the log (`map`, `select`, `count`, `to_a`, `include?`, ...) | the same method on `g.log.execute` |
|
|
@@ -1178,40 +1819,4 @@ observable in the result. Delete the option from the call.
|
|
|
1178
1819
|
|--------------------------------------------------------------------|-------------|
|
|
1179
1820
|
| `Git.export(url, dir, remote: name)` | `Git.export(url, dir)` |
|
|
1180
1821
|
|
|
1181
|
-
#### Context helper blocks that declare no parameter deprecated
|
|
1182
|
-
|
|
1183
|
-
`Git::Repository#with_index`, `#with_temp_index`, `#with_working`, and
|
|
1184
|
-
`#with_temp_working` yield `self` in v5.x, so a block could ignore the yielded
|
|
1185
|
-
value and call methods on the receiver. Calling one of these helpers with a block
|
|
1186
|
-
that declares no positional parameter (`do ... end`, `{ }`, `{ || }`, or a block
|
|
1187
|
-
with only keyword or block parameters) now emits a deprecation warning. The
|
|
1188
|
-
behavior is otherwise unchanged: the helpers still yield `self`, and a call with
|
|
1189
|
-
no block still raises `LocalJumpError`.
|
|
1190
|
-
|
|
1191
|
-
In v6.0.0 these helpers yield a separate repository bound to the other index or
|
|
1192
|
-
working tree instead of rebinding the receiver, and they raise `ArgumentError` for
|
|
1193
|
-
a block that declares no positional parameter. A call with no block also raises
|
|
1194
|
-
`ArgumentError` in v6.0.0 instead of `LocalJumpError`. Declare a block parameter
|
|
1195
|
-
and call methods on it. The parameter is required even when the block never uses
|
|
1196
|
-
the repository, for example a `with_temp_working` block that only writes files
|
|
1197
|
-
(`do |_scratch|`). Blocks that already declare a positional parameter (`|repo|`,
|
|
1198
|
-
`|_|`, `|repo = nil|`, `|*args|`, or a symbol-to-proc such as `&:write_tree`) do
|
|
1199
|
-
not warn. Both versions read the block's parameter list rather than its arity, so
|
|
1200
|
-
the v5.x warning and the v6.0.0 error agree on every block form.
|
|
1201
|
-
|
|
1202
|
-
The warning detects only the block's parameter list. Adding an unused parameter
|
|
1203
|
-
(`|_|`) silences it but does not fix a block that still calls methods on the outer
|
|
1204
|
-
repository; that block does not warn and acts on the wrong repository in v6.0.0,
|
|
1205
|
-
so review those blocks by hand.
|
|
1206
|
-
|
|
1207
|
-
| Deprecated call (works in v5.x, raises in v6.0.0) | Replacement |
|
|
1208
|
-
|---------------------------------------------------|-------------|
|
|
1209
|
-
| `g.with_index(path) { g.read_tree('HEAD') }` | `g.with_index(path) { \|r\| r.read_tree('HEAD') }` |
|
|
1210
|
-
| `g.with_temp_index { g.read_tree('HEAD') }` | `g.with_temp_index { \|r\| r.read_tree('HEAD') }` |
|
|
1211
|
-
| `g.with_working(dir) { g.add('.') }` | `g.with_working(dir) { \|r\| r.add('.') }` |
|
|
1212
|
-
| `g.with_temp_working { g.add('.') }` | `g.with_temp_working { \|r\| r.add('.') }` |
|
|
1213
|
-
|
|
1214
|
-
`chdir` is not part of this deprecation. It yields the directory path in both
|
|
1215
|
-
versions.
|
|
1216
|
-
|
|
1217
1822
|
---
|