git 5.0.5 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +69 -0
- data/CONTRIBUTING.md +209 -164
- data/LICENSE +1 -1
- data/README.md +205 -138
- data/git.gemspec +77 -17
- data/lib/git/command_line/base.rb +1 -2
- data/lib/git/commands/base.rb +1 -1
- data/lib/git/commands/cat_file/raw.rb +8 -7
- data/lib/git/configuring.rb +56 -0
- data/lib/git/log.rb +19 -0
- data/lib/git/repository/branching.rb +79 -5
- data/lib/git/repository/logging.rb +35 -11
- data/lib/git/repository/object_operations.rb +22 -1
- data/lib/git/version.rb +1 -1
- metadata +33 -122
- data/.claude/commands/address-copilot-reviews.md +0 -14
- data/.claude/settings.json +0 -16
- data/.claude/skills +0 -1
- data/.commitlintrc.yml +0 -38
- data/.dockerignore +0 -27
- data/.github/copilot-instructions.md +0 -30
- data/.github/hooks/bin-setup-on-worktree.json +0 -11
- data/.github/hooks/run-bin-setup-once.sh +0 -20
- data/.github/issue_template.md +0 -15
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +0 -188
- data/.github/pull_request_template.md +0 -21
- data/.github/skills/breaking-change-analysis/SKILL.md +0 -99
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +0 -264
- data/.github/skills/command-implementation/REFERENCE.md +0 -994
- data/.github/skills/command-implementation/SKILL.md +0 -230
- data/.github/skills/command-test-conventions/SKILL.md +0 -664
- data/.github/skills/command-yard-documentation/SKILL.md +0 -434
- data/.github/skills/dependency-management/SKILL.md +0 -72
- data/.github/skills/development-workflow/SKILL.md +0 -512
- data/.github/skills/facade-implementation/REFERENCE.md +0 -837
- data/.github/skills/facade-implementation/SKILL.md +0 -269
- data/.github/skills/facade-test-conventions/SKILL.md +0 -391
- data/.github/skills/facade-yard-documentation/SKILL.md +0 -435
- data/.github/skills/make-skill-template/SKILL.md +0 -226
- data/.github/skills/pr-readiness-review/SKILL.md +0 -205
- data/.github/skills/project-context/SKILL.md +0 -306
- data/.github/skills/pull-request-review/SKILL.md +0 -168
- data/.github/skills/rebase/SKILL.md +0 -148
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +0 -131
- data/.github/skills/release-management/SKILL.md +0 -125
- data/.github/skills/resolve-feedback/SKILL.md +0 -288
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +0 -788
- data/.github/skills/review-arguments-dsl/SKILL.md +0 -214
- data/.github/skills/review-cross-command-consistency/SKILL.md +0 -139
- data/.github/skills/reviewing-skills/SKILL.md +0 -214
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +0 -685
- data/.github/skills/tdd-refactor-step/SKILL.md +0 -236
- data/.github/skills/test-debugging/SKILL.md +0 -161
- data/.github/skills/yard-documentation/SKILL.md +0 -981
- data/.github/skills/yard-documentation/element-rules.md +0 -162
- data/.github/skills-deprecated/README.md +0 -21
- data/.github/skills-deprecated/extract-command-from-lib/SKILL.md +0 -487
- data/.github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -22
- data/.github/skills-deprecated/extract-facade-from-base-lib/SKILL.md +0 -600
- data/.github/skills-deprecated/review-backward-compatibility/SKILL.md +0 -275
- data/.github/workflows/continuous_integration.yml +0 -343
- data/.github/workflows/enforce_conventional_commits.yml +0 -35
- data/.github/workflows/experimental_continuous_integration.yml +0 -59
- data/.github/workflows/release.yml +0 -52
- data/.github/workflows/warm_bundler_caches.yml +0 -82
- data/.gitignore +0 -30
- data/.husky/commit-msg +0 -1
- data/.husky/pre-commit +0 -13
- data/.release-please-config.json +0 -36
- data/.release-please-manifest.json +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -37
- data/.rubocop_todo.yml +0 -30
- data/.yard-lint.yml +0 -75
- data/CLAUDE.md +0 -11
- data/Gemfile +0 -22
- data/Rakefile +0 -41
- data/docker/test/Dockerfile +0 -32
- data/docker/test/docker-compose.yml +0 -0
- data/package.json +0 -10
- data/redesign/1_architecture_existing.md +0 -102
- data/redesign/2_architecture_redesign.md +0 -449
- data/redesign/3_architecture_implementation.md +0 -1623
- data/redesign/Phase 4 - Step A.md +0 -366
- data/redesign/Phase 4 - Step B.md +0 -921
- data/redesign/Phase 4 - Step C.md +0 -833
- data/redesign/beta_release.md +0 -107
- data/redesign/branch_parse_refactor_plan.md +0 -163
- data/redesign/c1a-public-api-scope.tsv +0 -256
- data/redesign/c1c2_audit.md +0 -566
- data/redesign/c1c2_bucket6_lib_orphans.md +0 -626
- data/redesign/config_design.rb +0 -501
- data/redesign/index.md +0 -34
- data/redesign/info_object_migration_plan.md +0 -126
- data/redesign/integration_test_analysis.md +0 -521
- data/redesign/phase-4-step-b-test-audit.tsv +0 -485
- data/redesign/remote_refactor_plan.md +0 -164
- data/redesign/reverse_dependencies.sql +0 -44
- data/tasks/gem_tasks.rake +0 -14
- data/tasks/npm_tasks.rake +0 -7
- data/tasks/rspec.rake +0 -111
- data/tasks/rubocop.rake +0 -5
- data/tasks/test_gem.rake +0 -12
- data/tasks/yard.rake +0 -57
data/git.gemspec
CHANGED
|
@@ -43,38 +43,98 @@ Gem::Specification.new do |spec|
|
|
|
43
43
|
|
|
44
44
|
spec.add_dependency 'activesupport', '>= 5.0'
|
|
45
45
|
spec.add_dependency 'addressable', '~> 2.8'
|
|
46
|
-
spec.add_dependency 'process_executer', '~> 4.
|
|
46
|
+
spec.add_dependency 'process_executer', '~> 4.1'
|
|
47
47
|
spec.add_dependency 'rchardet', '~> 1.9'
|
|
48
48
|
|
|
49
|
+
# Not every development dependency is installed on every runtime. Each predicate
|
|
50
|
+
# below names one reason for holding a gem back, which keeps the dependency list
|
|
51
|
+
# itself a flat, readable list. Deriving one predicate from another also keeps
|
|
52
|
+
# coupled gems from drifting apart when a condition changes.
|
|
53
|
+
#
|
|
54
|
+
# These are local variables rather than methods deliberately. The Gemfile uses
|
|
55
|
+
# `gemspec`, so Bundler evaluates this file on every `bundle exec`, and a top-level
|
|
56
|
+
# `def` -- including one written inside this block, since a block is not a definition
|
|
57
|
+
# scope -- would define a private method on Object in every one of those processes.
|
|
58
|
+
|
|
59
|
+
# JRuby (which reports RUBY_PLATFORM as 'java') and TruffleRuby build no C extensions
|
|
60
|
+
# and do not run the docs build.
|
|
61
|
+
mri = !(RUBY_PLATFORM == 'java' || RUBY_ENGINE == 'truffleruby')
|
|
62
|
+
|
|
63
|
+
# irb stopped being a default gem in Ruby 3.4. JRuby and TruffleRuby ship their own.
|
|
64
|
+
install_irb = mri
|
|
65
|
+
|
|
66
|
+
# Ruby 4.0.0 dropped fiddle from the default gems. On Windows, irb loads
|
|
67
|
+
# reline/io/windows.rb, which requires fiddle/import for the Win32 console API, so
|
|
68
|
+
# bin/console cannot start without it; every other platform takes reline's ANSI IO
|
|
69
|
+
# gate and never loads that file. Derived from install_irb because fiddle exists only
|
|
70
|
+
# to serve irb and, being a C extension, could not install where irb is not.
|
|
71
|
+
install_fiddle = install_irb && Gem.win_platform?
|
|
72
|
+
|
|
73
|
+
# The docs toolchain is supported on MRI only. redcarpet, YARD's Markdown renderer,
|
|
74
|
+
# is also a C extension and so could not install on JRuby regardless.
|
|
75
|
+
install_docs = mri
|
|
76
|
+
|
|
77
|
+
# yard-lint requires Ruby >= 3.3.
|
|
78
|
+
install_yard_lint = install_docs && Gem.ruby_version >= Gem::Version.new('3.3.0')
|
|
79
|
+
|
|
80
|
+
# i18n 1.15+ uses Fiber.[] (Ruby 3.2 Fiber storage), which TruffleRuby < 34.0.0 does
|
|
81
|
+
# not implement, so those runtimes hold at the last release that works there.
|
|
82
|
+
pin_old_i18n = RUBY_ENGINE == 'truffleruby' &&
|
|
83
|
+
Gem::Version.new(RUBY_ENGINE_VERSION) < Gem::Version.new('34.0.0')
|
|
84
|
+
|
|
49
85
|
spec.add_development_dependency 'create_github_release', '~> 2.1'
|
|
86
|
+
spec.add_development_dependency 'fiddle', '~> 1.1' if install_fiddle
|
|
50
87
|
spec.add_development_dependency 'fuubar', '~> 2.5'
|
|
88
|
+
spec.add_development_dependency 'i18n', '< 1.15' if pin_old_i18n
|
|
89
|
+
spec.add_development_dependency 'irb', '~> 1.16' if install_irb
|
|
51
90
|
spec.add_development_dependency 'main_branch_shared_rubocop_config', '~> 0.1'
|
|
52
91
|
spec.add_development_dependency 'parallel_tests', '~> 5.6'
|
|
53
92
|
spec.add_development_dependency 'rake', '~> 13.3'
|
|
93
|
+
spec.add_development_dependency 'redcarpet', '~> 3.6' if install_docs
|
|
54
94
|
spec.add_development_dependency 'rspec', '~> 3.13'
|
|
55
95
|
spec.add_development_dependency 'rubocop', '~> 1.82'
|
|
56
96
|
spec.add_development_dependency 'simplecov', '~> 1.0'
|
|
57
97
|
spec.add_development_dependency 'simplecov-lcov', '~> 0.9'
|
|
58
98
|
spec.add_development_dependency 'simplecov-rspec', '~> 1.1'
|
|
99
|
+
spec.add_development_dependency 'yard', '~> 0.9', '>= 0.9.28' if install_docs
|
|
100
|
+
spec.add_development_dependency 'yard_example_test', '~> 0.2', '>= 0.2.1' if install_docs
|
|
101
|
+
spec.add_development_dependency 'yard-lint', '~> 1.8' if install_yard_lint
|
|
59
102
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
103
|
+
# Specify which files should be added to the gem when it is released.
|
|
104
|
+
#
|
|
105
|
+
# This is an allowlist rather than a denylist. A denylist admitted every new
|
|
106
|
+
# development-only path by default, so the gem shipped `.github/`, `tasks/`, the
|
|
107
|
+
# husky hooks, and -- the reason this became an allowlist -- the `.claude/skills`
|
|
108
|
+
# symlink. Extracting a symlink needs a privilege that Windows grants only under
|
|
109
|
+
# Developer Mode or an elevated shell, so installing the gem there either failed
|
|
110
|
+
# outright or, on RubyGems new enough to fall back to a copy, silently duplicated
|
|
111
|
+
# the whole skills tree into the installed gem.
|
|
112
|
+
#
|
|
113
|
+
# spec/unit/gemspec_spec.rb guards both directions: nothing in the list may be a
|
|
114
|
+
# symlink, and every tracked file under lib/ must be present, so the allowlist
|
|
115
|
+
# cannot quietly drop runtime code.
|
|
116
|
+
#
|
|
117
|
+
# doc_files must stay in sync with the extra files named in .yardopts -- those are
|
|
118
|
+
# what rubydoc.info renders for the published documentation, so a file listed there
|
|
119
|
+
# but absent from the gem becomes a broken link.
|
|
120
|
+
doc_files = %w[
|
|
121
|
+
AI_POLICY.md
|
|
122
|
+
CHANGELOG.md
|
|
123
|
+
CODE_OF_CONDUCT.md
|
|
124
|
+
CONTRIBUTING.md
|
|
125
|
+
GOVERNANCE.md
|
|
126
|
+
LICENSE
|
|
127
|
+
MAINTAINERS.md
|
|
128
|
+
README.md
|
|
129
|
+
UPGRADING.md
|
|
130
|
+
]
|
|
70
131
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
end
|
|
132
|
+
# .yardopts drives the rubydoc.info build; the gemspec is included by convention.
|
|
133
|
+
build_files = %w[.yardopts git.gemspec]
|
|
74
134
|
|
|
75
|
-
# Specify which files should be added to the gem when it is released.
|
|
76
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
77
135
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
78
|
-
`git ls-files -z`.split("\x0").
|
|
136
|
+
`git ls-files -z`.split("\x0").select do |f|
|
|
137
|
+
f.start_with?('lib/') || doc_files.include?(f) || build_files.include?(f)
|
|
138
|
+
end
|
|
79
139
|
end
|
|
80
140
|
end
|
|
@@ -232,7 +232,7 @@ module Git
|
|
|
232
232
|
#
|
|
233
233
|
# @api private
|
|
234
234
|
#
|
|
235
|
-
# rubocop:disable Metrics/ParameterLists
|
|
235
|
+
# rubocop:disable-next Metrics/ParameterLists
|
|
236
236
|
def command_line_result(command, result, processed_out, processed_err, timeout, raise_on_failure)
|
|
237
237
|
Git::CommandLine::Result.new(command, result, processed_out, processed_err).tap do |processed_result|
|
|
238
238
|
raise Git::TimeoutError.new(processed_result, timeout) if result.timed_out?
|
|
@@ -242,7 +242,6 @@ module Git
|
|
|
242
242
|
raise Git::FailedError, processed_result if raise_on_failure && !result.success?
|
|
243
243
|
end
|
|
244
244
|
end
|
|
245
|
-
# rubocop:enable Metrics/ParameterLists
|
|
246
245
|
end
|
|
247
246
|
end
|
|
248
247
|
end
|
data/lib/git/commands/base.rb
CHANGED
|
@@ -453,7 +453,7 @@ module Git
|
|
|
453
453
|
#
|
|
454
454
|
# @example Feed bound object names to a git batch command
|
|
455
455
|
# bound = args_definition.bind(*args, **kwargs)
|
|
456
|
-
# stdin_content = Array(bound.
|
|
456
|
+
# stdin_content = Array(bound.object).map { |object| "#{object}\n" }.join
|
|
457
457
|
# with_stdin(stdin_content) do |reader|
|
|
458
458
|
# @execution_context.command_capturing('cat-file', '--batch-check', in: reader, raise_on_failure: false)
|
|
459
459
|
# end
|
|
@@ -49,9 +49,10 @@ module Git
|
|
|
49
49
|
# See https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt--s
|
|
50
50
|
flag_option :s
|
|
51
51
|
|
|
52
|
-
# Allow -t and -s to query broken or corrupt objects of unknown type
|
|
53
|
-
#
|
|
54
|
-
#
|
|
52
|
+
# Allow -t and -s to query broken or corrupt objects of unknown type.
|
|
53
|
+
# Git 2.28-2.49 rejects this flag in other modes; git 2.50+ accepts and
|
|
54
|
+
# ignores it everywhere (the unknown-type feature was removed; see issue 1709).
|
|
55
|
+
# See https://git-scm.com/docs/git-cat-file/2.49.0#Documentation/git-cat-file.txt---allow-unknown-type
|
|
55
56
|
flag_option :allow_unknown_type
|
|
56
57
|
|
|
57
58
|
# Map committer/author identities through the mailmap before reporting size
|
|
@@ -74,8 +75,6 @@ module Git
|
|
|
74
75
|
|
|
75
76
|
# Object name: SHA, ref, `HEAD`, treeish path reference, etc.
|
|
76
77
|
operand :object, required: true
|
|
77
|
-
|
|
78
|
-
requires_one_of :t, :s, when: :allow_unknown_type
|
|
79
78
|
end
|
|
80
79
|
|
|
81
80
|
# Execute `git cat-file` for a single object.
|
|
@@ -114,7 +113,8 @@ module Git
|
|
|
114
113
|
# @param options [Hash] command options
|
|
115
114
|
#
|
|
116
115
|
# @option options [Boolean, nil] :allow_unknown_type (nil) allow querying broken or corrupt objects of
|
|
117
|
-
# unknown type
|
|
116
|
+
# unknown type on git 2.28-2.49; git 2.50 removed the unknown-type feature
|
|
117
|
+
# and accepts this flag as a no-op
|
|
118
118
|
#
|
|
119
119
|
# @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
|
|
120
120
|
#
|
|
@@ -138,7 +138,8 @@ module Git
|
|
|
138
138
|
# @param options [Hash] command options
|
|
139
139
|
#
|
|
140
140
|
# @option options [Boolean, nil] :allow_unknown_type (nil) allow querying broken or corrupt objects of
|
|
141
|
-
# unknown type
|
|
141
|
+
# unknown type on git 2.28-2.49; git 2.50 removed the unknown-type feature
|
|
142
|
+
# and accepts this flag as a no-op
|
|
142
143
|
#
|
|
143
144
|
# @option options [Boolean, nil] :use_mailmap (nil) remap identities via mailmap (`--use-mailmap`)
|
|
144
145
|
#
|
data/lib/git/configuring.rb
CHANGED
|
@@ -88,6 +88,14 @@ module Git
|
|
|
88
88
|
#
|
|
89
89
|
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
90
90
|
#
|
|
91
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
92
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
93
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
94
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
95
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
96
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
97
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
98
|
+
#
|
|
91
99
|
def config_get(name, value_regex = nil, **options)
|
|
92
100
|
Private.assert_valid_opts!(CONFIG_GET_ALLOWED_OPTS, **options)
|
|
93
101
|
assert_valid_scope!(**options)
|
|
@@ -139,6 +147,14 @@ module Git
|
|
|
139
147
|
#
|
|
140
148
|
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
141
149
|
#
|
|
150
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
151
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
152
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
153
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
154
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
155
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
156
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
157
|
+
#
|
|
142
158
|
def config_get_all(name, value_regex = nil, **options)
|
|
143
159
|
Private.assert_valid_opts!(CONFIG_GET_ALL_ALLOWED_OPTS, **options)
|
|
144
160
|
assert_valid_scope!(**options)
|
|
@@ -238,6 +254,14 @@ module Git
|
|
|
238
254
|
#
|
|
239
255
|
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
240
256
|
#
|
|
257
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
258
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
259
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
260
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
261
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
262
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
263
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
264
|
+
#
|
|
241
265
|
def config_get_regexp(name_regex, value_regex = nil, **options)
|
|
242
266
|
Private.assert_valid_opts!(CONFIG_GET_REGEXP_ALLOWED_OPTS, **options)
|
|
243
267
|
assert_valid_scope!(**options)
|
|
@@ -529,6 +553,22 @@ module Git
|
|
|
529
553
|
#
|
|
530
554
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
531
555
|
#
|
|
556
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
557
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
558
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
559
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
560
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
561
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
562
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
563
|
+
#
|
|
564
|
+
# @note A `value_regex` that selects nothing does not make this method a no-op.
|
|
565
|
+
# `git config --replace-all` *adds* `value` as an additional entry when no
|
|
566
|
+
# existing value matches, and exits zero. On Git for Windows, a `value_regex`
|
|
567
|
+
# whose metacharacters span non-ASCII text therefore leaves the value it was
|
|
568
|
+
# meant to replace in place and silently creates a duplicate entry beside it.
|
|
569
|
+
# Confirm the result with {#config_get_all}, or match on ASCII text, when the
|
|
570
|
+
# key must end up single-valued.
|
|
571
|
+
#
|
|
532
572
|
def config_replace_all(name, value, value_regex = nil, **)
|
|
533
573
|
Private.assert_valid_opts!(CONFIG_REPLACE_ALL_ALLOWED_OPTS, **)
|
|
534
574
|
assert_valid_scope!(**)
|
|
@@ -621,6 +661,14 @@ module Git
|
|
|
621
661
|
#
|
|
622
662
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
623
663
|
#
|
|
664
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
665
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
666
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
667
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
668
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
669
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
670
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
671
|
+
#
|
|
624
672
|
def config_unset(name, value_regex = nil, **)
|
|
625
673
|
Private.assert_valid_opts!(CONFIG_UNSET_ALLOWED_OPTS, **)
|
|
626
674
|
assert_valid_scope!(**)
|
|
@@ -666,6 +714,14 @@ module Git
|
|
|
666
714
|
#
|
|
667
715
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
668
716
|
#
|
|
717
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather than
|
|
718
|
+
# characters, so a metacharacter such as `.` or a POSIX class such as
|
|
719
|
+
# `[[:alpha:]]` in `value_regex` never matches a whole multi-byte character. The
|
|
720
|
+
# failure is silent: nothing raises, and the outcome is indistinguishable from a
|
|
721
|
+
# `value_regex` that genuinely matches nothing. `git config` value patterns are
|
|
722
|
+
# POSIX extended regular expressions with no PCRE mode, so unlike
|
|
723
|
+
# {Git::Repository#grep} there is no alternate regex engine to select here.
|
|
724
|
+
#
|
|
669
725
|
def config_unset_all(name, value_regex = nil, **)
|
|
670
726
|
Private.assert_valid_opts!(CONFIG_UNSET_ALL_ALLOWED_OPTS, **)
|
|
671
727
|
assert_valid_scope!(**)
|
data/lib/git/log.rb
CHANGED
|
@@ -142,6 +142,25 @@ module Git
|
|
|
142
142
|
#
|
|
143
143
|
def grep(regex) = set_option(:grep, regex)
|
|
144
144
|
|
|
145
|
+
# Interprets {#grep} and {#author} patterns as Perl-compatible regular expressions
|
|
146
|
+
#
|
|
147
|
+
# Selects PCRE instead of git's default POSIX basic regular expressions for
|
|
148
|
+
# every pattern in the query. Requires a git built with PCRE support.
|
|
149
|
+
#
|
|
150
|
+
# @example Match a metacharacter against a non-ASCII character on Git for Windows
|
|
151
|
+
# repo.log.perl_regexp.grep('^.PFEL').execute
|
|
152
|
+
#
|
|
153
|
+
# @return [Git::Log] the current query builder
|
|
154
|
+
#
|
|
155
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather
|
|
156
|
+
# than characters, so a metacharacter such as `.` or a POSIX class such as
|
|
157
|
+
# `[[:alpha:]]` never matches a whole multi-byte character. The match fails
|
|
158
|
+
# silently: git exits zero and the result is empty. PCRE does match characters
|
|
159
|
+
# on that platform, but it is a different dialect than git's default, so
|
|
160
|
+
# selecting it is a deliberate choice by the caller.
|
|
161
|
+
#
|
|
162
|
+
def perl_regexp = set_option(:perl_regexp, true)
|
|
163
|
+
|
|
145
164
|
# Limits commits to those that touch the given path or paths
|
|
146
165
|
#
|
|
147
166
|
# @param path [String, Pathname, Array<String, Pathname>] path limiter input
|
|
@@ -41,7 +41,7 @@ module Git
|
|
|
41
41
|
|
|
42
42
|
# Option keys accepted by {#checkout}
|
|
43
43
|
#
|
|
44
|
-
CHECKOUT_ALLOWED_OPTS = %i[force f new_branch b start_point].freeze
|
|
44
|
+
CHECKOUT_ALLOWED_OPTS = %i[force f new_branch b start_point orphan].freeze
|
|
45
45
|
private_constant :CHECKOUT_ALLOWED_OPTS
|
|
46
46
|
|
|
47
47
|
# Option keys accepted by {#checkout_index}
|
|
@@ -130,6 +130,9 @@ module Git
|
|
|
130
130
|
# @example Create a new branch with a name different from the start point
|
|
131
131
|
# repo.checkout('main', new_branch: 'new-feature')
|
|
132
132
|
#
|
|
133
|
+
# @example Create and check out an unborn branch with no history
|
|
134
|
+
# repo.checkout('gh-pages', orphan: true)
|
|
135
|
+
#
|
|
133
136
|
# @example Force checkout discarding local changes
|
|
134
137
|
# repo.checkout('main', force: true)
|
|
135
138
|
#
|
|
@@ -151,13 +154,25 @@ module Git
|
|
|
151
154
|
#
|
|
152
155
|
# @option opts [Boolean, nil] :f (nil) alias for `:force`
|
|
153
156
|
#
|
|
157
|
+
# @option opts [Boolean, String, nil] :orphan (nil) when `true`, creates a
|
|
158
|
+
# new unborn branch named `branch` whose first commit has no parents
|
|
159
|
+
#
|
|
160
|
+
# When a `String`, creates an unborn branch with that name, using
|
|
161
|
+
# `branch` as the start point for the working tree and index.
|
|
162
|
+
#
|
|
163
|
+
# `false` and `nil` are both treated as unset. A blank branch name is
|
|
164
|
+
# rejected rather than ignored.
|
|
165
|
+
#
|
|
154
166
|
# @option opts [String, nil] :start_point (nil) the commit or branch to
|
|
155
|
-
# start the new branch from; used together with `new_branch: true`
|
|
167
|
+
# start the new branch from; used together with `new_branch: true` or
|
|
168
|
+
# `orphan: true`
|
|
156
169
|
#
|
|
157
170
|
# @return [String] git's stdout from the checkout
|
|
158
171
|
#
|
|
159
172
|
# @raise [ArgumentError] if unsupported options are provided
|
|
160
173
|
#
|
|
174
|
+
# @raise [ArgumentError] if `:orphan` is given a blank or missing branch name
|
|
175
|
+
#
|
|
161
176
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
162
177
|
#
|
|
163
178
|
def checkout(branch = nil, opts = {})
|
|
@@ -680,19 +695,24 @@ module Git
|
|
|
680
695
|
:unborn
|
|
681
696
|
end
|
|
682
697
|
|
|
683
|
-
# Translates
|
|
698
|
+
# Translates {#checkout} options to the new command interface
|
|
684
699
|
#
|
|
685
700
|
# Legacy callers passed combinations like:
|
|
686
701
|
# checkout('branch', new_branch: true, start_point: 'main')
|
|
687
702
|
# which should map to:
|
|
688
703
|
# checkout('main', b: 'branch')
|
|
689
704
|
#
|
|
705
|
+
# `orphan: true` follows the same shape, naming the unborn branch:
|
|
706
|
+
# checkout('branch', orphan: true, start_point: 'main')
|
|
707
|
+
# maps to:
|
|
708
|
+
# checkout('main', orphan: 'branch')
|
|
709
|
+
#
|
|
690
710
|
# @param branch [String, nil] the branch argument passed to {#checkout}
|
|
691
711
|
#
|
|
692
712
|
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
693
713
|
#
|
|
694
|
-
# @return [Array] a two-element tuple
|
|
695
|
-
# translated checkout arguments
|
|
714
|
+
# @return [Array((String, nil), Hash)] a two-element tuple
|
|
715
|
+
# `[target, options]` containing the translated checkout arguments
|
|
696
716
|
#
|
|
697
717
|
# `target` (`String` or `nil`) is the branch or commit to check out.
|
|
698
718
|
# `options` is a `Hash` of keyword arguments for
|
|
@@ -701,15 +721,69 @@ module Git
|
|
|
701
721
|
# @api private
|
|
702
722
|
#
|
|
703
723
|
def translate_checkout_opts(branch, checkout_options)
|
|
724
|
+
checkout_options = normalize_orphan_option(checkout_options)
|
|
725
|
+
|
|
704
726
|
if checkout_options[:new_branch] == true || checkout_options[:b] == true
|
|
705
727
|
[checkout_options[:start_point], checkout_options.except(:new_branch, :b, :start_point).merge(b: branch)]
|
|
706
728
|
elsif checkout_options[:new_branch].is_a?(String)
|
|
707
729
|
[branch, checkout_options.except(:new_branch).merge(b: checkout_options[:new_branch])]
|
|
730
|
+
elsif checkout_options[:orphan] == true
|
|
731
|
+
translate_orphan_opts(branch, checkout_options)
|
|
708
732
|
else
|
|
709
733
|
[branch, checkout_options]
|
|
710
734
|
end
|
|
711
735
|
end
|
|
712
736
|
|
|
737
|
+
# Normalizes the `:orphan` option, rejecting names that git would never see
|
|
738
|
+
#
|
|
739
|
+
# `:orphan` is a value option on the underlying command, so a literal
|
|
740
|
+
# `false` would be emitted as `--orphan false` and create a branch named
|
|
741
|
+
# "false". Flag options such as `:force` already ignore `false`; this
|
|
742
|
+
# gives `:orphan` the same behavior.
|
|
743
|
+
#
|
|
744
|
+
# A blank name is rejected rather than dropped: the argument DSL omits
|
|
745
|
+
# empty values, so `orphan: ''` would otherwise degrade silently into a
|
|
746
|
+
# plain checkout.
|
|
747
|
+
#
|
|
748
|
+
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
749
|
+
#
|
|
750
|
+
# @return [Hash] the options with a `false` `:orphan` key removed
|
|
751
|
+
#
|
|
752
|
+
# @raise [ArgumentError] if `:orphan` is given a blank branch name
|
|
753
|
+
#
|
|
754
|
+
# @api private
|
|
755
|
+
#
|
|
756
|
+
def normalize_orphan_option(checkout_options)
|
|
757
|
+
orphan = checkout_options[:orphan]
|
|
758
|
+
return checkout_options.except(:orphan) if orphan == false
|
|
759
|
+
raise ArgumentError, 'orphan requires a non-empty branch name' if orphan.is_a?(String) && orphan.strip.empty?
|
|
760
|
+
|
|
761
|
+
checkout_options
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
# Translates `orphan: true` into the command's `:orphan` value option
|
|
765
|
+
#
|
|
766
|
+
# `orphan: true` names the unborn branch from the positional argument and
|
|
767
|
+
# takes its start point from `:start_point`, mirroring `new_branch: true`.
|
|
768
|
+
#
|
|
769
|
+
# @param branch [String, nil] the branch argument passed to {#checkout}
|
|
770
|
+
#
|
|
771
|
+
# @param checkout_options [Hash] the raw options passed to {#checkout}
|
|
772
|
+
#
|
|
773
|
+
# @return [Array((String, nil), Hash)] a two-element tuple
|
|
774
|
+
# `[target, options]` containing the translated checkout arguments
|
|
775
|
+
#
|
|
776
|
+
# @raise [ArgumentError] if `branch` is blank (`nil`, empty, or whitespace
|
|
777
|
+
# only), since the unborn branch would otherwise have no name
|
|
778
|
+
#
|
|
779
|
+
# @api private
|
|
780
|
+
#
|
|
781
|
+
def translate_orphan_opts(branch, checkout_options)
|
|
782
|
+
raise ArgumentError, 'orphan: true requires a branch name' if branch.to_s.strip.empty?
|
|
783
|
+
|
|
784
|
+
[checkout_options[:start_point], checkout_options.except(:start_point).merge(orphan: branch)]
|
|
785
|
+
end
|
|
786
|
+
|
|
713
787
|
# Normalizes path specifications for Git commands
|
|
714
788
|
#
|
|
715
789
|
# @param pathspecs [String, Pathname, Array<String, Pathname>, nil]
|
|
@@ -18,7 +18,7 @@ module Git
|
|
|
18
18
|
# @return [Array<Symbol>] the supported option keys
|
|
19
19
|
#
|
|
20
20
|
FULL_LOG_COMMITS_ALLOWED_OPTS = %i[
|
|
21
|
-
count all cherry since until grep author between object path_limiter skip merges
|
|
21
|
+
count all cherry since until grep author between object path_limiter skip merges perl_regexp
|
|
22
22
|
].freeze
|
|
23
23
|
private_constant :FULL_LOG_COMMITS_ALLOWED_OPTS
|
|
24
24
|
|
|
@@ -68,6 +68,13 @@ module Git
|
|
|
68
68
|
#
|
|
69
69
|
# @option opts [Boolean, nil] :merges (nil) include only merge commits
|
|
70
70
|
#
|
|
71
|
+
# @option opts [Boolean, nil] :perl_regexp (nil) interpret the `:grep` and
|
|
72
|
+
# `:author` patterns as Perl-compatible regular expressions (PCRE) instead of
|
|
73
|
+
# git's default POSIX basic regular expressions
|
|
74
|
+
#
|
|
75
|
+
# Requires a git built with PCRE support; git otherwise fails with
|
|
76
|
+
# "cannot use Perl-compatible regexes...".
|
|
77
|
+
#
|
|
71
78
|
# @return [Array<Hash>] the parsed raw log output for each commit
|
|
72
79
|
#
|
|
73
80
|
# @raise [ArgumentError] if unsupported options are provided
|
|
@@ -76,6 +83,14 @@ module Git
|
|
|
76
83
|
#
|
|
77
84
|
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
78
85
|
#
|
|
86
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather
|
|
87
|
+
# than characters, so a metacharacter such as `.` or a POSIX class such as
|
|
88
|
+
# `[[:alpha:]]` never matches a whole multi-byte character in a `:grep` or
|
|
89
|
+
# `:author` pattern. The match fails silently: git exits zero and the result
|
|
90
|
+
# is empty. Pass `perl_regexp: true` to select PCRE, which does match
|
|
91
|
+
# characters. PCRE is a different dialect than git's default, so this is a
|
|
92
|
+
# deliberate choice by the caller rather than a transparent substitution.
|
|
93
|
+
#
|
|
79
94
|
# @see https://git-scm.com/docs/git-log git-log
|
|
80
95
|
#
|
|
81
96
|
def full_log_commits(opts = {})
|
|
@@ -113,6 +128,14 @@ module Git
|
|
|
113
128
|
module Private
|
|
114
129
|
module_function
|
|
115
130
|
|
|
131
|
+
# Log option keys forwarded to {Git::Commands::Log#call} under the same name
|
|
132
|
+
#
|
|
133
|
+
# The remaining options are renamed or reshaped by {#log_base_call_options}.
|
|
134
|
+
#
|
|
135
|
+
# @return [Array<Symbol>] the pass-through option keys
|
|
136
|
+
#
|
|
137
|
+
PASSTHROUGH_LOG_OPTS = %i[all cherry since until grep author perl_regexp].freeze
|
|
138
|
+
|
|
116
139
|
# Validates the :count log option
|
|
117
140
|
#
|
|
118
141
|
# @param opts [Hash] the log options
|
|
@@ -195,6 +218,9 @@ module Git
|
|
|
195
218
|
# @option opts [String, nil] :author (nil) only include commits whose author
|
|
196
219
|
# matches this pattern
|
|
197
220
|
#
|
|
221
|
+
# @option opts [Boolean, nil] :perl_regexp (nil) interpret the `:grep` and
|
|
222
|
+
# `:author` patterns as Perl-compatible regular expressions
|
|
223
|
+
#
|
|
198
224
|
# @option opts [Integer, nil] :count (nil) maximum number of commits to return
|
|
199
225
|
#
|
|
200
226
|
# @option opts [String, Pathname, Array<String, Pathname>, nil] :path_limiter (nil)
|
|
@@ -207,16 +233,14 @@ module Git
|
|
|
207
233
|
# @return [Hash] keyword options for {Git::Commands::Log#call}
|
|
208
234
|
#
|
|
209
235
|
def log_base_call_options(opts, extra = {})
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
path: opts[:path_limiter] ? Array(opts[:path_limiter]) : nil
|
|
219
|
-
}.merge(extra).compact
|
|
236
|
+
opts
|
|
237
|
+
.slice(*PASSTHROUGH_LOG_OPTS)
|
|
238
|
+
.merge(
|
|
239
|
+
max_count: opts[:count],
|
|
240
|
+
path: opts[:path_limiter] ? Array(opts[:path_limiter]) : nil
|
|
241
|
+
)
|
|
242
|
+
.merge(extra)
|
|
243
|
+
.compact
|
|
220
244
|
end
|
|
221
245
|
|
|
222
246
|
# Executes git log and parses the raw output
|
|
@@ -454,7 +454,7 @@ module Git
|
|
|
454
454
|
end
|
|
455
455
|
|
|
456
456
|
# Option keys accepted by {#grep}
|
|
457
|
-
GREP_ALLOWED_OPTS = %i[ignore_case i invert_match v extended_regexp E object].freeze
|
|
457
|
+
GREP_ALLOWED_OPTS = %i[ignore_case i invert_match v extended_regexp E perl_regexp P object].freeze
|
|
458
458
|
private_constant :GREP_ALLOWED_OPTS
|
|
459
459
|
|
|
460
460
|
# Search tracked file contents in a git tree for a pattern
|
|
@@ -475,6 +475,9 @@ module Git
|
|
|
475
475
|
# @example Case-insensitive search
|
|
476
476
|
# repo.grep('todo', nil, ignore_case: true)
|
|
477
477
|
#
|
|
478
|
+
# @example Match a metacharacter against a non-ASCII character on Git for Windows
|
|
479
|
+
# repo.grep('^.PFEL', nil, perl_regexp: true)
|
|
480
|
+
#
|
|
478
481
|
# @param pattern [String] the pattern to search for
|
|
479
482
|
#
|
|
480
483
|
# @param path_limiter [String, Pathname, Array<String, Pathname>, nil]
|
|
@@ -499,6 +502,14 @@ module Git
|
|
|
499
502
|
#
|
|
500
503
|
# Alias: :E
|
|
501
504
|
#
|
|
505
|
+
# @option opts [Boolean, nil] :perl_regexp (nil) use Perl-compatible regular
|
|
506
|
+
# expressions (PCRE) for the pattern
|
|
507
|
+
#
|
|
508
|
+
# Requires a git built with PCRE support; git otherwise fails with
|
|
509
|
+
# "cannot use Perl-compatible regexes...".
|
|
510
|
+
#
|
|
511
|
+
# Alias: :P
|
|
512
|
+
#
|
|
502
513
|
# @return [Hash<String, Array<Array(Integer, String)>>] a hash mapping
|
|
503
514
|
# each `"treeish:filename"` key to an array of `[line_number, text]`
|
|
504
515
|
# pairs; returns an empty hash when no lines match
|
|
@@ -508,6 +519,16 @@ module Git
|
|
|
508
519
|
# @raise [Git::FailedError] if git exits with a non-zero status and
|
|
509
520
|
# stderr is non-empty (e.g. bad object reference)
|
|
510
521
|
#
|
|
522
|
+
# @note On Git for Windows, git's default regex engine matches *bytes* rather
|
|
523
|
+
# than characters, so a metacharacter such as `.` or a POSIX class such as
|
|
524
|
+
# `[[:alpha:]]` never matches a whole multi-byte character. The failure is
|
|
525
|
+
# silent: nothing raises, and the empty hash returned is indistinguishable
|
|
526
|
+
# from a pattern that genuinely does not occur in the tree. Pass
|
|
527
|
+
# `perl_regexp: true` to select PCRE, which does match characters. PCRE is a
|
|
528
|
+
# different dialect than git's default POSIX basic/extended regular
|
|
529
|
+
# expressions, so this is a deliberate choice by the caller rather than a
|
|
530
|
+
# transparent substitution, and it requires a git built with PCRE support.
|
|
531
|
+
#
|
|
511
532
|
# @see https://git-scm.com/docs/git-grep git-grep documentation
|
|
512
533
|
#
|
|
513
534
|
def grep(pattern, path_limiter = nil, opts = {})
|