git 5.0.0.beta.1 → 5.0.0.beta.2
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/.github/copilot-instructions.md +6 -0
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
- data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +28 -14
- data/.github/skills/facade-implementation/SKILL.md +14 -0
- data/.github/skills/facade-test-conventions/SKILL.md +14 -0
- data/.rubocop.yml +5 -0
- data/README.md +51 -11
- data/UPGRADING.md +141 -0
- data/git.gemspec +5 -0
- data/lib/git/branch.rb +7 -18
- data/lib/git/branches.rb +2 -10
- data/lib/git/command_line/base.rb +10 -0
- data/lib/git/command_line/capturing.rb +5 -3
- data/lib/git/command_line/streaming.rb +5 -3
- data/lib/git/command_line.rb +3 -3
- data/lib/git/commands/base.rb +7 -6
- data/lib/git/commands/cat_file/batch.rb +6 -1
- data/lib/git/commands/cat_file/raw.rb +7 -1
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +5 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +1 -1
- data/lib/git/commands/update_ref/batch.rb +1 -1
- data/lib/git/commands/version.rb +5 -0
- data/lib/git/commands.rb +5 -7
- data/lib/git/config.rb +17 -0
- data/lib/git/config_entry_info.rb +106 -0
- data/lib/git/configuring.rb +665 -0
- data/lib/git/deprecation.rb +9 -0
- data/lib/git/diff.rb +4 -8
- data/lib/git/diff_path_status.rb +2 -13
- data/lib/git/diff_stats.rb +1 -9
- data/lib/git/execution_context/global.rb +3 -28
- data/lib/git/execution_context/repository.rb +30 -41
- data/lib/git/execution_context.rb +43 -24
- data/lib/git/log.rb +3 -9
- data/lib/git/object.rb +14 -21
- data/lib/git/parsers/config_entry.rb +110 -0
- data/lib/git/parsers/ls_remote.rb +79 -0
- data/lib/git/remote.rb +7 -20
- data/lib/git/repository/branching.rb +183 -12
- data/lib/git/repository/committing.rb +64 -68
- data/lib/git/repository/configuring.rb +208 -13
- data/lib/git/repository/context_helpers.rb +264 -0
- data/lib/git/repository/factories.rb +682 -0
- data/lib/git/repository/inspecting.rb +99 -0
- data/lib/git/repository/maintenance.rb +65 -0
- data/lib/git/repository/merging.rb +63 -1
- data/lib/git/repository/object_operations.rb +133 -35
- data/lib/git/repository/path_resolver.rb +1 -1
- data/lib/git/repository/remote_operations.rb +166 -21
- data/lib/git/repository/staging.rb +187 -23
- data/lib/git/repository/stashing.rb +39 -3
- data/lib/git/repository/status_operations.rb +21 -0
- data/lib/git/repository.rb +68 -129
- data/lib/git/stash.rb +2 -9
- data/lib/git/stashes.rb +2 -7
- data/lib/git/status.rb +8 -17
- data/lib/git/version.rb +2 -2
- data/lib/git/worktree.rb +2 -15
- data/lib/git/worktrees.rb +2 -15
- data/lib/git.rb +180 -77
- data/redesign/3_architecture_implementation.md +148 -111
- data/redesign/Phase 4 - Step A.md +360 -0
- data/redesign/beta_release.md +107 -0
- data/redesign/c1c2_audit.md +566 -0
- data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
- data/redesign/config_design.rb +501 -0
- metadata +19 -5
- data/lib/git/base.rb +0 -1204
- data/lib/git/lib.rb +0 -2855
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/config_entry_info'
|
|
4
|
+
require 'git/parsers/config_entry'
|
|
5
|
+
require 'git/commands/config_option_syntax'
|
|
6
|
+
|
|
7
|
+
module Git
|
|
8
|
+
# Mixin that adds structured `git config` read and write operations
|
|
9
|
+
#
|
|
10
|
+
# Include or extend this module to gain the full suite of `config_*` methods.
|
|
11
|
+
# The including/extending class must implement two private methods:
|
|
12
|
+
#
|
|
13
|
+
# - {#execution_context} — returns a `Git::ExecutionContext` used to run commands
|
|
14
|
+
# - {#assert_valid_scope!} — raises `ArgumentError` if a requested scope is not
|
|
15
|
+
# valid in this context (e.g., `:local` is not valid without a repository)
|
|
16
|
+
#
|
|
17
|
+
# Read methods that return {Git::ConfigEntryInfo} objects merge
|
|
18
|
+
# `show_scope: true, show_origin: true, null: true` into the options so that
|
|
19
|
+
# every returned entry carries its full provenance. Two exceptions apply:
|
|
20
|
+
# {#config_get_urlmatch} merges only `show_scope: true, null: true` because
|
|
21
|
+
# git does not support `--show-origin` with `--get-urlmatch` (those entries
|
|
22
|
+
# always have `origin: nil`); {#config_get_colorbool} returns a plain `String`
|
|
23
|
+
# and does not use these output-format options at all.
|
|
24
|
+
#
|
|
25
|
+
# @example Include in a repository class
|
|
26
|
+
# class MyRepo
|
|
27
|
+
# include Git::Configuring
|
|
28
|
+
# private
|
|
29
|
+
# def execution_context = @ctx
|
|
30
|
+
# def assert_valid_scope!(**) = nil # all scopes allowed
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# @example Extend the Git module for global/system config
|
|
34
|
+
# extend Git::Configuring
|
|
35
|
+
# def self.execution_context = Git::ExecutionContext::Global.new
|
|
36
|
+
# private_class_method :execution_context
|
|
37
|
+
# def self.assert_valid_scope!(**opts)
|
|
38
|
+
# # reject :local, :worktree, :blob when called without a repository
|
|
39
|
+
# end
|
|
40
|
+
# private_class_method :assert_valid_scope!
|
|
41
|
+
#
|
|
42
|
+
# @api public
|
|
43
|
+
#
|
|
44
|
+
module Configuring # rubocop:disable Metrics/ModuleLength
|
|
45
|
+
# @!group Read Operations
|
|
46
|
+
|
|
47
|
+
# @api private
|
|
48
|
+
CONFIG_GET_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes type default].freeze
|
|
49
|
+
private_constant :CONFIG_GET_ALLOWED_OPTS
|
|
50
|
+
|
|
51
|
+
# Retrieve a single config entry by key name
|
|
52
|
+
#
|
|
53
|
+
# Wraps `git config --get --show-scope --show-origin --null`.
|
|
54
|
+
#
|
|
55
|
+
# @example Get a single config entry
|
|
56
|
+
# entry = repo.config_get('user.name')
|
|
57
|
+
# entry&.value # => "Alice"
|
|
58
|
+
#
|
|
59
|
+
# @param name [String] the full dotted config key (e.g. `"user.name"`)
|
|
60
|
+
#
|
|
61
|
+
# @param value_regex [String, nil] optional regex to filter by value
|
|
62
|
+
#
|
|
63
|
+
# @param options [Hash] scope and filter options forwarded to the command
|
|
64
|
+
#
|
|
65
|
+
# @option options [Boolean, nil] :global (nil) read from `~/.gitconfig`
|
|
66
|
+
#
|
|
67
|
+
# @option options [Boolean, nil] :system (nil) read from the system config file
|
|
68
|
+
#
|
|
69
|
+
# @option options [Boolean, nil] :local (nil) read from `.git/config`
|
|
70
|
+
#
|
|
71
|
+
# @option options [Boolean, nil] :worktree (nil) read from the worktree config
|
|
72
|
+
#
|
|
73
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
74
|
+
#
|
|
75
|
+
# @option options [String, nil] :blob (nil) read from a git blob object
|
|
76
|
+
#
|
|
77
|
+
# @option options [Boolean, nil] :includes (nil) follow include directives
|
|
78
|
+
#
|
|
79
|
+
# @option options [Boolean, nil] :no_includes (nil) suppress include directives
|
|
80
|
+
#
|
|
81
|
+
# @option options [String, nil] :type (nil) enforce a type constraint on the value
|
|
82
|
+
#
|
|
83
|
+
# @option options [String, nil] :default (nil) value to return when the key is missing
|
|
84
|
+
#
|
|
85
|
+
# @return [Git::ConfigEntryInfo, nil] the matching entry, or `nil` when not found
|
|
86
|
+
#
|
|
87
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
88
|
+
#
|
|
89
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
90
|
+
#
|
|
91
|
+
def config_get(name, value_regex = nil, **options)
|
|
92
|
+
Private.assert_valid_opts!(CONFIG_GET_ALLOWED_OPTS, **options)
|
|
93
|
+
assert_valid_scope!(**options)
|
|
94
|
+
options = options.merge(show_scope: true, show_origin: true, null: true)
|
|
95
|
+
cmd = Git::Commands::ConfigOptionSyntax::Get.new(execution_context)
|
|
96
|
+
output = cmd.call(name, value_regex, **options).stdout
|
|
97
|
+
Git::Parsers::ConfigEntry.parse_get(name, output)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @api private
|
|
101
|
+
CONFIG_GET_ALL_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes type].freeze
|
|
102
|
+
private_constant :CONFIG_GET_ALL_ALLOWED_OPTS
|
|
103
|
+
|
|
104
|
+
# Retrieve all values for a multi-valued config key
|
|
105
|
+
#
|
|
106
|
+
# Wraps `git config --get-all --show-scope --show-origin --null`.
|
|
107
|
+
#
|
|
108
|
+
# @example Get all values for a multi-valued key
|
|
109
|
+
# entries = repo.config_get_all('remote.origin.url')
|
|
110
|
+
# entries.map(&:value) # => ["https://...", "git@..."]
|
|
111
|
+
#
|
|
112
|
+
# @param name [String] the full dotted config key
|
|
113
|
+
#
|
|
114
|
+
# @param value_regex [String, nil] optional regex to filter by value
|
|
115
|
+
#
|
|
116
|
+
# @param options [Hash] scope and filter options (see {#config_get})
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<Git::ConfigEntryInfo>] all entries matching the key
|
|
119
|
+
#
|
|
120
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
121
|
+
#
|
|
122
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
123
|
+
#
|
|
124
|
+
def config_get_all(name, value_regex = nil, **options)
|
|
125
|
+
Private.assert_valid_opts!(CONFIG_GET_ALL_ALLOWED_OPTS, **options)
|
|
126
|
+
assert_valid_scope!(**options)
|
|
127
|
+
options = options.merge(show_scope: true, show_origin: true, null: true)
|
|
128
|
+
cmd = Git::Commands::ConfigOptionSyntax::GetAll.new(execution_context)
|
|
129
|
+
output = cmd.call(name, value_regex, **options).stdout
|
|
130
|
+
Git::Parsers::ConfigEntry.parse_get_all(name, output)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @api private
|
|
134
|
+
CONFIG_GET_COLORBOOL_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes].freeze
|
|
135
|
+
private_constant :CONFIG_GET_COLORBOOL_ALLOWED_OPTS
|
|
136
|
+
|
|
137
|
+
# @overload config_get_colorbool(name, stdout_is_tty = nil, **options)
|
|
138
|
+
#
|
|
139
|
+
# Query whether color output is enabled for a given config slot
|
|
140
|
+
#
|
|
141
|
+
# Wraps `git config --get-colorbool`.
|
|
142
|
+
#
|
|
143
|
+
# @example Check color status for color.ui
|
|
144
|
+
# repo.config_get_colorbool('color.ui') # => "true"
|
|
145
|
+
#
|
|
146
|
+
# @param name [String] the config key to check (e.g. `"color.ui"`)
|
|
147
|
+
#
|
|
148
|
+
# @param stdout_is_tty [Boolean, nil] whether stdout is a TTY
|
|
149
|
+
#
|
|
150
|
+
# @param options [Hash] scope and filter options
|
|
151
|
+
#
|
|
152
|
+
# @option options [Boolean, nil] :global (nil) read from `~/.gitconfig`
|
|
153
|
+
#
|
|
154
|
+
# @option options [Boolean, nil] :system (nil) read from the system config file
|
|
155
|
+
#
|
|
156
|
+
# @option options [Boolean, nil] :local (nil) read from `.git/config`
|
|
157
|
+
#
|
|
158
|
+
# @option options [Boolean, nil] :worktree (nil) read from the worktree config
|
|
159
|
+
#
|
|
160
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
161
|
+
#
|
|
162
|
+
# @option options [String, nil] :blob (nil) read from a git blob object
|
|
163
|
+
#
|
|
164
|
+
# @option options [Boolean, nil] :includes (nil) follow include directives (`--includes`)
|
|
165
|
+
#
|
|
166
|
+
# @option options [Boolean, nil] :no_includes (nil) suppress include directives (`--no-includes`)
|
|
167
|
+
#
|
|
168
|
+
# @return [String] `"true"` or `"false"`
|
|
169
|
+
#
|
|
170
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
171
|
+
#
|
|
172
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
173
|
+
#
|
|
174
|
+
def config_get_colorbool(name, stdout_is_tty = nil, **)
|
|
175
|
+
Private.assert_valid_opts!(CONFIG_GET_COLORBOOL_ALLOWED_OPTS, **)
|
|
176
|
+
assert_valid_scope!(**)
|
|
177
|
+
cmd = Git::Commands::ConfigOptionSyntax::GetColorBool.new(execution_context)
|
|
178
|
+
cmd.call(name, stdout_is_tty, **).stdout.chomp
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# @api private
|
|
182
|
+
CONFIG_GET_REGEXP_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes type].freeze
|
|
183
|
+
private_constant :CONFIG_GET_REGEXP_ALLOWED_OPTS
|
|
184
|
+
|
|
185
|
+
# Retrieve all config entries whose key matches a regular expression
|
|
186
|
+
#
|
|
187
|
+
# Wraps `git config --get-regexp --show-scope --show-origin --null`.
|
|
188
|
+
#
|
|
189
|
+
# @example Get all remote-related config entries
|
|
190
|
+
# entries = repo.config_get_regexp('remote\\.')
|
|
191
|
+
# entries.map(&:key) # => ["remote.origin.url", ...]
|
|
192
|
+
#
|
|
193
|
+
# @param name_regex [String] regex matched against config key names
|
|
194
|
+
#
|
|
195
|
+
# @param value_regex [String, nil] optional regex to filter by value
|
|
196
|
+
#
|
|
197
|
+
# @param options [Hash] scope and filter options (see {#config_get})
|
|
198
|
+
#
|
|
199
|
+
# @return [Array<Git::ConfigEntryInfo>] all entries whose key matches the regex
|
|
200
|
+
#
|
|
201
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
202
|
+
#
|
|
203
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
204
|
+
#
|
|
205
|
+
def config_get_regexp(name_regex, value_regex = nil, **options)
|
|
206
|
+
Private.assert_valid_opts!(CONFIG_GET_REGEXP_ALLOWED_OPTS, **options)
|
|
207
|
+
assert_valid_scope!(**options)
|
|
208
|
+
options = options.merge(show_scope: true, show_origin: true, null: true)
|
|
209
|
+
cmd = Git::Commands::ConfigOptionSyntax::GetRegexp.new(execution_context)
|
|
210
|
+
output = cmd.call(name_regex, value_regex, **options).stdout
|
|
211
|
+
Git::Parsers::ConfigEntry.parse_list(output)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @api private
|
|
215
|
+
CONFIG_GET_URLMATCH_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes type].freeze
|
|
216
|
+
private_constant :CONFIG_GET_URLMATCH_ALLOWED_OPTS
|
|
217
|
+
|
|
218
|
+
# Retrieve config entries whose URL pattern matches a given URL
|
|
219
|
+
#
|
|
220
|
+
# Wraps `git config --get-urlmatch --show-scope --null`.
|
|
221
|
+
#
|
|
222
|
+
# Note: `--show-origin` is not supported by git for `--get-urlmatch`, so
|
|
223
|
+
# the {Git::ConfigEntryInfo} entries returned by this method always have
|
|
224
|
+
# `origin: nil`.
|
|
225
|
+
#
|
|
226
|
+
# @example Get config entries for a specific URL
|
|
227
|
+
# entries = repo.config_get_urlmatch('http', 'https://github.com/user/repo')
|
|
228
|
+
# entries.map(&:key)
|
|
229
|
+
#
|
|
230
|
+
# @param name [String] the config section or key prefix to look up
|
|
231
|
+
#
|
|
232
|
+
# @param url [String] the URL to match against
|
|
233
|
+
#
|
|
234
|
+
# @param options [Hash] scope and filter options (see {#config_get})
|
|
235
|
+
#
|
|
236
|
+
# @return [Array<Git::ConfigEntryInfo>] all entries matching the URL; `origin` is `nil` on each
|
|
237
|
+
#
|
|
238
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
239
|
+
#
|
|
240
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
241
|
+
#
|
|
242
|
+
def config_get_urlmatch(name, url, **options)
|
|
243
|
+
Private.assert_valid_opts!(CONFIG_GET_URLMATCH_ALLOWED_OPTS, **options)
|
|
244
|
+
assert_valid_scope!(**options)
|
|
245
|
+
options = options.merge(show_scope: true, null: true)
|
|
246
|
+
cmd = Git::Commands::ConfigOptionSyntax::GetUrlmatch.new(execution_context)
|
|
247
|
+
output = cmd.call(name, url, **options).stdout
|
|
248
|
+
Git::Parsers::ConfigEntry.parse_urlmatch(output)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# @api private
|
|
252
|
+
CONFIG_LIST_ALLOWED_OPTS = %i[global system local worktree file f blob includes no_includes type].freeze
|
|
253
|
+
private_constant :CONFIG_LIST_ALLOWED_OPTS
|
|
254
|
+
|
|
255
|
+
# List all visible config entries
|
|
256
|
+
#
|
|
257
|
+
# Wraps `git config --list --show-scope --show-origin --null`.
|
|
258
|
+
#
|
|
259
|
+
# @example List all config entries
|
|
260
|
+
# entries = repo.config_list
|
|
261
|
+
# entries.first.scope # => "local"
|
|
262
|
+
#
|
|
263
|
+
# @param options [Hash] scope and filter options (see {#config_get})
|
|
264
|
+
#
|
|
265
|
+
# @return [Array<Git::ConfigEntryInfo>] all visible config entries
|
|
266
|
+
#
|
|
267
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
268
|
+
#
|
|
269
|
+
# @raise [Git::FailedError] if git exits with an unexpected non-zero status
|
|
270
|
+
#
|
|
271
|
+
def config_list(**options)
|
|
272
|
+
Private.assert_valid_opts!(CONFIG_LIST_ALLOWED_OPTS, **options)
|
|
273
|
+
assert_valid_scope!(**options)
|
|
274
|
+
options = options.merge(show_scope: true, show_origin: true, null: true)
|
|
275
|
+
cmd = Git::Commands::ConfigOptionSyntax::List.new(execution_context)
|
|
276
|
+
output = cmd.call(**options).stdout
|
|
277
|
+
Git::Parsers::ConfigEntry.parse_list(output)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# @!endgroup
|
|
281
|
+
|
|
282
|
+
# @!group Write Operations
|
|
283
|
+
|
|
284
|
+
# @api private
|
|
285
|
+
CONFIG_ADD_ALLOWED_OPTS = %i[global system local worktree file f blob type].freeze
|
|
286
|
+
private_constant :CONFIG_ADD_ALLOWED_OPTS
|
|
287
|
+
|
|
288
|
+
# @overload config_add(name, value, **options)
|
|
289
|
+
#
|
|
290
|
+
# Append a value to a multi-valued config key
|
|
291
|
+
#
|
|
292
|
+
# Wraps `git config --add`.
|
|
293
|
+
#
|
|
294
|
+
# @example Append a URL to a multi-valued remote key
|
|
295
|
+
# repo.config_add('remote.origin.url', 'git@github.com:user/repo.git')
|
|
296
|
+
#
|
|
297
|
+
# @param name [String] the full dotted config key
|
|
298
|
+
#
|
|
299
|
+
# @param value [String] the value to append
|
|
300
|
+
#
|
|
301
|
+
# @param options [Hash] scope options
|
|
302
|
+
#
|
|
303
|
+
# @option options [Boolean, nil] :global (nil) write to `~/.gitconfig`
|
|
304
|
+
#
|
|
305
|
+
# @option options [Boolean, nil] :system (nil) write to the system config file
|
|
306
|
+
#
|
|
307
|
+
# @option options [Boolean, nil] :local (nil) write to `.git/config`
|
|
308
|
+
#
|
|
309
|
+
# @option options [Boolean, nil] :worktree (nil) write to the worktree config
|
|
310
|
+
#
|
|
311
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
312
|
+
#
|
|
313
|
+
# @option options [String, nil] :blob (nil) write to a git blob object
|
|
314
|
+
#
|
|
315
|
+
# @option options [String, nil] :type (nil) coerce the value to the given type (e.g. `"bool"`, `"int"`)
|
|
316
|
+
#
|
|
317
|
+
# @return [nil]
|
|
318
|
+
#
|
|
319
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
320
|
+
#
|
|
321
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
322
|
+
#
|
|
323
|
+
def config_add(name, value, **)
|
|
324
|
+
Private.assert_valid_opts!(CONFIG_ADD_ALLOWED_OPTS, **)
|
|
325
|
+
assert_valid_scope!(**)
|
|
326
|
+
cmd = Git::Commands::ConfigOptionSyntax::Add.new(execution_context)
|
|
327
|
+
cmd.call(name, value, **)
|
|
328
|
+
nil
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# @api private
|
|
332
|
+
CONFIG_REMOVE_SECTION_ALLOWED_OPTS = %i[global system local worktree file f blob].freeze
|
|
333
|
+
private_constant :CONFIG_REMOVE_SECTION_ALLOWED_OPTS
|
|
334
|
+
|
|
335
|
+
# @overload config_remove_section(name, **options)
|
|
336
|
+
#
|
|
337
|
+
# Remove an entire config section
|
|
338
|
+
#
|
|
339
|
+
# Wraps `git config --remove-section`.
|
|
340
|
+
#
|
|
341
|
+
# @example Remove the origin remote section
|
|
342
|
+
# repo.config_remove_section('remote.origin')
|
|
343
|
+
#
|
|
344
|
+
# @param name [String] the section name to remove (e.g. `"remote.origin"`)
|
|
345
|
+
#
|
|
346
|
+
# @param options [Hash] scope options
|
|
347
|
+
#
|
|
348
|
+
# @option options [Boolean, nil] :global (nil) remove from `~/.gitconfig`
|
|
349
|
+
#
|
|
350
|
+
# @option options [Boolean, nil] :system (nil) remove from the system config file
|
|
351
|
+
#
|
|
352
|
+
# @option options [Boolean, nil] :local (nil) remove from `.git/config`
|
|
353
|
+
#
|
|
354
|
+
# @option options [Boolean, nil] :worktree (nil) remove from the worktree config
|
|
355
|
+
#
|
|
356
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
357
|
+
#
|
|
358
|
+
# @option options [String, nil] :blob (nil) remove from a git blob object
|
|
359
|
+
#
|
|
360
|
+
# @return [nil]
|
|
361
|
+
#
|
|
362
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
363
|
+
#
|
|
364
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
365
|
+
#
|
|
366
|
+
def config_remove_section(name, **)
|
|
367
|
+
Private.assert_valid_opts!(CONFIG_REMOVE_SECTION_ALLOWED_OPTS, **)
|
|
368
|
+
assert_valid_scope!(**)
|
|
369
|
+
cmd = Git::Commands::ConfigOptionSyntax::RemoveSection.new(execution_context)
|
|
370
|
+
cmd.call(name, **)
|
|
371
|
+
nil
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# @api private
|
|
375
|
+
CONFIG_RENAME_SECTION_ALLOWED_OPTS = %i[global system local worktree file f blob].freeze
|
|
376
|
+
private_constant :CONFIG_RENAME_SECTION_ALLOWED_OPTS
|
|
377
|
+
|
|
378
|
+
# @overload config_rename_section(old_name, new_name, **options)
|
|
379
|
+
#
|
|
380
|
+
# Rename a config section
|
|
381
|
+
#
|
|
382
|
+
# Wraps `git config --rename-section`.
|
|
383
|
+
#
|
|
384
|
+
# @example Rename a remote section
|
|
385
|
+
# repo.config_rename_section('remote.old', 'remote.new')
|
|
386
|
+
#
|
|
387
|
+
# @param old_name [String] the current section name
|
|
388
|
+
#
|
|
389
|
+
# @param new_name [String] the new section name
|
|
390
|
+
#
|
|
391
|
+
# @param options [Hash] scope options
|
|
392
|
+
#
|
|
393
|
+
# @option options [Boolean, nil] :global (nil) rename in `~/.gitconfig`
|
|
394
|
+
#
|
|
395
|
+
# @option options [Boolean, nil] :system (nil) rename in the system config file
|
|
396
|
+
#
|
|
397
|
+
# @option options [Boolean, nil] :local (nil) rename in `.git/config`
|
|
398
|
+
#
|
|
399
|
+
# @option options [Boolean, nil] :worktree (nil) rename in the worktree config
|
|
400
|
+
#
|
|
401
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
402
|
+
#
|
|
403
|
+
# @option options [String, nil] :blob (nil) rename in a git blob object
|
|
404
|
+
#
|
|
405
|
+
# @return [nil]
|
|
406
|
+
#
|
|
407
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
408
|
+
#
|
|
409
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
410
|
+
#
|
|
411
|
+
def config_rename_section(old_name, new_name, **)
|
|
412
|
+
Private.assert_valid_opts!(CONFIG_RENAME_SECTION_ALLOWED_OPTS, **)
|
|
413
|
+
assert_valid_scope!(**)
|
|
414
|
+
cmd = Git::Commands::ConfigOptionSyntax::RenameSection.new(execution_context)
|
|
415
|
+
cmd.call(old_name, new_name, **)
|
|
416
|
+
nil
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# @api private
|
|
420
|
+
CONFIG_REPLACE_ALL_ALLOWED_OPTS = %i[global system local worktree file f blob type].freeze
|
|
421
|
+
private_constant :CONFIG_REPLACE_ALL_ALLOWED_OPTS
|
|
422
|
+
|
|
423
|
+
# @overload config_replace_all(name, value, value_regex = nil, **options)
|
|
424
|
+
#
|
|
425
|
+
# Replace all values matching a key (and optional value regex)
|
|
426
|
+
#
|
|
427
|
+
# Wraps `git config --replace-all`.
|
|
428
|
+
#
|
|
429
|
+
# @example Replace all values for a key
|
|
430
|
+
# repo.config_replace_all('remote.origin.url', 'https://github.com/user/repo')
|
|
431
|
+
#
|
|
432
|
+
# @param name [String] the full dotted config key
|
|
433
|
+
#
|
|
434
|
+
# @param value [String] the new value
|
|
435
|
+
#
|
|
436
|
+
# @param value_regex [String, nil] optional regex; only matching values are replaced
|
|
437
|
+
#
|
|
438
|
+
# @param options [Hash] scope options
|
|
439
|
+
#
|
|
440
|
+
# @option options [Boolean, nil] :global (nil) write to `~/.gitconfig`
|
|
441
|
+
#
|
|
442
|
+
# @option options [Boolean, nil] :system (nil) write to the system config file
|
|
443
|
+
#
|
|
444
|
+
# @option options [Boolean, nil] :local (nil) write to `.git/config`
|
|
445
|
+
#
|
|
446
|
+
# @option options [Boolean, nil] :worktree (nil) write to the worktree config
|
|
447
|
+
#
|
|
448
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
449
|
+
#
|
|
450
|
+
# @option options [String, nil] :blob (nil) write to a git blob object
|
|
451
|
+
#
|
|
452
|
+
# @option options [String, nil] :type (nil) coerce the value to the given type (e.g. `"bool"`, `"int"`)
|
|
453
|
+
#
|
|
454
|
+
# @return [nil]
|
|
455
|
+
#
|
|
456
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
457
|
+
#
|
|
458
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
459
|
+
#
|
|
460
|
+
def config_replace_all(name, value, value_regex = nil, **)
|
|
461
|
+
Private.assert_valid_opts!(CONFIG_REPLACE_ALL_ALLOWED_OPTS, **)
|
|
462
|
+
assert_valid_scope!(**)
|
|
463
|
+
cmd = Git::Commands::ConfigOptionSyntax::ReplaceAll.new(execution_context)
|
|
464
|
+
cmd.call(name, value, value_regex, **)
|
|
465
|
+
nil
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# @api private
|
|
469
|
+
CONFIG_SET_ALLOWED_OPTS = %i[global system local worktree file f blob type].freeze
|
|
470
|
+
private_constant :CONFIG_SET_ALLOWED_OPTS
|
|
471
|
+
|
|
472
|
+
# @overload config_set(name, value, **options)
|
|
473
|
+
#
|
|
474
|
+
# Set a config entry to a new value
|
|
475
|
+
#
|
|
476
|
+
# Wraps the implicit set mode of `git config`.
|
|
477
|
+
#
|
|
478
|
+
# @example Set the user name in local config
|
|
479
|
+
# repo.config_set('user.name', 'Alice')
|
|
480
|
+
#
|
|
481
|
+
# @param name [String] the full dotted config key
|
|
482
|
+
#
|
|
483
|
+
# @param value [String] the value to set
|
|
484
|
+
#
|
|
485
|
+
# @param options [Hash] scope options
|
|
486
|
+
#
|
|
487
|
+
# @option options [Boolean, nil] :global (nil) write to `~/.gitconfig`
|
|
488
|
+
#
|
|
489
|
+
# @option options [Boolean, nil] :system (nil) write to the system config file
|
|
490
|
+
#
|
|
491
|
+
# @option options [Boolean, nil] :local (nil) write to `.git/config`
|
|
492
|
+
#
|
|
493
|
+
# @option options [Boolean, nil] :worktree (nil) write to the worktree config
|
|
494
|
+
#
|
|
495
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
496
|
+
#
|
|
497
|
+
# @option options [String, nil] :blob (nil) write to a git blob object
|
|
498
|
+
#
|
|
499
|
+
# @option options [String, nil] :type (nil) coerce the value to the given type (e.g. `"bool"`, `"int"`)
|
|
500
|
+
#
|
|
501
|
+
# @return [nil]
|
|
502
|
+
#
|
|
503
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
504
|
+
#
|
|
505
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
506
|
+
#
|
|
507
|
+
def config_set(name, value, **)
|
|
508
|
+
Private.assert_valid_opts!(CONFIG_SET_ALLOWED_OPTS, **)
|
|
509
|
+
assert_valid_scope!(**)
|
|
510
|
+
cmd = Git::Commands::ConfigOptionSyntax::Set.new(execution_context)
|
|
511
|
+
cmd.call(name, value, **)
|
|
512
|
+
nil
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# @api private
|
|
516
|
+
CONFIG_UNSET_ALLOWED_OPTS = %i[global system local worktree file f blob].freeze
|
|
517
|
+
private_constant :CONFIG_UNSET_ALLOWED_OPTS
|
|
518
|
+
|
|
519
|
+
# @overload config_unset(name, value_regex = nil, **options)
|
|
520
|
+
#
|
|
521
|
+
# Remove a config entry
|
|
522
|
+
#
|
|
523
|
+
# Wraps `git config --unset`.
|
|
524
|
+
#
|
|
525
|
+
# @example Remove a config entry
|
|
526
|
+
# repo.config_unset('user.name')
|
|
527
|
+
#
|
|
528
|
+
# @param name [String] the full dotted config key
|
|
529
|
+
#
|
|
530
|
+
# @param value_regex [String, nil] optional regex; only the matching value is removed
|
|
531
|
+
#
|
|
532
|
+
# @param options [Hash] scope options
|
|
533
|
+
#
|
|
534
|
+
# @option options [Boolean, nil] :global (nil) remove from `~/.gitconfig`
|
|
535
|
+
#
|
|
536
|
+
# @option options [Boolean, nil] :system (nil) remove from the system config file
|
|
537
|
+
#
|
|
538
|
+
# @option options [Boolean, nil] :local (nil) remove from `.git/config`
|
|
539
|
+
#
|
|
540
|
+
# @option options [Boolean, nil] :worktree (nil) remove from the worktree config
|
|
541
|
+
#
|
|
542
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
543
|
+
#
|
|
544
|
+
# @option options [String, nil] :blob (nil) remove from a git blob object
|
|
545
|
+
#
|
|
546
|
+
# @return [nil]
|
|
547
|
+
#
|
|
548
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
549
|
+
#
|
|
550
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
551
|
+
#
|
|
552
|
+
def config_unset(name, value_regex = nil, **)
|
|
553
|
+
Private.assert_valid_opts!(CONFIG_UNSET_ALLOWED_OPTS, **)
|
|
554
|
+
assert_valid_scope!(**)
|
|
555
|
+
cmd = Git::Commands::ConfigOptionSyntax::Unset.new(execution_context)
|
|
556
|
+
cmd.call(name, value_regex, **)
|
|
557
|
+
nil
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# @api private
|
|
561
|
+
CONFIG_UNSET_ALL_ALLOWED_OPTS = %i[global system local worktree file f blob].freeze
|
|
562
|
+
private_constant :CONFIG_UNSET_ALL_ALLOWED_OPTS
|
|
563
|
+
|
|
564
|
+
# @overload config_unset_all(name, value_regex = nil, **options)
|
|
565
|
+
#
|
|
566
|
+
# Remove all config entries for a key
|
|
567
|
+
#
|
|
568
|
+
# Wraps `git config --unset-all`.
|
|
569
|
+
#
|
|
570
|
+
# @example Remove all values for a multi-valued key
|
|
571
|
+
# repo.config_unset_all('remote.origin.url')
|
|
572
|
+
#
|
|
573
|
+
# @param name [String] the full dotted config key
|
|
574
|
+
#
|
|
575
|
+
# @param value_regex [String, nil] optional regex; only matching values are removed
|
|
576
|
+
#
|
|
577
|
+
# @param options [Hash] scope options
|
|
578
|
+
#
|
|
579
|
+
# @option options [Boolean, nil] :global (nil) remove from `~/.gitconfig`
|
|
580
|
+
#
|
|
581
|
+
# @option options [Boolean, nil] :system (nil) remove from the system config file
|
|
582
|
+
#
|
|
583
|
+
# @option options [Boolean, nil] :local (nil) remove from `.git/config`
|
|
584
|
+
#
|
|
585
|
+
# @option options [Boolean, nil] :worktree (nil) remove from the worktree config
|
|
586
|
+
#
|
|
587
|
+
# @option options [String, nil] :file (nil) path to a custom config file (alias: `:f`)
|
|
588
|
+
#
|
|
589
|
+
# @option options [String, nil] :blob (nil) remove from a git blob object
|
|
590
|
+
#
|
|
591
|
+
# @return [nil]
|
|
592
|
+
#
|
|
593
|
+
# @raise [ArgumentError] if unsupported options are provided
|
|
594
|
+
#
|
|
595
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
596
|
+
#
|
|
597
|
+
def config_unset_all(name, value_regex = nil, **)
|
|
598
|
+
Private.assert_valid_opts!(CONFIG_UNSET_ALL_ALLOWED_OPTS, **)
|
|
599
|
+
assert_valid_scope!(**)
|
|
600
|
+
cmd = Git::Commands::ConfigOptionSyntax::UnsetAll.new(execution_context)
|
|
601
|
+
cmd.call(name, value_regex, **)
|
|
602
|
+
nil
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
# @!endgroup
|
|
606
|
+
|
|
607
|
+
private
|
|
608
|
+
|
|
609
|
+
# @abstract
|
|
610
|
+
#
|
|
611
|
+
# Returns the execution context used to run git commands
|
|
612
|
+
#
|
|
613
|
+
# @return [Git::ExecutionContext]
|
|
614
|
+
#
|
|
615
|
+
def execution_context
|
|
616
|
+
raise NotImplementedError
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# @abstract
|
|
620
|
+
#
|
|
621
|
+
# @overload assert_valid_scope!(**options)
|
|
622
|
+
#
|
|
623
|
+
# Validates that the requested scope options are appropriate for this context
|
|
624
|
+
#
|
|
625
|
+
# Called before every config operation. Raise `ArgumentError` when a scope
|
|
626
|
+
# (e.g. `:local`) is not permitted without a repository.
|
|
627
|
+
#
|
|
628
|
+
# @param options [Hash] scope options forwarded from the calling config method
|
|
629
|
+
#
|
|
630
|
+
# @raise [ArgumentError] if the scope is not permitted in this context
|
|
631
|
+
#
|
|
632
|
+
# @return [void]
|
|
633
|
+
#
|
|
634
|
+
def assert_valid_scope!(**)
|
|
635
|
+
raise NotImplementedError
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# Internal helpers for {Git::Configuring}.
|
|
639
|
+
#
|
|
640
|
+
# @api private
|
|
641
|
+
#
|
|
642
|
+
module Private
|
|
643
|
+
module_function
|
|
644
|
+
|
|
645
|
+
# Validate that `options` contains only keys listed in `allowed`
|
|
646
|
+
#
|
|
647
|
+
# @param allowed [Array<Symbol>] the permitted option keys
|
|
648
|
+
#
|
|
649
|
+
# @param options [Hash] the options hash provided by the caller
|
|
650
|
+
#
|
|
651
|
+
# @return [void]
|
|
652
|
+
#
|
|
653
|
+
# @raise [ArgumentError] when `options` contains any key not in `allowed`
|
|
654
|
+
#
|
|
655
|
+
def assert_valid_opts!(allowed, **options)
|
|
656
|
+
unknown = options.keys - allowed
|
|
657
|
+
return if unknown.empty?
|
|
658
|
+
|
|
659
|
+
raise ArgumentError, "Unknown options: #{unknown.join(', ')}"
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
private_constant :Private
|
|
664
|
+
end
|
|
665
|
+
end
|