git 1.13.1 → 1.14.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: 8d000b5ac2ceebebeb6c84eae6aa1c6f4b3d58dd444f15c70390baadf7bb3c8e
4
- data.tar.gz: f45ef489fb3aa2d3cff1a45cb127bb27fe380693af5e322220322fd8aa6dfd33
3
+ metadata.gz: 344c98cd98670d4afa26aae12680f28ad857f1fdbca4384a10c9cf7ed7937a8a
4
+ data.tar.gz: 9d857e44f2457f6c5208bebca6935991c2e88fbd82b2c482c570cd7afcca7c38
5
5
  SHA512:
6
- metadata.gz: 6128142518501bce8bd4e5f40e178ac063359916daf544005bdc6187160619b74c6236a7f56b29438f3b5ebb547a5759b59b3140ee260ebd179bc8a4124d1a15
7
- data.tar.gz: 56e9d4940992d8feab68502815563d6d16967c1d659748271bdd27e0e1a382f81ce4be4dd7682645b562f8b616be791f79437fdaaa072778aca724c91e40b4d1
6
+ metadata.gz: 6fd40652aa02ad36238522ee2210ad7c01ced240f0a1b91f2de3e6baefe93dd0a20fb22b80821ee45bf974d73a3cc346e4a5adbaa2322384b57e2bb0251d491d
7
+ data.tar.gz: 0c8d86fe09a9e4f8d06c1d8bb0abf05eff45a2746450253ccf751163e4340b873df4eff2dbfb0711aad30c61303e0c692802a378bceb46a26a1e17ba08927268
data/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## v1.14.0 (2023-02-25)
9
+
10
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.13.2..v1.14.0)
11
+
12
+ Changes since v1.13.2:
13
+
14
+ * 0f7c4a5 Allow the use of an array of path_limiters and add extended_regexp option to grep (#624)
15
+ * 8992701 Refactor error thrown when a git command fails (#622)
16
+ * cf74b91 Simplify how temp files are used when testing Git::Base#archive (#621)
17
+ * a8bfb9d Set init.defaultBranch when running tests if it is not already set (#620)
18
+ * 9ee7ca9 Create a null logger if a logger is not provided (#619)
19
+ * 872de4c Internal refactor of Git::Lib command (#618)
20
+ * 29e157d Simplify test running and fixture repo cloning (#615)
21
+ * 08d04ef Use dynamically-created repo for signed commits test (#614)
22
+
23
+ ## v1.13.2 (2023-02-02)
24
+
25
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.13.1..v1.13.2)
26
+
27
+ Changes since v1.13.1:
28
+
29
+ * b6e031d Fix `Git::Lib#commit_data` for GPG-signed commits (#610)
30
+ * b12b820 Fix escaped path decoding (#612)
31
+
8
32
  ## v1.13.1 (2023-01-12)
9
33
 
10
34
  [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.13.0...v1.13.1)
data/CONTRIBUTING.md CHANGED
@@ -81,6 +81,18 @@ In order to ensure high quality, all pull requests must meet these requirements:
81
81
  * The entire test suite must pass when `bundle exec rake default` is run from the
82
82
  project's local working copy.
83
83
 
84
+ While working on specific features you can run individual test files or
85
+ a group of tests using `bin/test`:
86
+
87
+ # run a single file:
88
+ $ bin/test tests/units/test_object.rb
89
+
90
+ # run multiple files:
91
+ $ bin/test tests/units/test_object.rb tests/units/test_archive.rb
92
+
93
+ # run all unit tests:
94
+ $ bin/test
95
+
84
96
  ### Continuous integration
85
97
  * All tests must pass in the project's [GitHub Continuous Integration build](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI)
86
98
  before the pull request will be merged.
data/Rakefile CHANGED
@@ -1,16 +1,20 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'English'
3
3
 
4
- require "#{File.expand_path(File.dirname(__FILE__))}/lib/git/version"
4
+ require 'git/version'
5
5
 
6
6
  default_tasks = []
7
7
 
8
8
  desc 'Run Unit Tests'
9
9
  task :test do
10
- sh 'git config --global user.email "git@example.com"' if `git config user.email`.empty?
11
- sh 'git config --global user.name "GitExample"' if `git config user.name`.empty?
10
+ sh 'ruby bin/test'
12
11
 
13
- require File.dirname(__FILE__) + '/tests/all_tests.rb'
12
+ # You can run individual test files (or multiple files) from the command
13
+ # line with:
14
+ #
15
+ # $ bin/test tests/units/test_archive.rb
16
+ #
17
+ # $ bin/test tests/units/test_archive.rb tests/units/test_object.rb
14
18
  end
15
19
  default_tasks << :test
16
20
 
data/lib/git/base.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'git/base/factory'
2
+ require 'logger'
2
3
 
3
4
  module Git
4
5
  # Git::Base is the main public interface for interacting with Git commands.
@@ -90,12 +91,8 @@ module Git
90
91
  options[:repository] ||= File.join(working_dir, '.git')
91
92
  options[:index] ||= File.join(options[:repository], 'index')
92
93
  end
93
- if options[:log]
94
- @logger = options[:log]
95
- @logger.info("Starting Git")
96
- else
97
- @logger = nil
98
- end
94
+ @logger = (options[:log] || Logger.new(nil))
95
+ @logger.info("Starting Git")
99
96
 
100
97
  @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
101
98
  @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
@@ -212,6 +209,15 @@ module Git
212
209
  # end
213
210
  # end
214
211
  #
212
+ # @param string [String] the string to search for
213
+ # @param path_limiter [String, Array] a path or array of paths to limit the search to or nil for no limit
214
+ # @param opts [Hash] options to pass to the underlying `git grep` command
215
+ #
216
+ # @option opts [Boolean] :ignore_case (false) ignore case when matching
217
+ # @option opts [Boolean] :invert_match (false) select non-matching lines
218
+ # @option opts [Boolean] :extended_regexp (false) use extended regular expressions
219
+ # @option opts [String] :object (HEAD) the object to search from
220
+ #
215
221
  # @return [Hash<String, Array>] a hash of arrays
216
222
  # ```Ruby
217
223
  # {
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ # The result of running a git command
5
+ #
6
+ # This object stores the Git command executed and its status, stdout, and stderr.
7
+ #
8
+ # @api public
9
+ #
10
+ class CommandLineResult
11
+ # Create a CommandLineResult object
12
+ #
13
+ # @example
14
+ # `true`
15
+ # git_cmd = %w[git version]
16
+ # status = $?
17
+ # stdout = "git version 2.39.1\n"
18
+ # stderr = ""
19
+ # result = Git::CommandLineResult.new(git_cmd, status, stdout, stderr)
20
+ #
21
+ # @param git_cmd [Array<String>] the git command that was executed
22
+ # @param status [Process::Status] the status of the process
23
+ # @param stdout [String] the output of the process
24
+ # @param stderr [String] the error output of the process
25
+ #
26
+ def initialize(git_cmd, status, stdout, stderr)
27
+ @git_cmd = git_cmd
28
+ @status = status
29
+ @stdout = stdout
30
+ @stderr = stderr
31
+ end
32
+
33
+ # @attribute [r] git_cmd
34
+ #
35
+ # The git command that was executed
36
+ #
37
+ # @example
38
+ # git_cmd = %w[git version]
39
+ # result = Git::CommandLineResult.new(git_cmd, $?, "", "")
40
+ # result.git_cmd #=> ["git", "version"]
41
+ #
42
+ # @return [Array<String>]
43
+ #
44
+ attr_reader :git_cmd
45
+
46
+ # @attribute [r] status
47
+ #
48
+ # The status of the process
49
+ #
50
+ # @example
51
+ # `true`
52
+ # status = $?
53
+ # result = Git::CommandLineResult.new(status, "", "")
54
+ # result.status #=> #<Process::Status: pid 87859 exit 0>
55
+ #
56
+ # @return [Process::Status]
57
+ #
58
+ attr_reader :status
59
+
60
+ # @attribute [r] stdout
61
+ #
62
+ # The output of the process
63
+ #
64
+ # @example
65
+ # stdout = "git version 2.39.1\n"
66
+ # result = Git::CommandLineResult.new($?, stdout, "")
67
+ # result.stdout #=> "git version 2.39.1\n"
68
+ #
69
+ # @return [String]
70
+ #
71
+ attr_reader :stdout
72
+
73
+ # @attribute [r] stderr
74
+ #
75
+ # The error output of the process
76
+ #
77
+ # @example
78
+ # stderr = "Tag not found\n"
79
+ # result = Git::CommandLineResult.new($?, "", stderr)
80
+ # result.stderr #=> "Tag not found\n"
81
+ #
82
+ # @return [String]
83
+ #
84
+ attr_reader :stderr
85
+ end
86
+ end
@@ -42,7 +42,7 @@ module Git
42
42
  private
43
43
 
44
44
  def extract_octal(path, index)
45
- [path[index + 1..index + 4].to_i(8), 4]
45
+ [path[index + 1..index + 3].to_i(8), 4]
46
46
  end
47
47
 
48
48
  def extract_escape(path, index)
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/git_execute_error'
4
+
5
+ module Git
6
+ # This error is raised when a git command fails
7
+ #
8
+ # The git command executed, status, stdout, and stderr are available from this
9
+ # object. The #message includes the git command, the status of the process, and
10
+ # the stderr of the process.
11
+ #
12
+ # @api public
13
+ #
14
+ class FailedError < Git::GitExecuteError
15
+ # Create a FailedError object
16
+ #
17
+ # @example
18
+ # `exit 1` # set $? appropriately for this example
19
+ # result = Git::CommandLineResult.new(%w[git status], $?, '', "failed")
20
+ # error = Git::FailedError.new(result)
21
+ # error.message #=>
22
+ # "[\"git\", \"status\"]\nstatus: pid 89784 exit 1\nstderr: \"failed\""
23
+ #
24
+ # @param result [Git::CommandLineResult] the result of the git command including
25
+ # the git command, status, stdout, and stderr
26
+ #
27
+ def initialize(result)
28
+ super("#{result.git_cmd}\nstatus: #{result.status}\nstderr: #{result.stderr.inspect}")
29
+ @result = result
30
+ end
31
+
32
+ # @attribute [r] result
33
+ #
34
+ # The result of the git command including the git command and its status and output
35
+ #
36
+ # @example
37
+ # `exit 1` # set $? appropriately for this example
38
+ # result = Git::CommandLineResult.new(%w[git status], $?, '', "failed")
39
+ # error = Git::FailedError.new(result)
40
+ # error.result #=>
41
+ # #<Git::CommandLineResult:0x00000001046bd488
42
+ # @git_cmd=["git", "status"],
43
+ # @status=#<Process::Status: pid 89784 exit 1>,
44
+ # @stderr="failed",
45
+ # @stdout="">
46
+ #
47
+ # @return [Git::CommandLineResult]
48
+ #
49
+ attr_reader :result
50
+ end
51
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ # This error is raised when a git command fails
5
+ #
6
+ class GitExecuteError < StandardError; end
7
+ end
data/lib/git/lib.rb CHANGED
@@ -1,11 +1,9 @@
1
+ require 'git/failed_error'
2
+ require 'logger'
1
3
  require 'tempfile'
2
4
  require 'zlib'
3
5
 
4
6
  module Git
5
-
6
- class GitExecuteError < StandardError
7
- end
8
-
9
7
  class Lib
10
8
 
11
9
  @@semaphore = Mutex.new
@@ -52,6 +50,7 @@ module Git
52
50
  @git_index_file = nil
53
51
  @git_work_dir = nil
54
52
  @path = nil
53
+ @logger = logger || Logger.new(nil)
55
54
 
56
55
  if base.is_a?(Git::Base)
57
56
  @git_dir = base.repo.path
@@ -62,7 +61,6 @@ module Git
62
61
  @git_index_file = base[:index]
63
62
  @git_work_dir = base[:working_directory]
64
63
  end
65
- @logger = logger
66
64
  end
67
65
 
68
66
  # creates or reinitializes the repository
@@ -77,7 +75,7 @@ module Git
77
75
  arr_opts << '--bare' if opts[:bare]
78
76
  arr_opts << "--initial-branch=#{opts[:initial_branch]}" if opts[:initial_branch]
79
77
 
80
- command('init', arr_opts)
78
+ command('init', *arr_opts)
81
79
  end
82
80
 
83
81
  # tries to clone the given repo
@@ -113,7 +111,7 @@ module Git
113
111
  arr_opts << repository_url
114
112
  arr_opts << clone_dir
115
113
 
116
- command('clone', arr_opts)
114
+ command('clone', *arr_opts)
117
115
 
118
116
  return_base_opts_from_clone(clone_dir, opts)
119
117
  end
@@ -168,7 +166,7 @@ module Git
168
166
 
169
167
  arr_opts << committish if committish
170
168
 
171
- return command('describe', arr_opts)
169
+ return command('describe', *arr_opts)
172
170
  end
173
171
 
174
172
  def log_commits(opts={})
@@ -178,7 +176,7 @@ module Git
178
176
 
179
177
  arr_opts += log_path_options(opts)
180
178
 
181
- command_lines('log', arr_opts).map { |l| l.split.first }
179
+ command_lines('log', *arr_opts).map { |l| l.split.first }
182
180
  end
183
181
 
184
182
  def full_log_commits(opts={})
@@ -189,7 +187,7 @@ module Git
189
187
 
190
188
  arr_opts += log_path_options(opts)
191
189
 
192
- full_log = command_lines('log', arr_opts)
190
+ full_log = command_lines('log', *arr_opts)
193
191
 
194
192
  process_commit_log_data(full_log)
195
193
  end
@@ -221,54 +219,57 @@ module Git
221
219
  def commit_data(sha)
222
220
  sha = sha.to_s
223
221
  cdata = command_lines('cat-file', 'commit', sha)
224
- process_commit_data(cdata, sha, 0)
222
+ process_commit_data(cdata, sha)
225
223
  end
226
224
 
227
- def process_commit_data(data, sha = nil, indent = 4)
225
+ def process_commit_data(data, sha)
228
226
  hsh = {
229
- 'sha' => sha,
230
- 'message' => '',
231
- 'parent' => []
227
+ 'sha' => sha,
228
+ 'parent' => []
232
229
  }
233
230
 
234
- loop do
235
- key, *value = data.shift.split
236
-
237
- break if key.nil?
238
-
231
+ each_cat_file_header(data) do |key, value|
239
232
  if key == 'parent'
240
- hsh['parent'] << value.join(' ')
233
+ hsh['parent'] << value
241
234
  else
242
- hsh[key] = value.join(' ')
235
+ hsh[key] = value
243
236
  end
244
237
  end
245
238
 
246
- hsh['message'] = data.collect {|line| line[indent..-1]}.join("\n") + "\n"
239
+ hsh['message'] = data.join("\n") + "\n"
247
240
 
248
241
  return hsh
249
242
  end
250
243
 
244
+ CAT_FILE_HEADER_LINE = /\A(?<key>\w+) (?<value>.*)\z/
245
+
246
+ def each_cat_file_header(data)
247
+ while (match = CAT_FILE_HEADER_LINE.match(data.shift))
248
+ key = match[:key]
249
+ value_lines = [match[:value]]
250
+
251
+ while data.first.start_with?(' ')
252
+ value_lines << data.shift.lstrip
253
+ end
254
+
255
+ yield key, value_lines.join("\n")
256
+ end
257
+ end
258
+
251
259
  def tag_data(name)
252
260
  sha = sha.to_s
253
261
  tdata = command_lines('cat-file', 'tag', name)
254
- process_tag_data(tdata, name, 0)
262
+ process_tag_data(tdata, name)
255
263
  end
256
264
 
257
- def process_tag_data(data, name, indent=4)
258
- hsh = {
259
- 'name' => name,
260
- 'message' => ''
261
- }
262
-
263
- loop do
264
- key, *value = data.shift.split
265
-
266
- break if key.nil?
265
+ def process_tag_data(data, name)
266
+ hsh = { 'name' => name }
267
267
 
268
- hsh[key] = value.join(' ')
268
+ each_cat_file_header(data) do |key, value|
269
+ hsh[key] = value
269
270
  end
270
271
 
271
- hsh['message'] = data.collect {|line| line[indent..-1]}.join("\n") + "\n"
272
+ hsh['message'] = data.join("\n") + "\n"
272
273
 
273
274
  return hsh
274
275
  end
@@ -367,7 +368,7 @@ module Git
367
368
  # HEAD b8c63206f8d10f57892060375a86ae911fad356e
368
369
  # detached
369
370
  #
370
- command_lines('worktree',['list', '--porcelain']).each do |w|
371
+ command_lines('worktree', 'list', '--porcelain').each do |w|
371
372
  s = w.split("\s")
372
373
  directory = s[1] if s[0] == 'worktree'
373
374
  arr << [directory, s[1]] if s[0] == 'HEAD'
@@ -376,16 +377,16 @@ module Git
376
377
  end
377
378
 
378
379
  def worktree_add(dir, commitish = nil)
379
- return command('worktree', ['add', dir, commitish]) if !commitish.nil?
380
- command('worktree', ['add', dir])
380
+ return command('worktree', 'add', dir, commitish) if !commitish.nil?
381
+ command('worktree', 'add', dir)
381
382
  end
382
383
 
383
384
  def worktree_remove(dir)
384
- command('worktree', ['remove', dir])
385
+ command('worktree', 'remove', dir)
385
386
  end
386
387
 
387
388
  def worktree_prune
388
- command('worktree', ['prune'])
389
+ command('worktree', 'prune')
389
390
  end
390
391
 
391
392
  def list_files(ref_dir)
@@ -400,7 +401,7 @@ module Git
400
401
  end
401
402
 
402
403
  def branch_contains(commit, branch_name="")
403
- command("branch", [branch_name, "--contains", commit])
404
+ command("branch", branch_name, "--contains", commit)
404
405
  end
405
406
 
406
407
  # returns hash
@@ -412,13 +413,15 @@ module Git
412
413
  grep_opts = ['-n']
413
414
  grep_opts << '-i' if opts[:ignore_case]
414
415
  grep_opts << '-v' if opts[:invert_match]
416
+ grep_opts << '-E' if opts[:extended_regexp]
415
417
  grep_opts << '-e'
416
418
  grep_opts << string
417
419
  grep_opts << opts[:object] if opts[:object].is_a?(String)
418
- grep_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
420
+ grep_opts.push('--', opts[:path_limiter]) if opts[:path_limiter].is_a?(String)
421
+ grep_opts.push('--', *opts[:path_limiter]) if opts[:path_limiter].is_a?(Array)
419
422
 
420
423
  hsh = {}
421
- command_lines('grep', grep_opts).each do |line|
424
+ command_lines('grep', *grep_opts).each do |line|
422
425
  if m = /(.*?)\:(\d+)\:(.*)/.match(line)
423
426
  hsh[m[1]] ||= []
424
427
  hsh[m[1]] << [m[2].to_i, m[3]]
@@ -433,7 +436,7 @@ module Git
433
436
  diff_opts << obj2 if obj2.is_a?(String)
434
437
  diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
435
438
 
436
- command('diff', diff_opts)
439
+ command('diff', *diff_opts)
437
440
  end
438
441
 
439
442
  def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
@@ -444,7 +447,7 @@ module Git
444
447
 
445
448
  hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
446
449
 
447
- command_lines('diff', diff_opts).each do |file|
450
+ command_lines('diff', *diff_opts).each do |file|
448
451
  (insertions, deletions, filename) = file.split("\t")
449
452
  hsh[:total][:insertions] += insertions.to_i
450
453
  hsh[:total][:deletions] += deletions.to_i
@@ -463,7 +466,7 @@ module Git
463
466
 
464
467
  opts_arr << '--' << opts[:path] if opts[:path]
465
468
 
466
- command_lines('diff', opts_arr).inject({}) do |memo, line|
469
+ command_lines('diff', *opts_arr).inject({}) do |memo, line|
467
470
  status, path = line.split("\t")
468
471
  memo[path] = status
469
472
  memo
@@ -496,11 +499,11 @@ module Git
496
499
 
497
500
  def ls_remote(location=nil, opts={})
498
501
  arr_opts = []
499
- arr_opts << ['--refs'] if opts[:refs]
502
+ arr_opts << '--refs' if opts[:refs]
500
503
  arr_opts << (location || '.')
501
504
 
502
505
  Hash.new{ |h,k| h[k] = {} }.tap do |hsh|
503
- command_lines('ls-remote', arr_opts).each do |line|
506
+ command_lines('ls-remote', *arr_opts).each do |line|
504
507
  (sha, info) = line.split("\t")
505
508
  (ref, type, name) = info.split('/', 3)
506
509
  type ||= 'head'
@@ -581,7 +584,7 @@ module Git
581
584
 
582
585
  arr_opts << (path ? "#{objectish}:#{path}" : objectish)
583
586
 
584
- command('show', arr_opts.compact, chomp: false)
587
+ command('show', *arr_opts.compact, chomp: false)
585
588
  end
586
589
 
587
590
  ## WRITE COMMANDS ##
@@ -622,7 +625,7 @@ module Git
622
625
 
623
626
  arr_opts.flatten!
624
627
 
625
- command('add', arr_opts)
628
+ command('add', *arr_opts)
626
629
  end
627
630
 
628
631
  def remove(path = '.', opts = {})
@@ -636,7 +639,7 @@ module Git
636
639
  arr_opts << path
637
640
  end
638
641
 
639
- command('rm', arr_opts)
642
+ command('rm', *arr_opts)
640
643
  end
641
644
 
642
645
  # Takes the commit message with the options and executes the commit command
@@ -678,14 +681,14 @@ module Git
678
681
  arr_opts << '--no-gpg-sign'
679
682
  end
680
683
 
681
- command('commit', arr_opts)
684
+ command('commit', *arr_opts)
682
685
  end
683
686
 
684
687
  def reset(commit, opts = {})
685
688
  arr_opts = []
686
689
  arr_opts << '--hard' if opts[:hard]
687
690
  arr_opts << commit if commit
688
- command('reset', arr_opts)
691
+ command('reset', *arr_opts)
689
692
  end
690
693
 
691
694
  def clean(opts = {})
@@ -695,7 +698,7 @@ module Git
695
698
  arr_opts << '-d' if opts[:d]
696
699
  arr_opts << '-x' if opts[:x]
697
700
 
698
- command('clean', arr_opts)
701
+ command('clean', *arr_opts)
699
702
  end
700
703
 
701
704
  def revert(commitish, opts = {})
@@ -706,19 +709,19 @@ module Git
706
709
  arr_opts << '--no-edit' if opts[:no_edit]
707
710
  arr_opts << commitish
708
711
 
709
- command('revert', arr_opts)
712
+ command('revert', *arr_opts)
710
713
  end
711
714
 
712
715
  def apply(patch_file)
713
716
  arr_opts = []
714
717
  arr_opts << '--' << patch_file if patch_file
715
- command('apply', arr_opts)
718
+ command('apply', *arr_opts)
716
719
  end
717
720
 
718
721
  def apply_mail(patch_file)
719
722
  arr_opts = []
720
723
  arr_opts << '--' << patch_file if patch_file
721
- command('am', arr_opts)
724
+ command('am', *arr_opts)
722
725
  end
723
726
 
724
727
  def stashes_all
@@ -736,24 +739,24 @@ module Git
736
739
  end
737
740
 
738
741
  def stash_save(message)
739
- output = command('stash save', message)
742
+ output = command('stash', 'save', message)
740
743
  output =~ /HEAD is now at/
741
744
  end
742
745
 
743
746
  def stash_apply(id = nil)
744
747
  if id
745
- command('stash apply', id)
748
+ command('stash', 'apply', id)
746
749
  else
747
- command('stash apply')
750
+ command('stash', 'apply')
748
751
  end
749
752
  end
750
753
 
751
754
  def stash_clear
752
- command('stash clear')
755
+ command('stash', 'clear')
753
756
  end
754
757
 
755
758
  def stash_list
756
- command('stash list')
759
+ command('stash', 'list')
757
760
  end
758
761
 
759
762
  def branch_new(branch)
@@ -780,14 +783,14 @@ module Git
780
783
  arr_opts << branch
781
784
  arr_opts << opts[:start_point] if opts[:start_point] && arr_opts.include?('-b')
782
785
 
783
- command('checkout', arr_opts)
786
+ command('checkout', *arr_opts)
784
787
  end
785
788
 
786
789
  def checkout_file(version, file)
787
790
  arr_opts = []
788
791
  arr_opts << version
789
792
  arr_opts << file
790
- command('checkout', arr_opts)
793
+ command('checkout', *arr_opts)
791
794
  end
792
795
 
793
796
  def merge(branch, message = nil, opts = {})
@@ -795,8 +798,8 @@ module Git
795
798
  arr_opts << '--no-commit' if opts[:no_commit]
796
799
  arr_opts << '--no-ff' if opts[:no_ff]
797
800
  arr_opts << '-m' << message if message
798
- arr_opts += [branch]
799
- command('merge', arr_opts)
801
+ arr_opts += Array(branch)
802
+ command('merge', *arr_opts)
800
803
  end
801
804
 
802
805
  def merge_base(*args)
@@ -811,7 +814,7 @@ module Git
811
814
 
812
815
  arg_opts += args
813
816
 
814
- command('merge-base', arg_opts).lines.map(&:strip)
817
+ command('merge-base', *arg_opts).lines.map(&:strip)
815
818
  end
816
819
 
817
820
  def unmerged
@@ -845,7 +848,7 @@ module Git
845
848
  arr_opts << name
846
849
  arr_opts << url
847
850
 
848
- command('remote', arr_opts)
851
+ command('remote', *arr_opts)
849
852
  end
850
853
 
851
854
  def remote_set_url(name, url)
@@ -853,7 +856,7 @@ module Git
853
856
  arr_opts << name
854
857
  arr_opts << url
855
858
 
856
- command('remote', arr_opts)
859
+ command('remote', *arr_opts)
857
860
  end
858
861
 
859
862
  def remote_remove(name)
@@ -890,7 +893,7 @@ module Git
890
893
  arr_opts << '-m' << (opts[:m] || opts[:message])
891
894
  end
892
895
 
893
- command('tag', arr_opts)
896
+ command('tag', *arr_opts)
894
897
  end
895
898
 
896
899
  def fetch(remote, opts)
@@ -906,7 +909,7 @@ module Git
906
909
  arr_opts << remote if remote
907
910
  arr_opts << opts[:ref] if opts[:ref]
908
911
 
909
- command('fetch', arr_opts)
912
+ command('fetch', *arr_opts)
910
913
  end
911
914
 
912
915
  def push(remote, branch = 'master', opts = {})
@@ -920,10 +923,10 @@ module Git
920
923
  arr_opts << remote
921
924
 
922
925
  if opts[:mirror]
923
- command('push', arr_opts)
926
+ command('push', *arr_opts)
924
927
  else
925
- command('push', arr_opts + [branch])
926
- command('push', ['--tags'] + arr_opts) if opts[:tags]
928
+ command('push', *arr_opts, branch)
929
+ command('push', '--tags', *arr_opts) if opts[:tags]
927
930
  end
928
931
  end
929
932
 
@@ -951,7 +954,7 @@ module Git
951
954
  arr_opts = []
952
955
  arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
953
956
  arr_opts += [treeish]
954
- command('read-tree', arr_opts)
957
+ command('read-tree', *arr_opts)
955
958
  end
956
959
 
957
960
  def write_tree
@@ -968,7 +971,7 @@ module Git
968
971
  arr_opts << tree
969
972
  arr_opts << '-p' << opts[:parent] if opts[:parent]
970
973
  arr_opts += [opts[:parents]].map { |p| ['-p', p] }.flatten if opts[:parents]
971
- command('commit-tree', arr_opts, redirect: "< #{escape t.path}")
974
+ command('commit-tree', *arr_opts, redirect: "< #{escape t.path}")
972
975
  end
973
976
 
974
977
  def update_ref(branch, commit)
@@ -982,7 +985,7 @@ module Git
982
985
  arr_opts << "--all" if opts[:all]
983
986
  arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
984
987
 
985
- command('checkout-index', arr_opts)
988
+ command('checkout-index', *arr_opts)
986
989
  end
987
990
 
988
991
  # creates an archive file
@@ -1014,7 +1017,7 @@ module Git
1014
1017
  arr_opts << "--remote=#{opts[:remote]}" if opts[:remote]
1015
1018
  arr_opts << sha
1016
1019
  arr_opts << '--' << opts[:path] if opts[:path]
1017
- command('archive', arr_opts, redirect: " > #{escape file}")
1020
+ command('archive', *arr_opts, redirect: " > #{escape file}")
1018
1021
  if opts[:add_gzip]
1019
1022
  file_content = File.read(file)
1020
1023
  Zlib::GzipWriter.open(file) do |gz|
@@ -1103,52 +1106,46 @@ module Git
1103
1106
  restore_git_system_env_variables()
1104
1107
  end
1105
1108
 
1106
- def command(cmd, *opts, &block)
1109
+ def command(*cmd, redirect: '', chomp: true, &block)
1107
1110
  Git::Lib.warn_if_old_command(self)
1108
1111
 
1109
- command_opts = { chomp: true, redirect: '' }
1110
- if opts.last.is_a?(Hash)
1111
- command_opts.merge!(opts.pop)
1112
- end
1113
- command_opts.keys.each do |k|
1114
- raise ArgumentError.new("Unsupported option: #{k}") unless [:chomp, :redirect].include?(k)
1115
- end
1112
+ raise 'cmd can not include a nested array' if cmd.any? { |o| o.is_a? Array }
1116
1113
 
1117
1114
  global_opts = []
1118
1115
  global_opts << "--git-dir=#{@git_dir}" if !@git_dir.nil?
1119
1116
  global_opts << "--work-tree=#{@git_work_dir}" if !@git_work_dir.nil?
1120
- global_opts << %w[-c core.quotePath=true]
1121
- global_opts << %w[-c color.ui=false]
1117
+ global_opts << '-c' << 'core.quotePath=true'
1118
+ global_opts << '-c' << 'color.ui=false'
1122
1119
 
1123
- opts = [opts].flatten.map {|s| escape(s) }.join(' ')
1120
+ escaped_cmd = cmd.map { |part| escape(part) }.join(' ')
1124
1121
 
1125
- global_opts = global_opts.flatten.map {|s| escape(s) }.join(' ')
1122
+ global_opts = global_opts.map { |s| escape(s) }.join(' ')
1126
1123
 
1127
- git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{cmd} #{opts} #{command_opts[:redirect]} 2>&1"
1124
+ git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{escaped_cmd} #{redirect} 2>&1"
1128
1125
 
1129
1126
  output = nil
1130
1127
 
1131
1128
  command_thread = nil;
1132
1129
 
1133
- exitstatus = nil
1130
+ status = nil
1134
1131
 
1135
1132
  with_custom_env_variables do
1136
1133
  command_thread = Thread.new do
1137
1134
  output = run_command(git_cmd, &block)
1138
- exitstatus = $?.exitstatus
1135
+ status = $?
1139
1136
  end
1140
1137
  command_thread.join
1141
1138
  end
1142
1139
 
1143
- if @logger
1144
- @logger.info(git_cmd)
1145
- @logger.debug(output)
1146
- end
1140
+ @logger.info(git_cmd)
1141
+ @logger.debug(output)
1147
1142
 
1148
- raise Git::GitExecuteError, "#{git_cmd}:#{output}" if
1149
- exitstatus > 1 || (exitstatus == 1 && output != '')
1143
+ if status.exitstatus > 1 || (status.exitstatus == 1 && output != '')
1144
+ result = Git::CommandLineResult.new(git_cmd, status, output, '')
1145
+ raise Git::FailedError.new(result)
1146
+ end
1150
1147
 
1151
- output.chomp! if output && command_opts[:chomp] && !block_given?
1148
+ output.chomp! if output && chomp && !block_given?
1152
1149
 
1153
1150
  output
1154
1151
  end
@@ -1161,7 +1158,7 @@ module Git
1161
1158
  def diff_as_hash(diff_command, opts=[])
1162
1159
  # update index before diffing to avoid spurious diffs
1163
1160
  command('status')
1164
- command_lines(diff_command, opts).inject({}) do |memo, line|
1161
+ command_lines(diff_command, *opts).inject({}) do |memo, line|
1165
1162
  info, file = line.split("\t")
1166
1163
  mode_src, mode_dest, sha_src, sha_dest, type = info.split
1167
1164
 
@@ -1205,7 +1202,10 @@ module Git
1205
1202
  arr_opts = []
1206
1203
 
1207
1204
  arr_opts << opts[:object] if opts[:object].is_a? String
1208
- arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter]
1205
+ if opts[:path_limiter]
1206
+ arr_opts << '--'
1207
+ arr_opts += Array(opts[:path_limiter])
1208
+ end
1209
1209
  arr_opts
1210
1210
  end
1211
1211
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git/git_execute_error'
4
+
5
+ module Git
6
+ # This error is raised when a git command exits because of an uncaught signal
7
+ #
8
+ # The git command executed, status, stdout, and stderr are available from this
9
+ # object. The #message includes the git command, the status of the process, and
10
+ # the stderr of the process.
11
+ #
12
+ # @api public
13
+ #
14
+ class SignaledError < Git::GitExecuteError
15
+ # Create a SignaledError object
16
+ #
17
+ # @example
18
+ # `kill -9 $$` # set $? appropriately for this example
19
+ # result = Git::CommandLineResult.new(%w[git status], $?, '', "killed")
20
+ # error = Git::SignaledError.new(result)
21
+ # error.message #=>
22
+ # "[\"git\", \"status\"]\nstatus: pid 88811 SIGKILL (signal 9)\nstderr: \"killed\""
23
+ #
24
+ # @param result [Git::CommandLineResult] the result of the git command including the git command, status, stdout, and stderr
25
+ #
26
+ def initialize(result)
27
+ super("#{result.git_cmd}\nstatus: #{result.status}\nstderr: #{result.stderr.inspect}")
28
+ @result = result
29
+ end
30
+
31
+ # @attribute [r] result
32
+ #
33
+ # The result of the git command including the git command, status, and output
34
+ #
35
+ # @example
36
+ # `kill -9 $$` # set $? appropriately for this example
37
+ # result = Git::CommandLineResult.new(%w[git status], $?, '', "killed")
38
+ # error = Git::SignaledError.new(result)
39
+ # error.result #=>
40
+ # #<Git::CommandLineResult:0x000000010470f6e8
41
+ # @git_cmd=["git", "status"],
42
+ # @status=#<Process::Status: pid 88811 SIGKILL (signal 9)>,
43
+ # @stderr="killed",
44
+ # @stdout="">
45
+ #
46
+ # @return [Git::CommandLineResult]
47
+ #
48
+ attr_reader :result
49
+ end
50
+ end
data/lib/git/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Git
2
2
  # The current gem version
3
3
  # @return [String] the current gem version.
4
- VERSION='1.13.1'
4
+ VERSION='1.14.0'
5
5
  end
data/lib/git.rb CHANGED
@@ -7,10 +7,13 @@ require 'git/author'
7
7
  require 'git/base'
8
8
  require 'git/branch'
9
9
  require 'git/branches'
10
+ require 'git/command_line_result'
10
11
  require 'git/config'
11
12
  require 'git/diff'
12
13
  require 'git/encoding_utils'
13
14
  require 'git/escaped_path'
15
+ require 'git/failed_error'
16
+ require 'git/git_execute_error'
14
17
  require 'git/index'
15
18
  require 'git/lib'
16
19
  require 'git/log'
@@ -18,6 +21,7 @@ require 'git/object'
18
21
  require 'git/path'
19
22
  require 'git/remote'
20
23
  require 'git/repository'
24
+ require 'git/signaled_error'
21
25
  require 'git/status'
22
26
  require 'git/stash'
23
27
  require 'git/stashes'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.1
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon and others
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-12 00:00:00.000000000 Z
11
+ date: 2023-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -189,10 +189,13 @@ files:
189
189
  - lib/git/base/factory.rb
190
190
  - lib/git/branch.rb
191
191
  - lib/git/branches.rb
192
+ - lib/git/command_line_result.rb
192
193
  - lib/git/config.rb
193
194
  - lib/git/diff.rb
194
195
  - lib/git/encoding_utils.rb
195
196
  - lib/git/escaped_path.rb
197
+ - lib/git/failed_error.rb
198
+ - lib/git/git_execute_error.rb
196
199
  - lib/git/index.rb
197
200
  - lib/git/lib.rb
198
201
  - lib/git/log.rb
@@ -200,6 +203,7 @@ files:
200
203
  - lib/git/path.rb
201
204
  - lib/git/remote.rb
202
205
  - lib/git/repository.rb
206
+ - lib/git/signaled_error.rb
203
207
  - lib/git/stash.rb
204
208
  - lib/git/stashes.rb
205
209
  - lib/git/status.rb
@@ -231,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
235
  version: '0'
232
236
  requirements:
233
237
  - git 1.6.0.0, or greater
234
- rubygems_version: 3.3.26
238
+ rubygems_version: 3.4.1
235
239
  signing_key:
236
240
  specification_version: 4
237
241
  summary: An API to create, read, and manipulate Git repositories