git 5.7.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -35
- data/CONTRIBUTING.md +44 -31
- data/README.md +138 -100
- data/UPGRADING.md +867 -262
- 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
|
@@ -299,7 +299,7 @@ module Git
|
|
|
299
299
|
#
|
|
300
300
|
# @api private
|
|
301
301
|
#
|
|
302
|
-
DIFF_PATH_STATUS_ALLOWED_OPTS = %i[path_limiter
|
|
302
|
+
DIFF_PATH_STATUS_ALLOWED_OPTS = %i[path_limiter].freeze
|
|
303
303
|
private_constant :DIFF_PATH_STATUS_ALLOWED_OPTS
|
|
304
304
|
|
|
305
305
|
# Returns the file path status between two trees
|
|
@@ -349,9 +349,6 @@ module Git
|
|
|
349
349
|
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path_limiter (nil)
|
|
350
350
|
# limit the status report to the given path(s)
|
|
351
351
|
#
|
|
352
|
-
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path (nil)
|
|
353
|
-
# **deprecated** — use `:path_limiter` instead
|
|
354
|
-
#
|
|
355
352
|
# @return [Git::DiffPathStatus] the name-status report for the comparison
|
|
356
353
|
#
|
|
357
354
|
# @raise [ArgumentError] if unsupported options are provided
|
|
@@ -366,50 +363,12 @@ module Git
|
|
|
366
363
|
SharedPrivate.assert_valid_opts!(DIFF_PATH_STATUS_ALLOWED_OPTS, **opts)
|
|
367
364
|
raise ArgumentError, 'Invalid arguments: `from` is nil but `to` is not' if from.nil? && !to.nil?
|
|
368
365
|
|
|
369
|
-
|
|
370
|
-
pathspecs = Private.normalize_pathspecs(path_limiter, 'path limiter')
|
|
366
|
+
pathspecs = Private.normalize_pathspecs(opts[:path_limiter], 'path limiter')
|
|
371
367
|
|
|
372
368
|
result = Private.call_diff_command(@execution_context, from, to, pathspecs)
|
|
373
369
|
Git::DiffPathStatus.new(Private.extract_name_status_from_raw(result.stdout))
|
|
374
370
|
end
|
|
375
371
|
|
|
376
|
-
# Reports each changed path with its status (deprecated name for {#diff_path_status})
|
|
377
|
-
#
|
|
378
|
-
# @example Report path statuses between HEAD and the working tree
|
|
379
|
-
# repo.diff_name_status.to_h #=> { "lib/foo.rb" => "M" }
|
|
380
|
-
#
|
|
381
|
-
# @param from [String, nil] the first commit or object to compare
|
|
382
|
-
#
|
|
383
|
-
# @param to [String, nil] the second commit or object to compare
|
|
384
|
-
#
|
|
385
|
-
# @param opts [Hash] the options accepted by {#diff_path_status}
|
|
386
|
-
#
|
|
387
|
-
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path_limiter (nil)
|
|
388
|
-
# limit the status report to the given path(s)
|
|
389
|
-
#
|
|
390
|
-
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path (nil)
|
|
391
|
-
# **deprecated** — use `:path_limiter` instead
|
|
392
|
-
#
|
|
393
|
-
# @return [Git::DiffPathStatus] the name-status report for the comparison
|
|
394
|
-
#
|
|
395
|
-
# @raise [ArgumentError] if unsupported options are provided
|
|
396
|
-
#
|
|
397
|
-
# @raise [ArgumentError] if `from` is `nil` but `to` is not OR if `from` or `to` starts with `"-"`
|
|
398
|
-
#
|
|
399
|
-
# @raise [Git::FailedError] if git exits outside the allowed range (exit code > 2)
|
|
400
|
-
#
|
|
401
|
-
# @deprecated Use {#diff_path_status} instead. Will be removed in v6.0.0.
|
|
402
|
-
#
|
|
403
|
-
# @see #diff_path_status
|
|
404
|
-
#
|
|
405
|
-
def diff_name_status(from = 'HEAD', to = nil, opts = {})
|
|
406
|
-
Git::Deprecation.warn(
|
|
407
|
-
'Git::Repository#diff_name_status is deprecated and will be removed in v6.0.0. ' \
|
|
408
|
-
'Use Git::Repository#diff_path_status instead.'
|
|
409
|
-
)
|
|
410
|
-
diff_path_status(from, to, opts)
|
|
411
|
-
end
|
|
412
|
-
|
|
413
372
|
# Compares the index and the working directory
|
|
414
373
|
#
|
|
415
374
|
# Runs `git diff-files` to list files that differ between the index
|
|
@@ -523,35 +482,6 @@ module Git
|
|
|
523
482
|
module Private
|
|
524
483
|
module_function
|
|
525
484
|
|
|
526
|
-
# Resolves the effective path limiter from the options hash
|
|
527
|
-
#
|
|
528
|
-
# When `:path_limiter` is present it is used directly and no warning is
|
|
529
|
-
# emitted. When only `:path` is present a deprecation warning is emitted
|
|
530
|
-
# and its value is used. Returns `nil` when neither key is present.
|
|
531
|
-
#
|
|
532
|
-
# @param opts [Hash] the options hash from {#diff_path_status}
|
|
533
|
-
#
|
|
534
|
-
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path_limiter (nil)
|
|
535
|
-
# primary path limiter value used as-is when present
|
|
536
|
-
#
|
|
537
|
-
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path (nil)
|
|
538
|
-
# **deprecated** — fallback path limiter when `:path_limiter` is not provided
|
|
539
|
-
#
|
|
540
|
-
# @return [String, Pathname, Array<String, Pathname>, nil]
|
|
541
|
-
# the effective path limiter
|
|
542
|
-
#
|
|
543
|
-
def resolve_path_limiter(opts)
|
|
544
|
-
if opts.key?(:path_limiter)
|
|
545
|
-
opts[:path_limiter]
|
|
546
|
-
elsif opts.key?(:path)
|
|
547
|
-
Git::Deprecation.warn(
|
|
548
|
-
'Git::Repository#diff_path_status :path option is deprecated and will be removed in v6.0.0. ' \
|
|
549
|
-
'Use :path_limiter instead.'
|
|
550
|
-
)
|
|
551
|
-
opts[:path]
|
|
552
|
-
end
|
|
553
|
-
end
|
|
554
|
-
|
|
555
485
|
# Extracts only the patch text from combined diff command output
|
|
556
486
|
#
|
|
557
487
|
# When {Git::Commands::Diff} is called with `patch: true, numstat: true,
|
|
@@ -7,6 +7,7 @@ require 'git/commands/merge_base'
|
|
|
7
7
|
require 'git/commands/revert/start'
|
|
8
8
|
require 'git/commands/show'
|
|
9
9
|
require 'git/repository/shared_private'
|
|
10
|
+
require 'git/system_call_guard'
|
|
10
11
|
|
|
11
12
|
module Git
|
|
12
13
|
class Repository
|
|
@@ -81,6 +82,10 @@ module Git
|
|
|
81
82
|
#
|
|
82
83
|
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
83
84
|
#
|
|
85
|
+
# @note On a conflict, the merge is left in progress: the conflicted paths
|
|
86
|
+
# are in the index and working tree, and `MERGE_HEAD` is set until the
|
|
87
|
+
# caller commits the resolution or aborts the merge.
|
|
88
|
+
#
|
|
84
89
|
def merge(branch, message = nil, opts = {})
|
|
85
90
|
SharedPrivate.assert_valid_opts!(MERGE_ALLOWED_OPTS, **opts)
|
|
86
91
|
|
|
@@ -126,18 +131,13 @@ module Git
|
|
|
126
131
|
# branch is checked out, so those failures never leave the repository on
|
|
127
132
|
# `target_branch`. Anything rejected later, such as an option value that is
|
|
128
133
|
# not accepted or a source ref that does not exist, surfaces inside {#merge}
|
|
129
|
-
# after the checkout and
|
|
134
|
+
# after the checkout and leaves the repository checked out on `target_branch`.
|
|
130
135
|
#
|
|
131
136
|
# The `:no_commit` option is not accepted: a merge stopped before its commit
|
|
132
137
|
# would leave `target_branch` unchanged and the restore checkout would carry
|
|
133
138
|
# the staged result onto the original branch. To merge without committing,
|
|
134
139
|
# call {#checkout} and {#merge} directly.
|
|
135
140
|
#
|
|
136
|
-
# **Note:** the restore checkout is not wrapped in `ensure`. If the merge
|
|
137
|
-
# fails (for example, on a conflict), the repository is left checked out on
|
|
138
|
-
# `target_branch` with the merge in progress rather than restored to the
|
|
139
|
-
# original branch.
|
|
140
|
-
#
|
|
141
141
|
# @example Merge a feature branch into main while staying on the current branch
|
|
142
142
|
# repo.merge_into('main', 'feature')
|
|
143
143
|
#
|
|
@@ -179,6 +179,12 @@ module Git
|
|
|
179
179
|
#
|
|
180
180
|
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
181
181
|
#
|
|
182
|
+
# @note If the merge or the restore checkout fails, the repository is left
|
|
183
|
+
# checked out on `target_branch` rather than restored to the original
|
|
184
|
+
# branch. On a conflict, the merge is also left in progress. When the
|
|
185
|
+
# restore checkout is the step that fails, the merge has already been
|
|
186
|
+
# committed on `target_branch`.
|
|
187
|
+
#
|
|
182
188
|
def merge_into(target_branch, branch, message = nil, opts = {})
|
|
183
189
|
SharedPrivate.assert_valid_opts!(MERGE_INTO_ALLOWED_OPTS, **opts)
|
|
184
190
|
raise ArgumentError, 'at least one branch to merge is required' if Array(branch).empty?
|
|
@@ -187,6 +193,7 @@ module Git
|
|
|
187
193
|
restore_point = SharedPrivate.head_restore_point(self)
|
|
188
194
|
checkout(target_branch)
|
|
189
195
|
output = merge(branch, message, opts)
|
|
196
|
+
# Runs only on success. See ADR-0009.
|
|
190
197
|
checkout(restore_point)
|
|
191
198
|
output
|
|
192
199
|
end
|
|
@@ -278,6 +285,9 @@ module Git
|
|
|
278
285
|
# @raise [Git::FailedError] when `git diff --cached` exits outside the
|
|
279
286
|
# allowed range (exit code > 2)
|
|
280
287
|
#
|
|
288
|
+
# @raise [Git::Error] when the staged content cannot be written to a
|
|
289
|
+
# temporary file
|
|
290
|
+
#
|
|
281
291
|
# @yield [file, your_version, their_version] passes conflict details for
|
|
282
292
|
# each unmerged file
|
|
283
293
|
#
|
|
@@ -302,49 +312,6 @@ module Git
|
|
|
302
312
|
end
|
|
303
313
|
end
|
|
304
314
|
|
|
305
|
-
# Iterate over files with merge conflicts, yielding conflict details for each
|
|
306
|
-
#
|
|
307
|
-
# For each unmerged file, the staged content for both sides of the conflict
|
|
308
|
-
# (stage 2 "ours" and stage 3 "theirs") is written to temporary files whose
|
|
309
|
-
# paths are yielded alongside the file path. The temporary files are deleted
|
|
310
|
-
# automatically when the block returns.
|
|
311
|
-
#
|
|
312
|
-
# @example Inspect conflicting files
|
|
313
|
-
# repo.conflicts do |file, your_version, their_version|
|
|
314
|
-
# puts "Conflict in #{file}"
|
|
315
|
-
# puts File.read(your_version)
|
|
316
|
-
# puts File.read(their_version)
|
|
317
|
-
# end
|
|
318
|
-
#
|
|
319
|
-
# @return [Array<String>] the list of unmerged file paths
|
|
320
|
-
#
|
|
321
|
-
# @raise [Git::FailedError] when `git diff --cached` exits outside the
|
|
322
|
-
# allowed range (exit code > 2)
|
|
323
|
-
#
|
|
324
|
-
# @yield [file, your_version, their_version] passes conflict details for
|
|
325
|
-
# each unmerged file
|
|
326
|
-
#
|
|
327
|
-
# @yieldparam file [String] path to the conflicting file, relative to the
|
|
328
|
-
# working tree
|
|
329
|
-
#
|
|
330
|
-
# @yieldparam your_version [String] path to a temporary file containing the
|
|
331
|
-
# stage-2 (ours) content for the conflicting file
|
|
332
|
-
#
|
|
333
|
-
# @yieldparam their_version [String] path to a temporary file containing the
|
|
334
|
-
# stage-3 (theirs) content for the conflicting file
|
|
335
|
-
#
|
|
336
|
-
# @yieldreturn [void]
|
|
337
|
-
#
|
|
338
|
-
# @deprecated Use {#each_conflict} instead
|
|
339
|
-
#
|
|
340
|
-
def conflicts(&)
|
|
341
|
-
Git::Deprecation.warn(
|
|
342
|
-
'Git::Repository#conflicts is deprecated and will be removed in v6.0.0. ' \
|
|
343
|
-
'Use Git::Repository#each_conflict instead.'
|
|
344
|
-
)
|
|
345
|
-
each_conflict(&)
|
|
346
|
-
end
|
|
347
|
-
|
|
348
315
|
# Option keys accepted by {#revert}
|
|
349
316
|
#
|
|
350
317
|
# Derived from the 4.x option map for `Git::Lib#revert`.
|
|
@@ -385,6 +352,12 @@ module Git
|
|
|
385
352
|
#
|
|
386
353
|
# @raise [Git::FailedError] when git exits with a non-zero exit status
|
|
387
354
|
#
|
|
355
|
+
# @note On a conflict, the revert is left in progress with the conflicted
|
|
356
|
+
# paths in the index and working tree until the caller continues, skips,
|
|
357
|
+
# or aborts it. When more than one commit is reverted, the revert commits
|
|
358
|
+
# made before the conflict are on the branch; aborting the revert removes
|
|
359
|
+
# them again.
|
|
360
|
+
#
|
|
388
361
|
def revert(commitish = nil, opts = {})
|
|
389
362
|
commitish = 'HEAD' if commitish.nil?
|
|
390
363
|
SharedPrivate.assert_valid_opts!(REVERT_ALLOWED_OPTS, **opts)
|
|
@@ -429,6 +402,9 @@ module Git
|
|
|
429
402
|
#
|
|
430
403
|
# @return [void]
|
|
431
404
|
#
|
|
405
|
+
# @raise [Git::Error] if the staged content cannot be written to a
|
|
406
|
+
# temporary file
|
|
407
|
+
#
|
|
432
408
|
# @yield [f] yields the open Tempfile containing the staged content
|
|
433
409
|
#
|
|
434
410
|
# @yieldparam f [Tempfile] open IO object for the staged content
|
|
@@ -437,11 +413,13 @@ module Git
|
|
|
437
413
|
#
|
|
438
414
|
# @api private
|
|
439
415
|
#
|
|
440
|
-
def write_staged_file(execution_context, file_path, stage)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
416
|
+
def write_staged_file(execution_context, file_path, stage, &block)
|
|
417
|
+
Git::SystemCallGuard.call('Failed to write the staged content to a temporary file') do |guard|
|
|
418
|
+
Tempfile.create([STAGE_PREFIXES[stage], File.basename(file_path)]) do |f|
|
|
419
|
+
Git::Commands::Show.new(execution_context).call(":#{stage}:#{file_path}", out: f)
|
|
420
|
+
f.flush
|
|
421
|
+
guard.unguarded { block.call(f) }
|
|
422
|
+
end
|
|
445
423
|
end
|
|
446
424
|
end
|
|
447
425
|
end
|