git 5.5.0 → 5.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a27bcb58894e06dd36f368c545d7800e95b2106122d222f98e43e4776117d38
4
- data.tar.gz: a59267db8db5a09e843914400be509c574670d824882b8c7a0c80f3e38945238
3
+ metadata.gz: fb847c9e15258e66f25f6856a2ceb170213e9ae310d061035ef23501e6e0cd72
4
+ data.tar.gz: eca3a73ec5bf9f979d4576375062ceaeb71a78b54f12660b3b4386c2920792e9
5
5
  SHA512:
6
- metadata.gz: c60016fdfb41208d18ab63e36fb24a26c5a4cbc73978d44bab657ffb4ee8395d9c774311a752ae91e474b36d3b11d9eafb0c5ce1f54d8202068057d50b6c1093
7
- data.tar.gz: 24656d7407eeea1ae1f92a8748eee1e65cdba4bafb9409ca0a96a819cfe7e3e2be4d9838fa3369464ccf908d5a7313de884a2e11c750f23664d88fcaa157f3dd
6
+ metadata.gz: 3842eadabba8c7bead2147b438ca51597ca0acc129b7d33b41f942750d29cb7e5910b1ca92e3f50cf7bc440afb9f5ed203a97f38b72c19b09025f4e7317849f2
7
+ data.tar.gz: 558adf7d3f23639b9143dcf3b9092739caba6415e066a8273f491f0589f3af06851dc15fd1776b2bad3e406d01429da76cce72c7e05f3c7ac57858bc3a771645
data/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## [5.6.0](https://github.com/ruby-git/ruby-git/compare/v5.5.0...v5.6.0) (2026-09-12)
9
+
10
+
11
+ ### Features
12
+
13
+ * **repository:** Deprecate with_* context helper blocks that declare no parameter ([231b65c](https://github.com/ruby-git/ruby-git/commit/231b65c435e9b3d9cdbf8b113b3aba9313da5110)), closes [#1835](https://github.com/ruby-git/ruby-git/issues/1835)
14
+
15
+
16
+ ### Other Changes
17
+
18
+ * **export:** Describe what a failed .git removal leaves behind ([bd08096](https://github.com/ruby-git/ruby-git/commit/bd080964e44a11594202726e3823a8cafad62bd5)), closes [#1823](https://github.com/ruby-git/ruby-git/issues/1823)
19
+
8
20
  ## [5.5.0](https://github.com/ruby-git/ruby-git/compare/v5.4.1...v5.5.0) (2026-09-10)
9
21
 
10
22
 
data/UPGRADING.md CHANGED
@@ -35,6 +35,7 @@ to update your code when upgrading from the preceding major version.
35
35
  - [`Git::Log` Enumerable interface deprecated](#gitlog-enumerable-interface-deprecated)
36
36
  - [`Git::Object::Commit#set_commit` deprecated](#gitobjectcommitset_commit-deprecated)
37
37
  - [`Git.export` `:remote` option deprecated](#gitexport-remote-option-deprecated)
38
+ - [Context helper blocks that declare no parameter deprecated](#context-helper-blocks-that-declare-no-parameter-deprecated)
38
39
 
39
40
  ## Upgrading to v6.0.0
40
41
 
@@ -1135,4 +1136,40 @@ observable in the result. Delete the option from the call.
1135
1136
  |--------------------------------------------------------------------|-------------|
1136
1137
  | `Git.export(url, dir, remote: name)` | `Git.export(url, dir)` |
1137
1138
 
1139
+ #### Context helper blocks that declare no parameter deprecated
1140
+
1141
+ `Git::Repository#with_index`, `#with_temp_index`, `#with_working`, and
1142
+ `#with_temp_working` yield `self` in v5.x, so a block could ignore the yielded
1143
+ value and call methods on the receiver. Calling one of these helpers with a block
1144
+ that declares no positional parameter (`do ... end`, `{ }`, `{ || }`, or a block
1145
+ with only keyword or block parameters) now emits a deprecation warning. The
1146
+ behavior is otherwise unchanged: the helpers still yield `self`, and a call with
1147
+ no block still raises `LocalJumpError`.
1148
+
1149
+ In v6.0.0 these helpers yield a separate repository bound to the other index or
1150
+ working tree instead of rebinding the receiver, and they raise `ArgumentError` for
1151
+ a block that declares no positional parameter. A call with no block also raises
1152
+ `ArgumentError` in v6.0.0 instead of `LocalJumpError`. Declare a block parameter
1153
+ and call methods on it. The parameter is required even when the block never uses
1154
+ the repository, for example a `with_temp_working` block that only writes files
1155
+ (`do |_scratch|`). Blocks that already declare a positional parameter (`|repo|`,
1156
+ `|_|`, `|repo = nil|`, `|*args|`, or a symbol-to-proc such as `&:write_tree`) do
1157
+ not warn. Both versions read the block's parameter list rather than its arity, so
1158
+ the v5.x warning and the v6.0.0 error agree on every block form.
1159
+
1160
+ The warning detects only the block's parameter list. Adding an unused parameter
1161
+ (`|_|`) silences it but does not fix a block that still calls methods on the outer
1162
+ repository; that block does not warn and acts on the wrong repository in v6.0.0,
1163
+ so review those blocks by hand.
1164
+
1165
+ | Deprecated call (works in v5.x, raises in v6.0.0) | Replacement |
1166
+ |---------------------------------------------------|-------------|
1167
+ | `g.with_index(path) { g.read_tree('HEAD') }` | `g.with_index(path) { \|r\| r.read_tree('HEAD') }` |
1168
+ | `g.with_temp_index { g.read_tree('HEAD') }` | `g.with_temp_index { \|r\| r.read_tree('HEAD') }` |
1169
+ | `g.with_working(dir) { g.add('.') }` | `g.with_working(dir) { \|r\| r.add('.') }` |
1170
+ | `g.with_temp_working { g.add('.') }` | `g.with_temp_working { \|r\| r.add('.') }` |
1171
+
1172
+ `chdir` is not part of this deprecation. It yields the directory path in both
1173
+ versions.
1174
+
1138
1175
  ---
@@ -18,6 +18,10 @@ module Git
18
18
  # @api private
19
19
  #
20
20
  module ContextHelpers
21
+ # Parameter types from `Proc#parameters` that receive a positional argument
22
+ CONTEXT_HELPERS_POSITIONAL_PARAMETERS = %i[req opt rest].freeze
23
+ private_constant :CONTEXT_HELPERS_POSITIONAL_PARAMETERS
24
+
21
25
  # Changes the current working directory to the repository working directory
22
26
  # for the duration of the block
23
27
  #
@@ -51,9 +55,13 @@ module Git
51
55
  # yields `self`, then unconditionally restores the original execution
52
56
  # context — even if the block raises an exception.
53
57
  #
58
+ # Deprecated form: a block that declares no positional parameter emits a
59
+ # deprecation warning, because v6.0.0 yields a separate repository
60
+ # instead of `self`.
61
+ #
54
62
  # @example Read a tree into a custom index
55
- # repo.with_index('/tmp/custom.index') do
56
- # repo.read_tree('HEAD')
63
+ # repo.with_index('/tmp/custom.index') do |r|
64
+ # r.read_tree('HEAD')
57
65
  # end
58
66
  #
59
67
  # @param new_index [String, Pathname] path to the replacement index file
@@ -66,7 +74,8 @@ module Git
66
74
  #
67
75
  # @yieldreturn [Object] returned as the method's return value
68
76
  #
69
- def with_index(new_index) # :yields: self
77
+ def with_index(new_index, &block) # :yields: self
78
+ context_helpers_warn_if_block_declares_no_parameter(:with_index, block)
70
79
  old_context = @execution_context
71
80
  set_index(new_index, must_exist: false)
72
81
  yield self
@@ -84,10 +93,14 @@ module Git
84
93
  # are removed unconditionally after the block exits, even if the block
85
94
  # raises an exception.
86
95
  #
96
+ # Deprecated form: a block that declares no positional parameter emits a
97
+ # deprecation warning, because v6.0.0 yields a separate repository
98
+ # instead of `self`.
99
+ #
87
100
  # @example Stage changes using a temporary index
88
- # repo.with_temp_index do
89
- # repo.read_tree('HEAD')
90
- # repo.write_tree
101
+ # repo.with_temp_index do |r|
102
+ # r.read_tree('HEAD')
103
+ # r.write_tree
91
104
  # end
92
105
  #
93
106
  # @return [Object] the value returned by the block
@@ -98,13 +111,17 @@ module Git
98
111
  #
99
112
  # @yieldreturn [Object] returned as the method's return value
100
113
  #
101
- def with_temp_index(&) # :yields: self
114
+ def with_temp_index(&block) # :yields: self
115
+ context_helpers_warn_if_block_declares_no_parameter(:with_temp_index, block)
102
116
  # Use a unique temp directory so the index file path is collision-free
103
117
  # and does not exist until git writes it. An existing empty file would
104
118
  # be treated as a corrupt index by git.
105
119
  temp_dir = Dir.mktmpdir('git-temp-index-')
106
120
  begin
107
- with_index(File.join(temp_dir, 'index'), &)
121
+ # The inner block declares a parameter so with_index does not warn a
122
+ # second time under its own name; forwarding &block would.
123
+ # rubocop:disable-next Style/ExplicitBlockArgument
124
+ with_index(File.join(temp_dir, 'index')) { |repo| yield repo }
108
125
  ensure
109
126
  FileUtils.remove_entry(temp_dir, true)
110
127
  end
@@ -118,10 +135,14 @@ module Git
118
135
  # `self`, then unconditionally restores the original execution context —
119
136
  # even if the block raises an exception.
120
137
  #
138
+ # Deprecated form: a block that declares no positional parameter emits a
139
+ # deprecation warning, because v6.0.0 yields a separate repository
140
+ # instead of `self`.
141
+ #
121
142
  # @example Commit changes from a different worktree path
122
- # repo.with_working('/path/to/worktree') do
123
- # repo.add('.')
124
- # repo.commit('chore: automated update')
143
+ # repo.with_working('/path/to/worktree') do |r|
144
+ # r.add('.')
145
+ # r.commit('chore: automated update')
125
146
  # end
126
147
  #
127
148
  # @param work_dir [String, Pathname] path to the replacement working
@@ -138,7 +159,8 @@ module Git
138
159
  #
139
160
  # @yieldreturn [Object] returned as the method's return value
140
161
  #
141
- def with_working(work_dir) # :yields: self
162
+ def with_working(work_dir, &block) # :yields: self
163
+ context_helpers_warn_if_block_declares_no_parameter(:with_working, block)
142
164
  old_context = @execution_context
143
165
  set_working(work_dir)
144
166
  Dir.chdir(dir.to_s) { yield self }
@@ -153,9 +175,14 @@ module Git
153
175
  # The temporary directory is removed unconditionally after the block
154
176
  # exits, even if the block raises an exception.
155
177
  #
178
+ # Deprecated form: a block that declares no positional parameter emits a
179
+ # deprecation warning, because v6.0.0 yields a separate repository
180
+ # instead of `self`.
181
+ #
156
182
  # @example Write files in an isolated temporary working directory
157
- # repo.with_temp_working do
183
+ # repo.with_temp_working do |r|
158
184
  # File.write('scratch.txt', 'temporary content')
185
+ # r.add('scratch.txt')
159
186
  # end
160
187
  #
161
188
  # @return [Object] the value returned by the block
@@ -168,7 +195,11 @@ module Git
168
195
  # @yieldreturn [Object] returned as the method's return value
169
196
  #
170
197
  def with_temp_working(&block) # :yields: self
171
- Dir.mktmpdir('temp-workdir') { |temp_dir| with_working(temp_dir, &block) }
198
+ context_helpers_warn_if_block_declares_no_parameter(:with_temp_working, block)
199
+ # The inner block declares a parameter so with_working does not warn a
200
+ # second time under its own name; forwarding &block would.
201
+ # rubocop:disable-next Style/ExplicitBlockArgument
202
+ Dir.mktmpdir('temp-workdir') { |temp_dir| with_working(temp_dir) { |repo| yield repo } }
172
203
  end
173
204
 
174
205
  # Sets the git index to `index_file` and rebuilds the execution context
@@ -231,6 +262,42 @@ module Git
231
262
 
232
263
  private
233
264
 
265
+ # Emits a deprecation warning when `block` declares no positional parameter
266
+ #
267
+ # In v6.0.0 the `with_*` helpers yield a separate repository instead of
268
+ # rebinding the receiver, so a block that calls methods on the receiver
269
+ # (the v5.x form) acts on the wrong repository there. v6.0.0 raises
270
+ # `ArgumentError` for that form using this same rule: the block must
271
+ # declare a required, optional, or splat positional parameter. The rule
272
+ # reads `Proc#parameters` rather than arity because an optional parameter
273
+ # gives a proc an arity of zero although it receives the repository,
274
+ # while keyword and block parameters cannot receive it.
275
+ #
276
+ # A missing block is not checked here; the helper's `yield` raises
277
+ # `LocalJumpError` as before.
278
+ #
279
+ # The warning reports the helper's caller, not this helper's caller, so
280
+ # the location points at the block that needs changing.
281
+ #
282
+ # @param helper [Symbol] the public helper name used in the warning
283
+ #
284
+ # @param block [Proc, nil] the block passed to the helper
285
+ #
286
+ # @return [void]
287
+ #
288
+ def context_helpers_warn_if_block_declares_no_parameter(helper, block)
289
+ return if block.nil?
290
+ return if block.parameters.any? { |type, _name| CONTEXT_HELPERS_POSITIONAL_PARAMETERS.include?(type) }
291
+
292
+ Git::Deprecation.warn(
293
+ "Calling Git::Repository##{helper} with a block that declares no positional " \
294
+ 'parameter is deprecated and will be removed in v6.0.0, where the helper ' \
295
+ 'yields a separate repository instead of self. Declare a block parameter and ' \
296
+ "call methods on it instead: #{helper} { |repo| repo.some_method }",
297
+ caller_locations(2)
298
+ )
299
+ end
300
+
234
301
  # Resolves deprecated `check` argument semantics with `must_exist:`
235
302
  #
236
303
  # @param check [Boolean, nil] deprecated positional existence-check value
data/lib/git/version.rb CHANGED
@@ -4,7 +4,7 @@ module Git
4
4
  # The current gem version
5
5
  #
6
6
  # @return [String] the current gem version
7
- VERSION = '5.5.0'
7
+ VERSION = '5.6.0'
8
8
 
9
9
  # Represents a git version with major, minor, and patch components
10
10
  #
data/lib/git.rb CHANGED
@@ -327,6 +327,11 @@ module Git
327
327
  # Exports the current HEAD (or the specific branch given in <tt>options[:branch]</tt>)
328
328
  # into the given `directory`. It then removes all traces of git from the directory.
329
329
  #
330
+ # Removing `.git` is not atomic. If it fails, the exported files are complete and
331
+ # usable, but the directory keeps whatever part of `.git` could not be deleted.
332
+ # Nothing is cleaned up, because the exported files are the deliverable and the
333
+ # leftover has to be removed by hand once the cause of the failure is fixed.
334
+ #
330
335
  # Takes the same options as {Git.clone} except that `:depth` defaults to 1 and
331
336
  # `:remote` is ignored with a deprecation warning.
332
337
  #
@@ -348,6 +353,10 @@ module Git
348
353
  #
349
354
  # @return [void]
350
355
  #
356
+ # @raise [SystemCallError] if the `.git` directory cannot be removed. The exported
357
+ # files are left in place, and the directory keeps whatever part of `.git` could
358
+ # not be deleted.
359
+ #
351
360
  def self.export(repository_url, directory = nil, options = {})
352
361
  if options.key?(:remote)
353
362
  Git::Deprecation.warn(
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.0
4
+ version: 5.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon and others
@@ -548,8 +548,8 @@ licenses:
548
548
  metadata:
549
549
  homepage_uri: http://github.com/ruby-git/ruby-git
550
550
  source_code_uri: http://github.com/ruby-git/ruby-git
551
- changelog_uri: https://rubydoc.info/gems/git/5.5.0/file/CHANGELOG.md
552
- documentation_uri: https://rubydoc.info/gems/git/5.5.0
551
+ changelog_uri: https://rubydoc.info/gems/git/5.6.0/file/CHANGELOG.md
552
+ documentation_uri: https://rubydoc.info/gems/git/5.6.0
553
553
  rubygems_mfa_required: 'true'
554
554
  rdoc_options: []
555
555
  require_paths: