git 4.0.6 → 4.3.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.
data/lib/git/lib.rb CHANGED
@@ -5,6 +5,7 @@ require_relative 'args_builder'
5
5
  require 'git/command_line'
6
6
  require 'git/errors'
7
7
  require 'logger'
8
+ require 'pathname'
8
9
  require 'pp'
9
10
  require 'process_executer'
10
11
  require 'stringio'
@@ -64,6 +65,7 @@ module Git
64
65
  #
65
66
  def initialize(base = nil, logger = nil)
66
67
  @logger = logger || Logger.new(nil)
68
+ @git_ssh = :use_global_config
67
69
 
68
70
  case base
69
71
  when Git::Base
@@ -98,6 +100,21 @@ module Git
98
100
  { keys: [:filter], flag: '--filter', type: :valued_space },
99
101
  { keys: %i[remote origin], flag: '--origin', type: :valued_space },
100
102
  { keys: [:config], flag: '--config', type: :repeatable_valued_space },
103
+ {
104
+ keys: [:single_branch],
105
+ type: :custom,
106
+ validator: ->(value) { [nil, true, false].include?(value) },
107
+ builder: lambda do |value|
108
+ case value
109
+ when true
110
+ ['--single-branch']
111
+ when false
112
+ ['--no-single-branch']
113
+ else
114
+ []
115
+ end
116
+ end
117
+ },
101
118
  {
102
119
  keys: [:depth],
103
120
  type: :custom,
@@ -255,7 +272,8 @@ module Git
255
272
  #
256
273
  # Only :between or :object options can be used, not both.
257
274
  #
258
- # @option opts :path_limiter [Array<String>, String] only include commits that impact files from the specified paths
275
+ # @option opts :path_limiter [String, Pathname, Array<String, Pathname>] only
276
+ # include commits that impact files from the specified paths
259
277
  #
260
278
  # @return [Array<String>] the log output
261
279
  #
@@ -310,7 +328,7 @@ module Git
310
328
  #
311
329
  # Only :between or :object options can be used, not both.
312
330
  #
313
- # @option opts :path_limiter [Array<String>, String] only include commits that
331
+ # @option opts :path_limiter [String, Pathname, Array<String, Pathname>] only include commits that
314
332
  # impact files from the specified paths
315
333
  #
316
334
  # @option opts :skip [Integer]
@@ -719,17 +737,17 @@ module Git
719
737
  end
720
738
 
721
739
  def worktree_add(dir, commitish = nil)
722
- return command('worktree', 'add', dir, commitish) unless commitish.nil?
740
+ return worktree_command('worktree', 'add', dir, commitish) unless commitish.nil?
723
741
 
724
- command('worktree', 'add', dir)
742
+ worktree_command('worktree', 'add', dir)
725
743
  end
726
744
 
727
745
  def worktree_remove(dir)
728
- command('worktree', 'remove', dir)
746
+ worktree_command('worktree', 'remove', dir)
729
747
  end
730
748
 
731
749
  def worktree_prune
732
- command('worktree', 'prune')
750
+ worktree_command('worktree', 'prune')
733
751
  end
734
752
 
735
753
  def list_files(ref_dir)
@@ -824,6 +842,53 @@ module Git
824
842
  raise ArgumentError, "Invalid #{arg_name}: '#{invalid_args.join("', '")}'"
825
843
  end
826
844
 
845
+ # Normalizes path specifications for Git commands
846
+ #
847
+ # Converts a single path or array of paths into a consistent array format
848
+ # suitable for appending to Git command arguments after '--'. Empty strings
849
+ # are filtered out after conversion.
850
+ #
851
+ # @param pathspecs [String, Pathname, Array<String, Pathname>, nil] path(s) to normalize
852
+ # @param arg_name [String] name of the argument for error messages
853
+ # @return [Array<String>, nil] normalized array of path strings, or nil if empty/nil input
854
+ # @raise [ArgumentError] if any path is not a String or Pathname
855
+ #
856
+ def normalize_pathspecs(pathspecs, arg_name)
857
+ return nil unless pathspecs
858
+
859
+ normalized = Array(pathspecs)
860
+ validate_pathspec_types(normalized, arg_name)
861
+
862
+ normalized = normalized.map(&:to_s).reject(&:empty?)
863
+ return nil if normalized.empty?
864
+
865
+ normalized
866
+ end
867
+
868
+ # Validates that all pathspecs are String or Pathname objects
869
+ #
870
+ # @param pathspecs [Array] the pathspecs to validate
871
+ # @param arg_name [String] name of the argument for error messages
872
+ # @raise [ArgumentError] if any path is not a String or Pathname
873
+ #
874
+ def validate_pathspec_types(pathspecs, arg_name)
875
+ return if pathspecs.all? { |path| path.is_a?(String) || path.is_a?(Pathname) }
876
+
877
+ raise ArgumentError, "Invalid #{arg_name}: must be a String, Pathname, or Array of Strings/Pathnames"
878
+ end
879
+
880
+ # Handle deprecated :path option in favor of :path_limiter
881
+ def handle_deprecated_path_option(opts)
882
+ if opts.key?(:path_limiter)
883
+ opts[:path_limiter]
884
+ elsif opts.key?(:path)
885
+ Git::Deprecation.warn(
886
+ 'Git::Lib#diff_path_status :path option is deprecated. Use :path_limiter instead.'
887
+ )
888
+ opts[:path]
889
+ end
890
+ end
891
+
827
892
  DIFF_FULL_OPTION_MAP = [
828
893
  { type: :static, flag: '-p' },
829
894
  { keys: [:path_limiter], type: :validate_only }
@@ -836,8 +901,8 @@ module Git
836
901
  args = build_args(opts, DIFF_FULL_OPTION_MAP)
837
902
  args.push(obj1, obj2).compact!
838
903
 
839
- if (path = opts[:path_limiter]) && path.is_a?(String)
840
- args.push('--', path)
904
+ if (pathspecs = normalize_pathspecs(opts[:path_limiter], 'path limiter'))
905
+ args.push('--', *pathspecs)
841
906
  end
842
907
 
843
908
  command('diff', *args)
@@ -855,8 +920,8 @@ module Git
855
920
  args = build_args(opts, DIFF_STATS_OPTION_MAP)
856
921
  args.push(obj1, obj2).compact!
857
922
 
858
- if (path = opts[:path_limiter]) && path.is_a?(String)
859
- args.push('--', path)
923
+ if (pathspecs = normalize_pathspecs(opts[:path_limiter], 'path limiter'))
924
+ args.push('--', *pathspecs)
860
925
  end
861
926
 
862
927
  output_lines = command_lines('diff', *args)
@@ -865,6 +930,7 @@ module Git
865
930
 
866
931
  DIFF_PATH_STATUS_OPTION_MAP = [
867
932
  { type: :static, flag: '--name-status' },
933
+ { keys: [:path_limiter], type: :validate_only },
868
934
  { keys: [:path], type: :validate_only }
869
935
  ].freeze
870
936
 
@@ -874,7 +940,11 @@ module Git
874
940
 
875
941
  args = build_args(opts, DIFF_PATH_STATUS_OPTION_MAP)
876
942
  args.push(reference1, reference2).compact!
877
- args.push('--', opts[:path]) if opts[:path]
943
+
944
+ path_limiter = handle_deprecated_path_option(opts)
945
+ if (pathspecs = normalize_pathspecs(path_limiter, 'path limiter'))
946
+ args.push('--', *pathspecs)
947
+ end
878
948
 
879
949
  parse_diff_path_status(args)
880
950
  end
@@ -1319,6 +1389,20 @@ module Git
1319
1389
  command('remote', *command_args)
1320
1390
  end
1321
1391
 
1392
+ REMOTE_SET_BRANCHES_OPTION_MAP = [
1393
+ { keys: [:add], flag: '--add', type: :boolean }
1394
+ ].freeze
1395
+
1396
+ def remote_set_branches(name, branches, opts = {})
1397
+ ArgsBuilder.validate!(opts, REMOTE_SET_BRANCHES_OPTION_MAP)
1398
+
1399
+ flags = build_args(opts, REMOTE_SET_BRANCHES_OPTION_MAP)
1400
+ branch_args = Array(branches).flatten
1401
+ command_args = ['set-branches'] + flags + [name] + branch_args
1402
+
1403
+ command('remote', *command_args)
1404
+ end
1405
+
1322
1406
  def remote_set_url(name, url)
1323
1407
  arr_opts = ['set-url']
1324
1408
  arr_opts << name
@@ -1446,6 +1530,38 @@ module Git
1446
1530
  command('gc', '--prune', '--aggressive', '--auto')
1447
1531
  end
1448
1532
 
1533
+ FSCK_OPTION_MAP = [
1534
+ { flag: '--no-progress', type: :static },
1535
+ { keys: [:unreachable], flag: '--unreachable', type: :boolean },
1536
+ { keys: [:strict], flag: '--strict', type: :boolean },
1537
+ { keys: [:connectivity_only], flag: '--connectivity-only', type: :boolean },
1538
+ { keys: [:root], flag: '--root', type: :boolean },
1539
+ { keys: [:tags], flag: '--tags', type: :boolean },
1540
+ { keys: [:cache], flag: '--cache', type: :boolean },
1541
+ { keys: [:no_reflogs], flag: '--no-reflogs', type: :boolean },
1542
+ { keys: [:lost_found], flag: '--lost-found', type: :boolean },
1543
+ { keys: [:dangling], flag: '--dangling', type: :boolean_negatable },
1544
+ { keys: [:full], flag: '--full', type: :boolean_negatable },
1545
+ { keys: [:name_objects], flag: '--name-objects', type: :boolean_negatable },
1546
+ { keys: [:references], flag: '--references', type: :boolean_negatable }
1547
+ ].freeze
1548
+
1549
+ def fsck(*objects, **opts)
1550
+ args = ArgsBuilder.build(opts, FSCK_OPTION_MAP)
1551
+ args.concat(objects) unless objects.empty?
1552
+ # fsck returns non-zero exit status when issues are found:
1553
+ # 1 = errors found, 2 = missing objects, 4 = warnings
1554
+ # We still want to parse the output in these cases
1555
+ output = begin
1556
+ command('fsck', *args)
1557
+ rescue Git::FailedError => e
1558
+ raise unless [1, 2, 4].include?(e.result.status.exitstatus)
1559
+
1560
+ e.result.stdout
1561
+ end
1562
+ parse_fsck_output(output)
1563
+ end
1564
+
1449
1565
  READ_TREE_OPTION_MAP = [
1450
1566
  { keys: [:prefix], flag: '--prefix', type: :valued_equals }
1451
1567
  ].freeze
@@ -1600,8 +1716,52 @@ module Git
1600
1716
  { keys: [:between], type: :custom, builder: ->(value) { "#{value[0]}..#{value[1]}" if value } }
1601
1717
  ].freeze
1602
1718
 
1719
+ FSCK_OBJECT_PATTERN = /\A(dangling|missing|unreachable) (\w+) ([0-9a-f]{40})(?: \((.+)\))?\z/
1720
+ FSCK_WARNING_PATTERN = /\Awarning in (\w+) ([0-9a-f]{40}): (.+)\z/
1721
+ FSCK_ROOT_PATTERN = /\Aroot ([0-9a-f]{40})\z/
1722
+ FSCK_TAGGED_PATTERN = /\Atagged (\w+) ([0-9a-f]{40}) \((.+)\) in ([0-9a-f]{40})\z/
1723
+
1724
+ private_constant :FSCK_OBJECT_PATTERN, :FSCK_WARNING_PATTERN, :FSCK_ROOT_PATTERN, :FSCK_TAGGED_PATTERN
1725
+
1603
1726
  private
1604
1727
 
1728
+ def parse_fsck_output(output)
1729
+ result = { dangling: [], missing: [], unreachable: [], warnings: [], root: [], tagged: [] }
1730
+ output.each_line { |line| parse_fsck_line(line.strip, result) }
1731
+ Git::FsckResult.new(**result)
1732
+ end
1733
+
1734
+ def parse_fsck_line(line, result)
1735
+ parse_fsck_object_line(line, result) ||
1736
+ parse_fsck_warning_line(line, result) ||
1737
+ parse_fsck_root_line(line, result) ||
1738
+ parse_fsck_tagged_line(line, result)
1739
+ end
1740
+
1741
+ def parse_fsck_object_line(line, result)
1742
+ return unless (match = FSCK_OBJECT_PATTERN.match(line))
1743
+
1744
+ result[match[1].to_sym] << Git::FsckObject.new(type: match[2].to_sym, sha: match[3], name: match[4])
1745
+ end
1746
+
1747
+ def parse_fsck_warning_line(line, result)
1748
+ return unless (match = FSCK_WARNING_PATTERN.match(line))
1749
+
1750
+ result[:warnings] << Git::FsckObject.new(type: match[1].to_sym, sha: match[2], message: match[3])
1751
+ end
1752
+
1753
+ def parse_fsck_root_line(line, result)
1754
+ return unless (match = FSCK_ROOT_PATTERN.match(line))
1755
+
1756
+ result[:root] << Git::FsckObject.new(type: :commit, sha: match[1])
1757
+ end
1758
+
1759
+ def parse_fsck_tagged_line(line, result)
1760
+ return unless (match = FSCK_TAGGED_PATTERN.match(line))
1761
+
1762
+ result[:tagged] << Git::FsckObject.new(type: match[1].to_sym, sha: match[2], name: match[3])
1763
+ end
1764
+
1605
1765
  def parse_diff_path_status(args)
1606
1766
  command_lines('diff', *args).each_with_object({}) do |line, memo|
1607
1767
  status, path = split_status_line(line)
@@ -1625,15 +1785,17 @@ module Git
1625
1785
  end
1626
1786
 
1627
1787
  def initialize_from_base(base_object)
1628
- @git_dir = base_object.repo.path
1629
- @git_index_file = base_object.index&.path
1630
- @git_work_dir = base_object.dir&.path
1788
+ @git_dir = base_object.repo.to_s
1789
+ @git_index_file = base_object.index&.to_s
1790
+ @git_work_dir = base_object.dir&.to_s
1791
+ @git_ssh = base_object.git_ssh
1631
1792
  end
1632
1793
 
1633
1794
  def initialize_from_hash(base_hash)
1634
1795
  @git_dir = base_hash[:repository]
1635
1796
  @git_index_file = base_hash[:index]
1636
1797
  @git_work_dir = base_hash[:working_directory]
1798
+ @git_ssh = base_hash.key?(:git_ssh) ? base_hash[:git_ssh] : :use_global_config
1637
1799
  end
1638
1800
 
1639
1801
  def return_base_opts_from_clone(clone_dir, opts)
@@ -1641,6 +1803,7 @@ module Git
1641
1803
  base_opts[:repository] = clone_dir if opts[:bare] || opts[:mirror]
1642
1804
  base_opts[:working_directory] = clone_dir unless opts[:bare] || opts[:mirror]
1643
1805
  base_opts[:log] = opts[:log] if opts[:log]
1806
+ base_opts[:git_ssh] = opts[:git_ssh] if opts.key?(:git_ssh)
1644
1807
  base_opts
1645
1808
  end
1646
1809
 
@@ -1883,14 +2046,63 @@ module Git
1883
2046
  op.split("\n")
1884
2047
  end
1885
2048
 
1886
- def env_overrides
2049
+ # Returns a hash of environment variable overrides for git commands
2050
+ #
2051
+ # This method builds a hash of environment variables that control git's behavior,
2052
+ # such as the git directory, working tree, and index file locations.
2053
+ #
2054
+ # @param additional_overrides [Hash] additional environment variables to set or unset
2055
+ #
2056
+ # Keys should be environment variable names (String) and values should be either:
2057
+ # * A String value to set the environment variable
2058
+ # * `nil` to unset the environment variable
2059
+ #
2060
+ # Per Process.spawn semantics, setting a key to `nil` will unset that environment
2061
+ # variable, removing it from the environment passed to the git command.
2062
+ #
2063
+ # @return [Hash<String, String|nil>] environment variable overrides
2064
+ #
2065
+ # @example Basic usage with default environment variables
2066
+ # env_overrides
2067
+ # # => { 'GIT_DIR' => '/path/to/.git', 'GIT_WORK_TREE' => '/path/to/worktree', ... }
2068
+ #
2069
+ # @example Adding a custom environment variable
2070
+ # env_overrides('GIT_TRACE' => '1')
2071
+ # # => { 'GIT_DIR' => '/path/to/.git', ..., 'GIT_TRACE' => '1' }
2072
+ #
2073
+ # @example Unsetting an environment variable (used by worktree_command_line)
2074
+ # env_overrides('GIT_INDEX_FILE' => nil)
2075
+ # # => { 'GIT_DIR' => '/path/to/.git', 'GIT_WORK_TREE' => '/path/to/worktree',
2076
+ # # 'GIT_INDEX_FILE' => nil, 'GIT_SSH' => <git_ssh_value>, 'LC_ALL' => 'en_US.UTF-8' }
2077
+ # # When passed to Process.spawn, GIT_INDEX_FILE will be unset in the environment
2078
+ #
2079
+ # @see https://ruby-doc.org/core/Process.html#method-c-spawn Process.spawn
2080
+ #
2081
+ # @api private
2082
+ #
2083
+ def env_overrides(**additional_overrides)
1887
2084
  {
1888
2085
  'GIT_DIR' => @git_dir,
1889
2086
  'GIT_WORK_TREE' => @git_work_dir,
1890
2087
  'GIT_INDEX_FILE' => @git_index_file,
1891
- 'GIT_SSH' => Git::Base.config.git_ssh,
2088
+ 'GIT_SSH' => resolved_git_ssh,
1892
2089
  'LC_ALL' => 'en_US.UTF-8'
1893
- }
2090
+ }.merge(additional_overrides)
2091
+ end
2092
+
2093
+ # Resolve the git_ssh value to use for this instance
2094
+ #
2095
+ # @return [String, nil] the resolved git_ssh value
2096
+ #
2097
+ # Returns the global config value if @git_ssh is the sentinel :use_global_config,
2098
+ # otherwise returns @git_ssh (which may be nil or a string)
2099
+ #
2100
+ # @api private
2101
+ #
2102
+ def resolved_git_ssh
2103
+ return Git::Base.config.git_ssh if @git_ssh == :use_global_config
2104
+
2105
+ @git_ssh
1894
2106
  end
