git 1.19.1 → 4.4.5

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.commitlintrc.yml +38 -0
  3. data/.github/copilot-instructions.md +2733 -0
  4. data/.github/pull_request_template.md +17 -0
  5. data/.github/workflows/continuous_integration.yml +92 -21
  6. data/.github/workflows/enforce_conventional_commits.yml +29 -0
  7. data/.github/workflows/experimental_continuous_integration.yml +59 -0
  8. data/.github/workflows/release.yml +53 -0
  9. data/.gitignore +5 -0
  10. data/.husky/commit-msg +1 -0
  11. data/.release-please-manifest.json +3 -0
  12. data/.rubocop.yml +55 -0
  13. data/.rubocop_todo.yml +12 -0
  14. data/.yardopts +4 -1
  15. data/AI_POLICY.md +24 -0
  16. data/CHANGELOG.md +501 -0
  17. data/CODE_OF_CONDUCT.md +25 -0
  18. data/CONTRIBUTING.md +323 -102
  19. data/GOVERNANCE.md +106 -0
  20. data/LICENSE +1 -1
  21. data/MAINTAINERS.md +17 -4
  22. data/README.md +575 -246
  23. data/Rakefile +13 -55
  24. data/git.gemspec +36 -30
  25. data/lib/git/args_builder.rb +111 -0
  26. data/lib/git/author.rb +9 -7
  27. data/lib/git/base.rb +602 -173
  28. data/lib/git/branch.rb +318 -38
  29. data/lib/git/branches.rb +21 -24
  30. data/lib/git/command_line.rb +330 -0
  31. data/lib/git/command_line_result.rb +9 -3
  32. data/lib/git/config.rb +10 -6
  33. data/lib/git/diff.rb +149 -81
  34. data/lib/git/diff_path_status.rb +46 -0
  35. data/lib/git/diff_stats.rb +59 -0
  36. data/lib/git/errors.rb +212 -0
  37. data/lib/git/escaped_path.rb +2 -2
  38. data/lib/git/fsck_object.rb +48 -0
  39. data/lib/git/fsck_result.rb +121 -0
  40. data/lib/git/index.rb +2 -1
  41. data/lib/git/lib.rb +1648 -643
  42. data/lib/git/log.rb +143 -106
  43. data/lib/git/object.rb +151 -125
  44. data/lib/git/path.rb +23 -16
  45. data/lib/git/remote.rb +5 -4
  46. data/lib/git/repository.rb +2 -2
  47. data/lib/git/stash.rb +11 -12
  48. data/lib/git/stashes.rb +16 -15
  49. data/lib/git/status.rb +104 -143
  50. data/lib/git/url.rb +3 -3
  51. data/lib/git/version.rb +3 -1
  52. data/lib/git/working_directory.rb +2 -0
  53. data/lib/git/worktree.rb +6 -5
  54. data/lib/git/worktrees.rb +6 -6
  55. data/lib/git.rb +131 -28
  56. data/package.json +10 -0
  57. data/redesign/1_architecture_existing.md +66 -0
  58. data/redesign/2_architecture_redesign.md +130 -0
  59. data/redesign/3_architecture_implementation.md +138 -0
  60. data/redesign/index.md +34 -0
  61. data/release-please-config.json +36 -0
  62. data/tasks/gem_tasks.rake +10 -0
  63. data/tasks/rubocop.rake +12 -0
  64. data/tasks/test.rake +13 -0
  65. data/tasks/test_gem.rake +12 -0
  66. data/tasks/yard.rake +23 -0
  67. metadata +114 -37
  68. data/.github/stale.yml +0 -25
  69. data/Dockerfile.changelog-rs +0 -12
  70. data/PULL_REQUEST_TEMPLATE.md +0 -9
  71. data/RELEASING.md +0 -70
  72. data/lib/git/base/factory.rb +0 -99
  73. data/lib/git/failed_error.rb +0 -53
  74. data/lib/git/git_execute_error.rb +0 -7
  75. data/lib/git/signaled_error.rb +0 -50
  76. /data/{ISSUE_TEMPLATE.md → .github/issue_template.md} +0 -0
data/Rakefile CHANGED
@@ -1,60 +1,18 @@
1
- require 'bundler/gem_tasks'
2
- require 'English'
1
+ # frozen_string_literal: true
3
2
 
4
- require 'git/version'
3
+ require 'rake/clean'
5
4
 
6
- default_tasks = []
7
-
8
- desc 'Run Unit Tests'
9
- task :test do
10
- sh 'ruby bin/test'
11
-
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
18
- end
19
- default_tasks << :test
20
-
21
- unless RUBY_PLATFORM == 'java' || RUBY_ENGINE == 'truffleruby'
22
- #
23
- # YARD documentation for this project can NOT be built with JRuby.
24
- # This project uses the redcarpet gem which can not be installed on JRuby.
25
- #
26
- require 'yard'
27
- YARD::Rake::YardocTask.new
28
- CLEAN << '.yardoc'
29
- CLEAN << 'doc'
30
- default_tasks << :yard
31
-
32
- require 'yardstick/rake/verify'
33
- Yardstick::Rake::Verify.new(:'yardstick:coverage') do |t|
34
- t.threshold = 50
35
- t.require_exact_threshold = false
36
- end
37
- default_tasks << :'yardstick:coverage'
5
+ # Load all .rake files from tasks and its subdirectories.
6
+ Dir.glob('tasks/**/*.rake').each { |r| load r }
38
7
 
39
- desc 'Run yardstick to check yard docs'
40
- task :yardstick do
41
- sh "yardstick 'lib/**/*.rb'"
42
- end
43
- # Do not include yardstick as a default task for now since there are too many
44
- # warnings. Will work to get the warnings down before re-enabling it.
45
- #
46
- # default_tasks << :yardstick
47
- end
48
-
49
- default_tasks << :build
8
+ default_tasks = []
9
+ default_tasks << :test if Rake::Task.task_defined?(:test)
10
+ default_tasks << :rubocop if Rake::Task.task_defined?(:rubocop)
11
+ default_tasks << :yard if Rake::Task.task_defined?(:yard)
12
+ default_tasks << :'yardstick:coverage' if Rake::Task.task_defined?(:'yardstick:coverage')
13
+ # Do not include yardstick as a default task for now since there are too many
14
+ # warnings. Will work to get the warnings down before re-enabling it.
15
+ # default_tasks << :yardstick if Rake::Task.task_defined?(:yardstick)
16
+ default_tasks << :build if Rake::Task.task_defined?(:build)
50
17
 
51
18
  task default: default_tasks
52
-
53
- desc 'Build and install the git gem and run a sanity check'
54
- task :'test:gem' => :install do
55
- output = `ruby -e "require 'git'; g = Git.open('.'); puts g.log.size"`.chomp
56
- raise 'Gem test failed' unless $CHILD_STATUS.success?
57
- raise 'Expected gem test to return an integer' unless output =~ /^\d+$/
58
-
59
- puts 'Gem Test Succeeded'
60
- end
data/git.gemspec CHANGED
@@ -1,52 +1,58 @@
1
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
2
4
  require 'git/version'
3
5
 
4
- Gem::Specification.new do |s|
5
- s.author = 'Scott Chacon and others'
6
- s.email = 'schacon@gmail.com'
7
- s.homepage = 'http://github.com/ruby-git/ruby-git'
8
- s.license = 'MIT'
9
- s.name = 'git'
10
- s.summary = 'An API to create, read, and manipulate Git repositories'
11
- s.description = <<~DESCRIPTION
6
+ Gem::Specification.new do |spec|
7
+ spec.author = 'Scott Chacon and others'
8
+ spec.email = 'schacon@gmail.com'
9
+ spec.homepage = 'http://github.com/ruby-git/ruby-git'
10
+ spec.license = 'MIT'
11
+ spec.name = 'git'
12
+ spec.summary = 'An API to create, read, and manipulate Git repositories'
13
+ spec.description = <<~DESCRIPTION
12
14
  The git gem provides an API that can be used to
13
15
  create, read, and manipulate Git repositories by wrapping system calls to the git
14
16
  command line. The API can be used for working with Git in complex interactions
15
17
  including branching and merging, object inspection and manipulation, history, patch
16
18
  generation and more.
17
19
  DESCRIPTION
18
- s.version = Git::VERSION
20
+ spec.version = Git::VERSION
19
21
 
22
+ spec.metadata['homepage_uri'] = spec.homepage
23
+ spec.metadata['source_code_uri'] = spec.homepage
24
+ spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md"
25
+ spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}"
26
+ spec.metadata['rubygems_mfa_required'] = 'true'
20
27
 
21
- s.metadata['homepage_uri'] = s.homepage
22
- s.metadata['source_code_uri'] = s.homepage
23
- s.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{s.name}/#{s.version}/file/CHANGELOG.md"
24
- s.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{s.name}/#{s.version}"
28
+ spec.require_paths = ['lib']
29
+ spec.required_ruby_version = '>= 3.2.0'
30
+ spec.requirements = ['git 2.28.0 or greater']
25
31
 
26
- s.require_paths = ['lib']
27
- s.required_ruby_version = '>= 2.3'
28
- s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?(:required_rubygems_version=)
29
- s.requirements = ['git 1.6.0.0, or greater']
32
+ spec.add_dependency 'activesupport', '>= 5.0'
33
+ spec.add_dependency 'addressable', '~> 2.8'
34
+ spec.add_dependency 'process_executer', '~> 4.1'
35
+ spec.add_dependency 'rchardet', '~> 1.9'
30
36
 
31
- s.add_runtime_dependency 'addressable', '~> 2.8'
32
- s.add_runtime_dependency 'rchardet', '~> 1.8'
37
+ spec.add_development_dependency 'create_github_release', '~> 2.1'
38
+ spec.add_development_dependency 'main_branch_shared_rubocop_config', '~> 0.1'
39
+ spec.add_development_dependency 'minitar', '~> 1.0'
40
+ spec.add_development_dependency 'mocha', '~> 2.7'
41
+ spec.add_development_dependency 'rake', '~> 13.2'
42
+ spec.add_development_dependency 'rubocop', '~> 1.77'
33
43
 
34
- s.add_development_dependency 'bump', '~> 0.10'
35
- s.add_development_dependency 'create_github_release', '~> 0.2'
36
- s.add_development_dependency 'minitar', '~> 0.9'
37
- s.add_development_dependency 'mocha', '~> 2.1'
38
- s.add_development_dependency 'rake', '~> 13.0'
39
- s.add_development_dependency 'test-unit', '~> 3.3'
44
+ spec.add_development_dependency 'test-unit', '~> 3.6'
40
45
 
41
46
  unless RUBY_PLATFORM == 'java'
42
- s.add_development_dependency 'redcarpet', '~> 3.5'
43
- s.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28'
44
- s.add_development_dependency 'yardstick', '~> 0.9'
47
+ spec.add_development_dependency 'irb', '~> 1.6'
48
+ spec.add_development_dependency 'redcarpet', '~> 3.6'
49
+ spec.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28'
50
+ spec.add_development_dependency 'yardstick', '~> 0.9'
45
51
  end
46
52
 
47
53
  # Specify which files should be added to the gem when it is released.
48
54
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
49
- s.files = Dir.chdir(File.expand_path(__dir__)) do
55
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
50
56
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(tests|spec|features|bin)/}) }
51
57
  end
52
58
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Git
4
+ # Takes a hash of user options and a declarative map and produces
5
+ # an array of command-line arguments. Also validates that only
6
+ # supported options are provided based on the map.
7
+ #
8
+ # @api private
9
+ class ArgsBuilder
10
+ # This hash maps an option type to a lambda that knows how to build the
11
+ # corresponding command-line argument. This is a scalable dispatch table.
12
+ ARG_BUILDERS = {
13
+ boolean: ->(config, value) { value ? config[:flag] : [] },
14
+
15
+ boolean_negatable: lambda do |config, value|
16
+ case value
17
+ when true then config[:flag]
18
+ when false then config[:flag].sub('--', '--no-')
19
+ else []
20
+ end
21
+ end,
22
+
23
+ valued_equals: ->(config, value) { "#{config[:flag]}=#{value}" if value },
24
+
25
+ valued_space: ->(config, value) { [config[:flag], value.to_s] if value },
26
+
27
+ repeatable_valued_space: lambda do |config, value|
28
+ Array(value).flat_map { |v| [config[:flag], v.to_s] }
29
+ end,
30
+
31
+ custom: ->(config, value) { config[:builder].call(value) },
32
+
33
+ validate_only: ->(_config, _value) { [] } # Does not build any args
34
+ }.freeze
35
+
36
+ # Main entrypoint to validate options and build arguments
37
+ def self.build(opts, option_map)
38
+ validate!(opts, option_map)
39
+ new(opts, option_map).build
40
+ end
41
+
42
+ # Public validation method that can be called independently
43
+ def self.validate!(opts, option_map)
44
+ validate_unsupported_keys!(opts, option_map)
45
+ validate_configured_options!(opts, option_map)
46
+ end
47
+
48
+ def initialize(opts, option_map)
49
+ @opts = opts
50
+ @option_map = option_map
51
+ end
52
+
53
+ def build
54
+ @option_map.flat_map do |config|
55
+ type = config[:type]
56
+ next config[:flag] if type == :static
57
+
58
+ key = config[:keys].find { |k| @opts.key?(k) }
59
+ next [] unless key
60
+
61
+ build_arg_for_option(config, @opts[key])
62
+ end.compact
63
+ end
64
+
65
+ private
66
+
67
+ def build_arg_for_option(config, value)
68
+ builder = ARG_BUILDERS[config[:type]]
69
+ builder&.call(config, value) || []
70
+ end
71
+
72
+ private_class_method def self.validate_unsupported_keys!(opts, option_map)
73
+ all_valid_keys = option_map.flat_map { |config| config[:keys] }.compact
74
+ unsupported_keys = opts.keys - all_valid_keys
75
+
76
+ return if unsupported_keys.empty?
77
+
78
+ raise ArgumentError, "Unsupported options: #{unsupported_keys.map(&:inspect).join(', ')}"
79
+ end
80
+
81
+ private_class_method def self.validate_configured_options!(opts, option_map)
82
+ option_map.each do |config|
83
+ next unless config[:keys] # Skip static flags
84
+
85
+ check_for_missing_required_option!(opts, config)
86
+ validate_option_value!(opts, config)
87
+ end
88
+ end
89
+
90
+ private_class_method def self.check_for_missing_required_option!(opts, config)
91
+ return unless config[:required]
92
+
93
+ key_provided = config[:keys].any? { |k| opts.key?(k) }
94
+ return if key_provided
95
+
96
+ raise ArgumentError, "Missing required option: #{config[:keys].first}"
97
+ end
98
+
99
+ private_class_method def self.validate_option_value!(opts, config)
100
+ validator = config[:validator]
101
+ return unless validator
102
+
103
+ user_key = config[:keys].find { |k| opts.key?(k) }
104
+ return unless user_key # Don't validate if the user didn't provide the option
105
+
106
+ return if validator.call(opts[user_key])
107
+
108
+ raise ArgumentError, "Invalid value for option: #{user_key}"
109
+ end
110
+ end
111
+ end
data/lib/git/author.rb CHANGED
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Git
4
+ # An author in a Git commit
2
5
  class Author
3
6
  attr_accessor :name, :email, :date
4
-
7
+
5
8
  def initialize(author_string)
6
- if m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string)
7
- @name = m[1]
8
- @email = m[2]
9
- @date = Time.at(m[3].to_i)
10
- end
9
+ return unless (m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string))
10
+
11
+ @name = m[1]
12
+ @email = m[2]
13
+ @date = Time.at(m[3].to_i)
11
14
  end
12
-
13
15
  end
14
16
  end