git 1.13.2 → 1.15.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: 29b8c6b76f613f41bcddf2786fe9b164ef2168f265f3b8fdccb9f8f4ead52669
4
- data.tar.gz: b0f66b11fd1a2eba3640bfa42ff842dcfbd52ab30455026b97ebecad8fd86f0c
3
+ metadata.gz: 8a3877a2258c4835e6adc9ad9844f89eeaf340bf1ad7a47937178fc4abe4bfae
4
+ data.tar.gz: 4bc93c337d92610aa46c7265fb03cfff12ca62d23fcfe67488e5ffaf0dd171cb
5
5
  SHA512:
6
- metadata.gz: bb85d50e45a905b7e71617da29f6194e478b17aed237237e0dd53066a5182c328d4e992494a3b7d26df47223c0e601733400e62d04b7e9fffdf8993c22cd2fb5
7
- data.tar.gz: ee9d9edbd87615caee4cc073acd2df9a047b46d5ba117997f193a98d28374d214e2994018d3bed10c0e4acad7cd913ba39da25ecc2b0fd973863930f19d0f129
6
+ metadata.gz: 89caa1ce17512244548e72fcac709390c8017601e7699d6355939d613c8cba973c5309c733d4071d5db356d93f9fe37b42e3ca48862e759c00fdbf85b55eb51f
7
+ data.tar.gz: fff185e87d3925baed674a81b3501dba49a9e9c8af1e1f99fdb27645c83a5a22e820001ab46a49a71e703b0dcb741d5a6aa8baeddf2dd4c39fa6199443a8190e
data/CHANGELOG.md CHANGED
@@ -5,6 +5,34 @@
5
5
 
6
6
  # Change Log
7
7
 
8
+ ## v1.15.0 (2023-03-01)
9
+
10
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.14.0..v1.15.0)
11
+
12
+ Changes since v1.14.0:
13
+
14
+ * b40d #pull with no options should do the same thing as `git pull` with no options (#633)
15
+ * 9c5e Fix error when calling `Git::Lib#remove` with `recursive` or `cached` options (#632)
16
+ * 806e Add Git::Log#all option (#630)
17
+ * d905 Allow a repo to be opened giving a non-root repo directory (#629)
18
+ * 1ccd Rewrite worktree tests (#628)
19
+ * 4409 Fix Git::Branch#update_ref (#626)
20
+
21
+ ## v1.14.0 (2023-02-25)
22
+
23
+ [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.13.2..v1.14.0)
24
+
25
+ Changes since v1.13.2:
26
+
27
+ * 0f7c4a5 Allow the use of an array of path_limiters and add extended_regexp option to grep (#624)
28
+ * 8992701 Refactor error thrown when a git command fails (#622)
29
+ * cf74b91 Simplify how temp files are used when testing Git::Base#archive (#621)
30
+ * a8bfb9d Set init.defaultBranch when running tests if it is not already set (#620)
31
+ * 9ee7ca9 Create a null logger if a logger is not provided (#619)
32
+ * 872de4c Internal refactor of Git::Lib command (#618)
33
+ * 29e157d Simplify test running and fixture repo cloning (#615)
34
+ * 08d04ef Use dynamically-created repo for signed commits test (#614)
35
+
8
36
  ## v1.13.2 (2023-02-02)
9
37
 
10
38
  [Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.13.1..v1.13.2)
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/README.md CHANGED
@@ -66,6 +66,10 @@ like:
66
66
 
67
67
  `@git.log(20).object("some_file").since("2 weeks ago").between('v2.6', 'v2.7').each { |commit| [block] }`
68
68
 
69
+ Pass the `--all` option to `git log` as follows:
70
+
71
+ `@git.log.all.each { |commit| [block] }`
72
+
69
73
  **Git::Worktrees** - Enumerable object that holds `Git::Worktree objects`.
70
74
 
71
75
  ## Examples
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.
@@ -57,9 +58,26 @@ module Git
57
58
  self.new(options)
58
59
  end
59
60
 
61
+ def self.root_of_worktree(working_dir)
62
+ result = working_dir
63
+ status = nil
64
+ Dir.chdir(working_dir) do
65
+ git_cmd = "#{Git::Base.config.binary_path} -c core.quotePath=true -c color.ui=false rev-parse --show-toplevel 2>&1"
66
+ result = `#{git_cmd}`.chomp
67
+ status = $?
68
+ end
69
+ raise ArgumentError, "'#{working_dir}' is not in a git working tree" unless status.success?
70
+ result
71
+ end
72
+
60
73
  # (see Git.open)
61
74
  def self.open(working_dir, options = {})
75
+ raise ArgumentError, "'#{working_dir}' is not a directory" unless Dir.exist?(working_dir)
76
+
77
+ working_dir = root_of_worktree(working_dir) unless options[:repository]
78
+
62
79
  normalize_paths(options, default_working_directory: working_dir)
80
+
63
81
  self.new(options)
64
82
  end
65
83
 
@@ -90,12 +108,8 @@ module Git
90
108
  options[:repository] ||= File.join(working_dir, '.git')
91
109
  options[:index] ||= File.join(options[:repository], 'index')
92
110
  end
93
- if options[:log]
94
- @logger = options[:log]
95
- @logger.info("Starting Git")
96
- else
97
- @logger = nil
98
- end
111
+ @logger = (options[:log] || Logger.new(nil))
112
+ @logger.info("Starting Git")
99
113
 
100
114
  @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
101
115
  @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
@@ -212,6 +226,15 @@ module Git
212
226
  # end
213
227
  # end
214
228
  #
229
+ # @param string [String] the string to search for
230
+ # @param path_limiter [String, Array] a path or array of paths to limit the search to or nil for no limit
231
+ # @param opts [Hash] options to pass to the underlying `git grep` command
232
+ #
233
+ # @option opts [Boolean] :ignore_case (false) ignore case when matching
234
+ # @option opts [Boolean] :invert_match (false) select non-matching lines
235
+ # @option opts [Boolean] :extended_regexp (false) use extended regular expressions
236
+ # @option opts [String] :object (HEAD) the object to search from
237
+ #
215
238
  # @return [Hash<String, Array>] a hash of arrays
216
239
  # ```Ruby
217
240
  # {
@@ -249,10 +272,12 @@ module Git
249
272
  end
250
273
 
251
274
  # removes file(s) from the git repository
252
- def remove(path = '.', opts = {})
253
- self.lib.remove(path, opts)
275
+ def rm(path = '.', opts = {})
276
+ self.lib.rm(path, opts)
254
277
  end
255
278
 
279
+ alias remove rm
280
+
256
281
  # resets the working directory to the provided commitish
257
282
  def reset(commitish = nil, opts = {})
258
283
  self.lib.reset(commitish, opts)
@@ -374,7 +399,7 @@ module Git
374
399
  # @git.pull('upstream') # pulls from upstream/master
375
400
  # @git.pull('upstream', 'develope') # pulls from upstream/develop
376
401
  #
377
- def pull(remote='origin', branch='master')
402
+ def pull(remote = nil, branch = nil)
378
403
  self.lib.pull(remote, branch)
379
404
  end
380
405
 
data/lib/git/branch.rb CHANGED
@@ -78,7 +78,11 @@ module Git
78
78
  end
79
79
 
80
80
  def update_ref(commit)
81
- @base.lib.update_ref(@full, commit)
81
+ if @remote
82
+ @base.lib.update_ref("refs/remotes/#{@remote.name}/#{@name}", commit)
83
+ else
84
+ @base.lib.update_ref("refs/heads/#{@name}", commit)
85
+ end
82
86
  end
83
87
 
84
88
  def to_a
@@ -114,7 +118,7 @@ module Git
114
118
  # param [String] name branch full name.
115
119
  # return [<Git::Remote,NilClass,String>] an Array containing the remote and branch names.
116
120
  def parse_name(name)
117
- if name.match(/^(?:remotes)?\/([^\/]+)\/(.+)/)
121
+ if name.match(/^(?:remotes\/)?([^\/]+)\/(.+)/)
118
122
  return [Git::Remote.new(@base, $1), $2]
119
123
  end
120
124
 
@@ -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
@@ -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
@@ -370,7 +368,7 @@ module Git
370
368
  # HEAD b8c63206f8d10f57892060375a86ae911fad356e
371
369
  # detached
372
370
  #
373
- command_lines('worktree',['list', '--porcelain']).each do |w|
371
+ command_lines('worktree', 'list', '--porcelain').each do |w|
374
372
  s = w.split("\s")
375
373
  directory = s[1] if s[0] == 'worktree'
376
374
  arr << [directory, s[1]] if s[0] == 'HEAD'
@@ -379,16 +377,16 @@ module Git
379
377
  end
380
378
 
381
379
  def worktree_add(dir, commitish = nil)
382
- return command('worktree', ['add', dir, commitish]) if !commitish.nil?
383
- command('worktree', ['add', dir])
380
+ return command('worktree', 'add', dir, commitish) if !commitish.nil?
381
+ command('worktree', 'add', dir)
384
382
  end
385
383
 
386
384
  def worktree_remove(dir)
387
- command('worktree', ['remove', dir])
385
+ command('worktree', 'remove', dir)
388
386
  end
389
387
 
390
388
  def worktree_prune
391
- command('worktree', ['prune'])
389
+ command('worktree', 'prune')
392
390
  end
393
391
 
394
392
  def list_files(ref_dir)
@@ -403,7 +401,7 @@ module Git
403
401
  end
404
402
 
405
403
  def branch_contains(commit, branch_name="")
406
- command("branch", [branch_name, "--contains", commit])
404
+ command("branch", branch_name, "--contains", commit)
407
405
  end
408
406
 
409
407
  # returns hash
@@ -415,13 +413,15 @@ module Git
415
413
  grep_opts = ['-n']
416
414
  grep_opts << '-i' if opts[:ignore_case]
417
415
  grep_opts << '-v' if opts[:invert_match]
416
+ grep_opts << '-E' if opts[:extended_regexp]
418
417
  grep_opts << '-e'
419
418
  grep_opts << string
420
419
  grep_opts << opts[:object] if opts[:object].is_a?(String)
421
- 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)
422
422
 
423
423
  hsh = {}
424
- command_lines('grep', grep_opts).each do |line|
424
+ command_lines('grep', *grep_opts).each do |line|
425
425
  if m = /(.*?)\:(\d+)\:(.*)/.match(line)
426
426
  hsh[m[1]] ||= []
427
427
  hsh[m[1]] << [m[2].to_i, m[3]]
@@ -436,7 +436,7 @@ module Git
436
436
  diff_opts << obj2 if obj2.is_a?(String)
437
437
  diff_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
438
438
 
439
- command('diff', diff_opts)
439
+ command('diff', *diff_opts)
440
440
  end
441
441
 
442
442
  def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
@@ -447,7 +447,7 @@ module Git
447
447
 
448
448
  hsh = {:total => {:insertions => 0, :deletions => 0, :lines => 0, :files => 0}, :files => {}}
449
449
 
450
- command_lines('diff', diff_opts).each do |file|
450
+ command_lines('diff', *diff_opts).each do |file|
451
451
  (insertions, deletions, filename) = file.split("\t")
452
452
  hsh[:total][:insertions] += insertions.to_i
453
453
  hsh[:total][:deletions] += deletions.to_i
@@ -466,7 +466,7 @@ module Git
466
466
 
467
467
  opts_arr << '--' << opts[:path] if opts[:path]
468
468
 
469
- command_lines('diff', opts_arr).inject({}) do |memo, line|
469
+ command_lines('diff', *opts_arr).inject({}) do |memo, line|
470
470
  status, path = line.split("\t")
471
471
  memo[path] = status
472
472
  memo
@@ -499,11 +499,11 @@ module Git
499
499
 
500
500
  def ls_remote(location=nil, opts={})
501
501
  arr_opts = []
502
- arr_opts << ['--refs'] if opts[:refs]
502
+ arr_opts << '--refs' if opts[:refs]
503
503
  arr_opts << (location || '.')
504
504
 
505
505
  Hash.new{ |h,k| h[k] = {} }.tap do |hsh|
506
- command_lines('ls-remote', arr_opts).each do |line|
506
+ command_lines('ls-remote', *arr_opts).each do |line|
507
507
  (sha, info) = line.split("\t")
508
508
  (ref, type, name) = info.split('/', 3)
509
509
  type ||= 'head'
@@ -584,7 +584,7 @@ module Git
584
584
 
585
585
  arr_opts << (path ? "#{objectish}:#{path}" : objectish)
586
586
 
587
- command('show', arr_opts.compact, chomp: false)
587
+ command('show', *arr_opts.compact, chomp: false)
588
588
  end
589
589
 
590
590
  ## WRITE COMMANDS ##
@@ -625,21 +625,17 @@ module Git
625
625
 
626
626
  arr_opts.flatten!
627
627
 
628
- command('add', arr_opts)
628
+ command('add', *arr_opts)
629
629
  end
630
630
 
631
- def remove(path = '.', opts = {})
631
+ def rm(path = '.', opts = {})
632
632
  arr_opts = ['-f'] # overrides the up-to-date check by default
633
- arr_opts << ['-r'] if opts[:recursive]
634
- arr_opts << ['--cached'] if opts[:cached]
633
+ arr_opts << '-r' if opts[:recursive]
634
+ arr_opts << '--cached' if opts[:cached]
635
635
  arr_opts << '--'
636
- if path.is_a?(Array)
637
- arr_opts += path
638
- else
639
- arr_opts << path
640
- end
636
+ arr_opts += Array(path)
641
637
 
642
- command('rm', arr_opts)
638
+ command('rm', *arr_opts)
643
639
  end
644
640
 
645
641
  # Takes the commit message with the options and executes the commit command
@@ -681,14 +677,14 @@ module Git
681
677
  arr_opts << '--no-gpg-sign'
682
678
  end
683
679
 
684
- command('commit', arr_opts)
680
+ command('commit', *arr_opts)
685
681
  end
686
682
 
687
683
  def reset(commit, opts = {})
688
684
  arr_opts = []
689
685
  arr_opts << '--hard' if opts[:hard]
690
686
  arr_opts << commit if commit
691
- command('reset', arr_opts)
687
+ command('reset', *arr_opts)
692
688
  end
693
689
 
694
690
  def clean(opts = {})
@@ -698,7 +694,7 @@ module Git
698
694
  arr_opts << '-d' if opts[:d]
699
695
  arr_opts << '-x' if opts[:x]
700
696
 
701
- command('clean', arr_opts)
697
+ command('clean', *arr_opts)
702
698
  end
703
699
 
704
700
  def revert(commitish, opts = {})
@@ -709,19 +705,19 @@ module Git
709
705
  arr_opts << '--no-edit' if opts[:no_edit]
710
706
  arr_opts << commitish
711
707
 
712
- command('revert', arr_opts)
708
+ command('revert', *arr_opts)
713
709
  end
714
710
 
715
711
  def apply(patch_file)
716
712
  arr_opts = []
717
713
  arr_opts << '--' << patch_file if patch_file
718
- command('apply', arr_opts)
714
+ command('apply', *arr_opts)
719
715
  end
720
716
 
721
717
  def apply_mail(patch_file)
722
718
  arr_opts = []
723
719
  arr_opts << '--' << patch_file if patch_file
724
- command('am', arr_opts)
720
+ command('am', *arr_opts)
725
721
  end
726
722
 
727
723
  def stashes_all
@@ -739,24 +735,24 @@ module Git
739
735
  end
740
736
 
741
737
  def stash_save(message)
742
- output = command('stash save', message)
738
+ output = command('stash', 'save', message)
743
739
  output =~ /HEAD is now at/
744
740
  end
745
741
 
746
742
  def stash_apply(id = nil)
747
743
  if id
748
- command('stash apply', id)
744
+ command('stash', 'apply', id)
749
745
  else
750
- command('stash apply')
746
+ command('stash', 'apply')
751
747
  end
752
748
  end
753
749
 
754
750
  def stash_clear
755
- command('stash clear')
751
+ command('stash', 'clear')
756
752
  end
757
753
 
758
754
  def stash_list
759
- command('stash list')
755
+ command('stash', 'list')
760
756
  end
761
757
 
762
758
  def branch_new(branch)
@@ -783,14 +779,14 @@ module Git
783
779
  arr_opts << branch
784
780
  arr_opts << opts[:start_point] if opts[:start_point] && arr_opts.include?('-b')
785
781
 
786
- command('checkout', arr_opts)
782
+ command('checkout', *arr_opts)
787
783
  end
788
784
 
789
785
  def checkout_file(version, file)
790
786
  arr_opts = []
791
787
  arr_opts << version
792
788
  arr_opts << file
793
- command('checkout', arr_opts)
789
+ command('checkout', *arr_opts)
794
790
  end
795
791
 
796
792
  def merge(branch, message = nil, opts = {})
@@ -798,8 +794,8 @@ module Git
798
794
  arr_opts << '--no-commit' if opts[:no_commit]
799
795
  arr_opts << '--no-ff' if opts[:no_ff]
800
796
  arr_opts << '-m' << message if message
801
- arr_opts += [branch]
802
- command('merge', arr_opts)
797
+ arr_opts += Array(branch)
798
+ command('merge', *arr_opts)
803
799
  end
804
800
 
805
801
  def merge_base(*args)
@@ -814,7 +810,7 @@ module Git
814
810
 
815
811
  arg_opts += args
816
812
 
817
- command('merge-base', arg_opts).lines.map(&:strip)
813
+ command('merge-base', *arg_opts).lines.map(&:strip)
818
814
  end
819
815
 
820
816
  def unmerged
@@ -848,7 +844,7 @@ module Git
848
844
  arr_opts << name
849
845
  arr_opts << url
850
846
 
851
- command('remote', arr_opts)
847
+ command('remote', *arr_opts)
852
848
  end
853
849
 
854
850
  def remote_set_url(name, url)
@@ -856,7 +852,7 @@ module Git
856
852
  arr_opts << name
857
853
  arr_opts << url
858
854
 
859
- command('remote', arr_opts)
855
+ command('remote', *arr_opts)
860
856
  end
861
857
 
862
858
  def remote_remove(name)
@@ -893,7 +889,7 @@ module Git
893
889
  arr_opts << '-m' << (opts[:m] || opts[:message])
894
890
  end
895
891
 
896
- command('tag', arr_opts)
892
+ command('tag', *arr_opts)
897
893
  end
898
894
 
899
895
  def fetch(remote, opts)
@@ -909,7 +905,7 @@ module Git
909
905
  arr_opts << remote if remote
910
906
  arr_opts << opts[:ref] if opts[:ref]
911
907
 
912
- command('fetch', arr_opts)
908
+ command('fetch', *arr_opts)
913
909
  end
914
910
 
915
911
  def push(remote, branch = 'master', opts = {})
@@ -923,15 +919,20 @@ module Git
923
919
  arr_opts << remote
924
920
 
925
921
  if opts[:mirror]
926
- command('push', arr_opts)
922
+ command('push', *arr_opts)
927
923
  else
928
- command('push', arr_opts + [branch])
929
- command('push', ['--tags'] + arr_opts) if opts[:tags]
924
+ command('push', *arr_opts, branch)
925
+ command('push', '--tags', *arr_opts) if opts[:tags]
930
926
  end
931
927
  end
932
928
 
933
- def pull(remote='origin', branch='master')
934
- command('pull', remote, branch)
929
+ def pull(remote = nil, branch = nil)
930
+ raise ArgumentError, "You must specify a remote if a branch is specified" if remote.nil? && !branch.nil?
931
+
932
+ arr_opts = []
933
+ arr_opts << remote if remote
934
+ arr_opts << branch if branch
935
+ command('pull', *arr_opts)
935
936
  end
936
937
 
937
938
  def tag_sha(tag_name)
@@ -954,7 +955,7 @@ module Git
954
955
  arr_opts = []
955
956
  arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
956
957
  arr_opts += [treeish]
957
- command('read-tree', arr_opts)
958
+ command('read-tree', *arr_opts)
958
959
  end
959
960
 
960
961
  def write_tree
@@ -971,11 +972,11 @@ module Git
971
972
  arr_opts << tree
972
973
  arr_opts << '-p' << opts[:parent] if opts[:parent]
973
974
  arr_opts += [opts[:parents]].map { |p| ['-p', p] }.flatten if opts[:parents]
974
- command('commit-tree', arr_opts, redirect: "< #{escape t.path}")
975
+ command('commit-tree', *arr_opts, redirect: "< #{escape t.path}")
975
976
  end
976
977
 
977
- def update_ref(branch, commit)
978
- command('update-ref', branch, commit)
978
+ def update_ref(ref, commit)
979
+ command('update-ref', ref, commit)
979
980
  end
980
981
 
981
982
  def checkout_index(opts = {})
@@ -985,7 +986,7 @@ module Git
985
986
  arr_opts << "--all" if opts[:all]
986
987
  arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter].is_a? String
987
988
 
988
- command('checkout-index', arr_opts)
989
+ command('checkout-index', *arr_opts)
989
990
  end
990
991
 
991
992
  # creates an archive file
@@ -1017,7 +1018,7 @@ module Git
1017
1018
  arr_opts << "--remote=#{opts[:remote]}" if opts[:remote]
1018
1019
  arr_opts << sha
1019
1020
  arr_opts << '--' << opts[:path] if opts[:path]
1020
- command('archive', arr_opts, redirect: " > #{escape file}")
1021
+ command('archive', *arr_opts, redirect: " > #{escape file}")
1021
1022
  if opts[:add_gzip]
1022
1023
  file_content = File.read(file)
1023
1024
  Zlib::GzipWriter.open(file) do |gz|
@@ -1106,52 +1107,46 @@ module Git
1106
1107
  restore_git_system_env_variables()
1107
1108
  end
1108
1109
 
1109
- def command(cmd, *opts, &block)
1110
+ def command(*cmd, redirect: '', chomp: true, &block)
1110
1111
  Git::Lib.warn_if_old_command(self)
1111
1112
 
1112
- command_opts = { chomp: true, redirect: '' }
1113
- if opts.last.is_a?(Hash)
1114
- command_opts.merge!(opts.pop)
1115
- end
1116
- command_opts.keys.each do |k|
1117
- raise ArgumentError.new("Unsupported option: #{k}") unless [:chomp, :redirect].include?(k)
1118
- end
1113
+ raise 'cmd can not include a nested array' if cmd.any? { |o| o.is_a? Array }
1119
1114
 
1120
1115
  global_opts = []
1121
1116
  global_opts << "--git-dir=#{@git_dir}" if !@git_dir.nil?
1122
1117
  global_opts << "--work-tree=#{@git_work_dir}" if !@git_work_dir.nil?
1123
- global_opts << %w[-c core.quotePath=true]
1124
- global_opts << %w[-c color.ui=false]
1118
+ global_opts << '-c' << 'core.quotePath=true'
1119
+ global_opts << '-c' << 'color.ui=false'
1125
1120
 
1126
- opts = [opts].flatten.map {|s| escape(s) }.join(' ')
1121
+ escaped_cmd = cmd.map { |part| escape(part) }.join(' ')
1127
1122
 
1128
- global_opts = global_opts.flatten.map {|s| escape(s) }.join(' ')
1123
+ global_opts = global_opts.map { |s| escape(s) }.join(' ')
1129
1124
 
1130
- git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{cmd} #{opts} #{command_opts[:redirect]} 2>&1"
1125
+ git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{escaped_cmd} #{redirect} 2>&1"
1131
1126
 
1132
1127
  output = nil
1133
1128
 
1134
1129
  command_thread = nil;
1135
1130
 
1136
- exitstatus = nil
1131
+ status = nil
1137
1132
 
1138
1133
  with_custom_env_variables do
1139
1134
  command_thread = Thread.new do
1140
1135
  output = run_command(git_cmd, &block)
1141
- exitstatus = $?.exitstatus
1136
+ status = $?
1142
1137
  end
1143
1138
  command_thread.join
1144
1139
  end
1145
1140
 
1146
- if @logger
1147
- @logger.info(git_cmd)
1148
- @logger.debug(output)
1149
- end
1141
+ @logger.info(git_cmd)
1142
+ @logger.debug(output)
1150
1143
 
1151
- raise Git::GitExecuteError, "#{git_cmd}:#{output}" if
1152
- exitstatus > 1 || (exitstatus == 1 && output != '')
1144
+ if status.exitstatus > 1 || (status.exitstatus == 1 && output != '')
1145
+ result = Git::CommandLineResult.new(git_cmd, status, output, '')
1146
+ raise Git::FailedError.new(result)
1147
+ end
1153
1148
 
1154
- output.chomp! if output && command_opts[:chomp] && !block_given?
1149
+ output.chomp! if output && chomp && !block_given?
1155
1150
 
1156
1151
  output
1157
1152
  end
@@ -1164,7 +1159,7 @@ module Git
1164
1159
  def diff_as_hash(diff_command, opts=[])
1165
1160
  # update index before diffing to avoid spurious diffs
1166
1161
  command('status')
1167
- command_lines(diff_command, opts).inject({}) do |memo, line|
1162
+ command_lines(diff_command, *opts).inject({}) do |memo, line|
1168
1163
  info, file = line.split("\t")
1169
1164
  mode_src, mode_dest, sha_src, sha_dest, type = info.split
1170
1165
 
@@ -1188,7 +1183,12 @@ module Git
1188
1183
  def log_common_options(opts)
1189
1184
  arr_opts = []
1190
1185
 
1191
- arr_opts << "-#{opts[:count]}" if opts[:count]
1186
+ if opts[:count] && !opts[:count].is_a?(Integer)
1187
+ raise ArgumentError, "The log count option must be an Integer but was #{opts[:count].inspect}"
1188
+ end
1189
+
1190
+ arr_opts << "--max-count=#{opts[:count]}" if opts[:count]
1191
+ arr_opts << "--all" if opts[:all]
1192
1192
  arr_opts << "--no-color"
1193
1193
  arr_opts << "--cherry" if opts[:cherry]
1194
1194
  arr_opts << "--since=#{opts[:since]}" if opts[:since].is_a? String
@@ -1208,7 +1208,10 @@ module Git
1208
1208
  arr_opts = []
1209
1209
 
1210
1210
  arr_opts << opts[:object] if opts[:object].is_a? String
1211
- arr_opts << '--' << opts[:path_limiter] if opts[:path_limiter]
1211
+ if opts[:path_limiter]
1212
+ arr_opts << '--'
1213
+ arr_opts += Array(opts[:path_limiter])
1214
+ end
1212
1215
  arr_opts
1213
1216
  end
1214
1217
 
data/lib/git/log.rb CHANGED
@@ -1,24 +1,19 @@
1
1
  module Git
2
-
2
+
3
3
  # object that holds the last X commits on given branch
4
4
  class Log
5
5
  include Enumerable
6
-
6
+
7
7
  def initialize(base, count = 30)
8
8
  dirty_log
9
9
  @base = base
10
10
  @count = count
11
-
12
- @commits = nil
13
- @author = nil
14
- @grep = nil
15
- @object = nil
16
- @path = nil
17
- @since = nil
18
- @skip = nil
19
- @until = nil
20
- @between = nil
21
- @cherry = nil
11
+ end
12
+
13
+ def all
14
+ dirty_log
15
+ @all = true
16
+ self
22
17
  end
23
18
 
24
19
  def object(objectish)
@@ -32,37 +27,37 @@ module Git
32
27
  @author = regex
33
28
  return self
34
29
  end
35
-
30
+
36
31
  def grep(regex)
37
32
  dirty_log
38
33
  @grep = regex
39
34
  return self
40
35
  end
41
-
36
+
42
37
  def path(path)
43
38
  dirty_log
44
39
  @path = path
45
40
  return self
46
41
  end
47
-
42
+
48
43
  def skip(num)
49
44
  dirty_log
50
45
  @skip = num
51
46
  return self
52
47
  end
53
-
48
+
54
49
  def since(date)
55
50
  dirty_log
56
51
  @since = date
57
52
  return self
58
53
  end
59
-
54
+
60
55
  def until(date)
61
56
  dirty_log
62
57
  @until = date
63
58
  return self
64
59
  end
65
-
60
+
66
61
  def between(sha1, sha2 = nil)
67
62
  dirty_log
68
63
  @between = [sha1, sha2]
@@ -74,24 +69,24 @@ module Git
74
69
  @cherry = true
75
70
  return self
76
71
  end
77
-
72
+
78
73
  def to_s
79
74
  self.map { |c| c.to_s }.join("\n")
80
75
  end
81
-
76
+
82
77
 
83
78
  # forces git log to run
84
-
79
+
85
80
  def size
86
81
  check_log
87
82
  @commits.size rescue nil
88
83
  end
89
-
84
+
90
85
  def each(&block)
91
86
  check_log
92
87
  @commits.each(&block)
93
88
  end
94
-
89
+
95
90
  def first
96
91
  check_log
97
92
  @commits.first rescue nil
@@ -107,29 +102,30 @@ module Git
107
102
  @commits[index] rescue nil
108
103
  end
109
104
 
110
-
111
- private
112
-
105
+
106
+ private
107
+
113
108
  def dirty_log
114
109
  @dirty_flag = true
115
110
  end
116
-
111
+
117
112
  def check_log
118
113
  if @dirty_flag
119
114
  run_log
120
115
  @dirty_flag = false
121
116
  end
122
117
  end
123
-
118
+
124
119
  # actually run the 'git log' command
125
- def run_log
126
- log = @base.lib.full_log_commits(:count => @count, :object => @object,
127
- :path_limiter => @path, :since => @since,
128
- :author => @author, :grep => @grep, :skip => @skip,
129
- :until => @until, :between => @between, :cherry => @cherry)
120
+ def run_log
121
+ log = @base.lib.full_log_commits(
122
+ count: @count, all: @all, object: @object, path_limiter: @path, since: @since,
123
+ author: @author, grep: @grep, skip: @skip, until: @until, between: @between,
124
+ cherry: @cherry
125
+ )
130
126
  @commits = log.map { |c| Git::Object::Commit.new(@base, c['sha'], c) }
131
127
  end
132
-
128
+
133
129
  end
134
-
130
+
135
131
  end
@@ -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.2'
4
+ VERSION='1.15.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.2
4
+ version: 1.15.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-02-02 00:00:00.000000000 Z
11
+ date: 2023-03-01 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