1895
2107
 
1896
2108
  def global_opts
@@ -1906,6 +2118,46 @@ module Git
1906
2118
  Git::CommandLine.new(env_overrides, Git::Base.config.binary_path, global_opts, @logger)
1907
2119
  end
1908
2120
 
2121
+ # Returns a command line instance without GIT_INDEX_FILE for worktree commands
2122
+ #
2123
+ # Git worktrees manage their own index files and setting GIT_INDEX_FILE
2124
+ # causes corruption of both the main worktree and new worktree indexes.
2125
+ #
2126
+ # @return [Git::CommandLine]
2127
+ # @api private
2128
+ #
2129
+ def worktree_command_line
2130
+ @worktree_command_line ||=
2131
+ Git::CommandLine.new(env_overrides('GIT_INDEX_FILE' => nil), Git::Base.config.binary_path, global_opts,
2132
+ @logger)
2133
+ end
2134
+
2135
+ # @overload worktree_command(*args, **options_hash)
2136
+ # Runs a git worktree command and returns the output
2137
+ #
2138
+ # This method is similar to #command but uses a command line instance
2139
+ # that excludes GIT_INDEX_FILE from the environment to prevent index corruption.
2140
+ #
2141
+ # @param args [Array<String>] the command arguments
2142
+ # @param options_hash [Hash] the options to pass to the command
2143
+ #
2144
+ # @return [String] the command's stdout
2145
+ #
2146
+ # @see #command
2147
+ #
2148
+ # @api private
2149
+ #
2150
+ def worktree_command(*, **options_hash)
2151
+ options_hash = COMMAND_ARG_DEFAULTS.merge(options_hash)
2152
+ options_hash[:timeout] ||= Git.config.timeout
2153
+
2154
+ extra_options = options_hash.keys - COMMAND_ARG_DEFAULTS.keys
2155
+ raise ArgumentError, "Unknown options: #{extra_options.join(', ')}" if extra_options.any?
2156
+
2157
+ result = worktree_command_line.run(*, **options_hash)
2158
+ result.stdout
2159
+ end
2160
+
1909
2161
  # Runs a git command and returns the output
1910
2162
  #
1911
2163
  # Additional args are passed to the command line. They should exclude the 'git'
data/lib/git/log.rb CHANGED
@@ -1,9 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Git
4
- # Builds and executes a `git log` query.
4
+ # Builds and executes a `git log` query
5
5
  #
6
6
  # This class provides a fluent interface for building complex `git log` queries.
7
+ #
8
+ # Queries default to returning 30 commits; call {#max_count} with `:all` to
9
+ # return every matching commit. Calling {#all} adds the `--all` flag to include
10
+ # all refs in the search but does not change the number of commits returned.
11
+ #
7
12
  # The query is lazily executed when results are requested either via the modern
8
13
  # `#execute` method or the deprecated Enumerable methods.
9
14
  #
data/lib/git/path.rb CHANGED
@@ -7,7 +7,13 @@ module Git
7
7
  # directory or index file.
8
8
  #
9
9
  class Path
10
- attr_accessor :path
10
+ def path
11
+ Git::Deprecation.warn(
12
+ 'The .path accessor is deprecated and will be removed in v5.0. ' \
13
+ 'Use .to_s instead.'
14
+ )
15
+ @path
16
+ end
11
17
 
12
18
  def initialize(path, must_exist: true)
13
19
  path = File.expand_path(path)
data/lib/git/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  module Git
4
4
  # The current gem version
5
5
  # @return [String] the current gem version.
6
- VERSION = '4.0.6'
6
+ VERSION = '4.3.0'
7
7
  end
data/lib/git.rb CHANGED
@@ -18,6 +18,8 @@ require 'git/diff'
18
18
  require 'git/encoding_utils'
19
19
  require 'git/errors'
20
20
  require 'git/escaped_path'
21
+ require 'git/fsck_object'
22
+ require 'git/fsck_result'
21
23
  require 'git/index'
22
24
  require 'git/lib'
23
25
  require 'git/log'
@@ -93,6 +95,12 @@ module Git
93
95
  # @param [Hash] options The options for this command (see list of valid
94
96
  # options below)
95
97
  #
98
+ # @option options [String, nil] :git_ssh An optional custom SSH command
99
+ #
100
+ # - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
101
+ # - If nil, disables SSH for this instance.
102
+ # - If a non-empty string, uses that value for this instance.
103
+ #
96
104
  # @option options [Logger] :log A logger to use for Git operations. Git commands
97
105
  # are logged at the `:info` level. Additional logging is done at the `:debug`
98
106
  # level.
@@ -145,6 +153,20 @@ module Git
145
153
  # @option options [String] :filter Request that the server send a partial
146
154
  # clone according to the given filter
147
155
  #
156
+ # @option options [Boolean, nil] :single_branch Control whether the clone
157
+ # limits fetch refspecs to a single branch.
158
+ # - If nil (default), no flag is passed and the Git default is used.
159
+ # - If true, `--single-branch` is passed to limit the refspec to the
160
+ # checkout branch.
161
+ # - If false, `--no-single-branch` is passed to broaden the refspec (useful
162
+ # for shallow clones that should include all branches).
163
+ #
164
+ # @option options [String, nil] :git_ssh An optional custom SSH command
165
+ #
166
+ # - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
167
+ # - If nil, disables SSH for this instance.
168
+ # - If a non-empty string, uses that value for this instance.
169
+ #
148
170
  # @option options [Logger] :log A logger to use for Git operations. Git
149
171
  # commands are logged at the `:info` level. Additional logging is done
150
172
  # at the `:debug` level.
@@ -187,6 +209,13 @@ module Git
187
209
  # config: ['user.name=John Doe', 'user.email=john@doe.com']
188
210
  # )
189
211
  #
212
+ # @example Clone using a specific SSH key
213
+ # git = Git.clone(
214
+ # 'git@github.com:ruby-git/ruby-git.git',
215
+ # 'local-dir',
216
+ # git_ssh: 'ssh -i /path/to/private_key'
217
+ # )
218
+ #
190
219
  # @return [Git::Base] an object that can execute git commands in the context
191
220
  # of the cloned local working copy or cloned repository.
192
221
  #
@@ -300,6 +329,12 @@ module Git
300
329
  # and converted to an absolute path using
301
330
  # [File.expand_path](https://www.rubydoc.info/stdlib/core/File.expand_path).
302
331
  #
332
+ # @option options [String, nil] :git_ssh An optional custom SSH command
333
+ #
334
+ # - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
335
+ # - If nil, disables SSH for this instance.
336
+ # - If a non-empty string, uses that value for this instance.
337
+ #
303
338
  # @option options [Logger] :log A logger to use for Git operations. Git
304
339
  # commands are logged at the `:info` level. Additional logging is done
305
340
  # at the `:debug` level.
@@ -374,6 +409,12 @@ module Git
374
409
  # @option options [Pathname] :index used to specify a non-standard path to an
375
410
  # index file. The default is `"#{working_dir}/.git/index"`
376
411
  #
412
+ # @option options [String, nil] :git_ssh An optional custom SSH command
413
+ #
414
+ # - If not specified, uses the global config (Git.configure { |c| c.git_ssh = ... }).
415
+ # - If nil, disables SSH for this instance.
416
+ # - If a non-empty string, uses that value for this instance.
417
+ #
377
418
  # @option options [Logger] :log A logger to use for Git operations. Git
378
419
  # commands are logged at the `:info` level. Additional logging is done
379
420
  # at the `:debug` level.
data/redesign/index.md ADDED
@@ -0,0 +1,34 @@
1
+ # Architectural Redesign Project
2
+
3
+ [This project was announced in the project's README](../README.md#2025-07-09-architectural-redesign)
4
+
5
+ The git gem is undergoing a significant architectural redesign for the upcoming
6
+ v5.0.0 release. The current architecture has several design challenges that make it
7
+ difficult to maintain and evolve. This redesign aims to address these issues by
8
+ introducing a clearer, more robust, and more testable structure.
9
+
10
+ We have prepared detailed documents outlining the analysis of the current
11
+ architecture and the proposed changes. We encourage our community and contributors to
12
+ review them:
13
+
14
+ 1. [Analysis of the Current Architecture](1_architecture_existing.md): A
15
+ breakdown of the existing design and its challenges.
16
+ 2. [The Proposed Redesign](2_architecture_redesign.md): An overview of the
17
+ new three-layered architecture.
18
+ 3. [Implementation Plan](3_architecture_implementation.md): The step-by-step
19
+ plan for implementing the redesign.
20
+
21
+ Your feedback is welcome! Please feel free to open an issue to discuss the proposed
22
+ changes.
23
+
24
+ > **DON'T PANIC!**
25
+ >
26
+ > While this is a major internal refactoring, our goal is to keep the primary public
27
+ API on the main repository object as stable as possible. Most users who rely on
28
+ documented methods like `g.commit`, `g.add`, and `g.status` should find the
29
+ transition to v5.0.0 straightforward.
30
+ >
31
+ > The breaking changes will primarily affect users who have been relying on the
32
+ internal g.lib accessor, which will be removed as part of this cleanup. For more
33
+ details, please see the "Impact on Users" section in [the redesign
34
+ > document](2_architecture_redesign.md).
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: 4.0.6
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon and others
@@ -163,6 +163,20 @@ dependencies:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
165
  version: '3.6'
166
+ - !ruby/object:Gem::Dependency
167
+ name: irb
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '1.6'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.6'
166
180
  - !ruby/object:Gem::Dependency
167
181
  name: redcarpet
168
182
  requirement: !ruby/object:Gem::Requirement
@@ -223,6 +237,7 @@ extensions: []
223
237
  extra_rdoc_files: []
224
238
  files:
225
239
  - ".commitlintrc.yml"
240
+ - ".github/copilot-instructions.md"
226
241
  - ".github/issue_template.md"
227
242
  - ".github/pull_request_template.md"
228
243
  - ".github/workflows/continuous_integration.yml"
@@ -235,8 +250,11 @@ files:
235
250
  - ".rubocop.yml"
236
251
  - ".rubocop_todo.yml"
237
252
  - ".yardopts"
253
+ - AI_POLICY.md
238
254
  - CHANGELOG.md
255
+ - CODE_OF_CONDUCT.md
239
256
  - CONTRIBUTING.md
257
+ - GOVERNANCE.md
240
258
  - Gemfile
241
259
  - LICENSE
242
260
  - MAINTAINERS.md
@@ -258,6 +276,8 @@ files:
258
276
  - lib/git/encoding_utils.rb
259
277
  - lib/git/errors.rb
260
278
  - lib/git/escaped_path.rb
279
+ - lib/git/fsck_object.rb
280
+ - lib/git/fsck_result.rb
261
281
  - lib/git/index.rb
262
282
  - lib/git/lib.rb
263
283
  - lib/git/log.rb
@@ -277,6 +297,7 @@ files:
277
297
  - redesign/1_architecture_existing.md
278
298
  - redesign/2_architecture_redesign.md
279
299
  - redesign/3_architecture_implementation.md
300
+ - redesign/index.md
280
301
  - release-please-config.json
281
302
  - tasks/gem_tasks.rake
282
303
  - tasks/rubocop.rake
@@ -289,8 +310,8 @@ licenses:
289
310
  metadata:
290
311
  homepage_uri: http://github.com/ruby-git/ruby-git
291
312
  source_code_uri: http://github.com/ruby-git/ruby-git
292
- changelog_uri: https://rubydoc.info/gems/git/4.0.6/file/CHANGELOG.md
293
- documentation_uri: https://rubydoc.info/gems/git/4.0.6
313
+ changelog_uri: https://rubydoc.info/gems/git/4.3.0/file/CHANGELOG.md
314
+ documentation_uri: https://rubydoc.info/gems/git/4.3.0
294
315
  rubygems_mfa_required: 'true'
295
316
  rdoc_options: []
296
317
  require_paths:
@@ -307,7 +328,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
307
328
  version: '0'
308
329
  requirements:
309
330
  - git 2.28.0 or greater
310
- rubygems_version: 3.6.9
331
+ rubygems_version: 4.0.3
311
332
  specification_version: 4
312
333
  summary: An API to create, read, and manipulate Git repositories
313
334
  test_files: []