0
# Configuration Management
1
2
Comprehensive Git configuration file parsing and manipulation supporting repository, user, and system-level configuration with hierarchical stacking, type conversion, multi-value support, URL rewriting, and advanced pattern matching for includeIf directives.
3
4
## Capabilities
5
6
### Configuration Classes
7
8
Classes for reading and writing Git configuration files with hierarchical support.
9
10
```python { .api }
11
class Config:
12
"""Abstract base class for Git configuration."""
13
14
def get(self, section: SectionLike, name: NameLike) -> Value:
15
"""
16
Get configuration value.
17
18
Args:
19
section: Section name or tuple with section and optional subsection
20
name: Configuration key name
21
22
Returns:
23
Configuration value as bytes
24
25
Raises:
26
KeyError: If the value is not set
27
"""
28
29
def get_multivar(self, section: SectionLike, name: NameLike) -> Iterator[Value]:
30
"""
31
Get multiple values for a configuration key.
32
33
Args:
34
section: Section name or tuple with section and optional subsection
35
name: Configuration key name
36
37
Returns:
38
Iterator over configuration values
39
40
Raises:
41
KeyError: If the value is not set
42
"""
43
44
def get_boolean(
45
self,
46
section: SectionLike,
47
name: NameLike,
48
default: Optional[bool] = None
49
) -> Optional[bool]:
50
"""
51
Get configuration value as boolean.
52
53
Args:
54
section: Section name or tuple with section and optional subsection
55
name: Configuration key name
56
default: Default value if not found
57
58
Returns:
59
Boolean value or default
60
61
Raises:
62
ValueError: If value is not a valid boolean
63
"""
64
65
def set(
66
self,
67
section: SectionLike,
68
name: NameLike,
69
value: Union[ValueLike, bool]
70
) -> None:
71
"""
72
Set configuration value.
73
74
Args:
75
section: Section name or tuple with section and optional subsection
76
name: Configuration key name
77
value: Value to set
78
"""
79
80
def items(self, section: SectionLike) -> Iterator[Tuple[Name, Value]]:
81
"""
82
Iterate over items in a configuration section.
83
84
Args:
85
section: Section name or tuple with section and optional subsection
86
87
Yields:
88
Tuples of (name, value) pairs
89
"""
90
91
def sections(self) -> Iterator[Section]:
92
"""
93
Iterate over configuration sections.
94
95
Returns:
96
Iterator over section tuples
97
"""
98
99
def has_section(self, name: Section) -> bool:
100
"""
101
Check if a section exists.
102
103
Args:
104
name: Section name to check
105
106
Returns:
107
True if section exists
108
"""
109
110
class ConfigDict(Config):
111
"""Git configuration stored in a dictionary.
112
113
Provides in-memory configuration storage with case-insensitive
114
section names and support for multi-valued configuration keys.
115
"""
116
117
def __init__(
118
self,
119
values: Optional[MutableMapping[Section, MutableMapping[Name, Value]]] = None,
120
encoding: Optional[str] = None
121
):
122
"""
123
Initialize dictionary-based configuration.
124
125
Args:
126
values: Initial configuration values
127
encoding: Text encoding (defaults to system default)
128
"""
129
130
def __getitem__(self, key: Section) -> CaseInsensitiveOrderedMultiDict[Name, Value]:
131
"""Get section by name."""
132
133
def __setitem__(self, key: Section, value: MutableMapping[Name, Value]) -> None:
134
"""Set section by name."""
135
136
def __delitem__(self, key: Section) -> None:
137
"""Delete section by name."""
138
139
def __iter__(self) -> Iterator[Section]:
140
"""Iterate over section names."""
141
142
def __len__(self) -> int:
143
"""Number of sections."""
144
145
def keys(self) -> KeysView[Section]:
146
"""Get section names."""
147
148
class ConfigFile(ConfigDict):
149
"""File-based configuration implementation.
150
151
Reads and writes Git configuration files with proper parsing
152
of sections, subsections, and multi-line values.
153
"""
154
155
def __init__(
156
self,
157
filename: Optional[str] = None,
158
file: Optional[BinaryIO] = None,
159
encoding: Optional[str] = None
160
):
161
"""
162
Initialize file-based configuration.
163
164
Args:
165
filename: Path to configuration file
166
file: File-like object to read from
167
encoding: Text encoding (defaults to UTF-8)
168
"""
169
170
@classmethod
171
def from_path(cls, path: str) -> "ConfigFile":
172
"""
173
Create ConfigFile from file path.
174
175
Args:
176
path: Path to configuration file
177
178
Returns:
179
ConfigFile instance
180
"""
181
182
@classmethod
183
def from_file(cls, f: BinaryIO) -> "ConfigFile":
184
"""
185
Create ConfigFile from file object.
186
187
Args:
188
f: File-like object to read from
189
190
Returns:
191
ConfigFile instance
192
"""
193
194
def write_to_path(self, path: str) -> None:
195
"""
196
Write configuration to file path.
197
198
Args:
199
path: Output file path
200
"""
201
202
def write_to_file(self, f: BinaryIO) -> None:
203
"""
204
Write configuration to file-like object.
205
206
Args:
207
f: File-like object to write to
208
"""
209
210
def write(self) -> None:
211
"""
212
Write configuration back to original file.
213
"""
214
215
class StackedConfig(Config):
216
"""Configuration which reads from multiple config files.
217
218
Provides layered configuration where values are looked up
219
in order from multiple configuration sources (local, global, system).
220
"""
221
222
def __init__(
223
self,
224
backends: List[ConfigFile],
225
writable: Optional[ConfigFile] = None
226
):
227
"""
228
Initialize stacked configuration.
229
230
Args:
231
backends: List of configuration files (searched in order)
232
writable: Configuration file for write operations
233
"""
234
235
@classmethod
236
def default(cls) -> "StackedConfig":
237
"""
238
Create default stacked configuration.
239
240
Returns:
241
StackedConfig with system, global, and user configurations
242
"""
243
244
@classmethod
245
def default_backends(cls) -> List[ConfigFile]:
246
"""
247
Get default configuration backends.
248
249
Searches for configuration files in Git's standard locations:
250
- User config: ~/.gitconfig or $XDG_CONFIG_HOME/git/config
251
- System config: /etc/gitconfig (Unix) or system paths (Windows)
252
253
Respects GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM, and GIT_CONFIG_NOSYSTEM
254
environment variables.
255
256
Returns:
257
List of ConfigFile objects for found configuration files
258
"""
259
```
260
261
### Utility Classes
262
263
Helper classes for configuration file handling.
264
265
```python { .api }
266
class CaseInsensitiveOrderedMultiDict:
267
"""Case-insensitive dictionary supporting multiple values per key."""
268
269
def __init__(self): ...
270
271
def __getitem__(self, key: str) -> Any: ...
272
def __setitem__(self, key: str, value: Any) -> None: ...
273
def __contains__(self, key: str) -> bool: ...
274
275
def get(self, key: str, default=None) -> Any:
276
"""Get value with default."""
277
278
def getlist(self, key: str) -> List[Any]:
279
"""Get all values for key as list."""
280
281
def items(self) -> Iterator[Tuple[str, Any]]:
282
"""Iterate over key-value pairs."""
283
```
284
285
### Submodule Configuration
286
287
Functions for reading and parsing Git submodule configuration.
288
289
```python { .api }
290
def read_submodules(config_file) -> Iterator[Tuple[bytes, bytes, bytes]]:
291
"""
292
Read submodule configuration from .gitmodules file.
293
294
Args:
295
config_file: Configuration file object
296
297
Yields:
298
Tuples of (path, name, url)
299
"""
300
301
def parse_submodules(config: Config) -> Dict[bytes, Dict[bytes, bytes]]:
302
"""
303
Parse submodule configuration into structured format.
304
305
Args:
306
config: Configuration object
307
308
Returns:
309
Dictionary mapping submodule names to their configuration
310
"""
311
```
312
313
### URL Rewriting
314
315
Functions for handling Git URL rewriting configuration (insteadOf).
316
317
```python { .api }
318
def iter_instead_of(config: Config, push: bool = False) -> Iterator[Tuple[bytes, bytes]]:
319
"""
320
Iterate over URL rewriting rules.
321
322
Args:
323
config: Configuration object
324
push: Whether to get pushInsteadOf rules
325
326
Yields:
327
Tuples of (original_prefix, replacement_prefix)
328
"""
329
330
def apply_instead_of(config: Config, url: bytes, push: bool = False) -> bytes:
331
"""
332
Apply URL rewriting rules to a URL.
333
334
Args:
335
config: Configuration object
336
url: Original URL
337
push: Whether to apply pushInsteadOf rules
338
339
Returns:
340
Rewritten URL
341
"""
342
```
343
344
### Pattern Matching
345
346
Functions for Git configuration pattern matching.
347
348
```python { .api }
349
def match_glob_pattern(pattern: str, path: str) -> bool:
350
"""
351
Match path against Git glob pattern.
352
353
Args:
354
pattern: Glob pattern (supports *, ?, [])
355
path: Path to match
356
357
Returns:
358
True if path matches pattern
359
"""
360
```
361
362
## Usage Examples
363
364
### Basic Configuration Operations
365
366
```python
367
from dulwich.config import ConfigFile
368
369
# Read repository configuration
370
config = ConfigFile.from_path('.git/config')
371
372
# Get configuration values
373
user_name = config.get(('user',), 'name')
374
user_email = config.get(('user',), 'email')
375
print(f"User: {user_name.decode()} <{user_email.decode()}>")
376
377
# Set configuration values
378
config.set(('user',), 'name', 'John Doe')
379
config.set(('user',), 'email', 'john@example.com')
380
381
# Work with sections
382
for section in config.sections():
383
print(f"Section: {section}")
384
for name, value in config.items(section):
385
print(f" {name.decode()}: {value.decode()}")
386
387
# Write changes back to file
388
config.write() # Writes to original file
389
# Or write to different path
390
config.write_to_path('/tmp/config-backup')
391
```
392
393
### Stacked Configuration
394
395
```python
396
from dulwich.config import ConfigFile, StackedConfig
397
398
# Create stacked configuration (system -> global -> local)
399
system_config = ConfigFile('/etc/gitconfig')
400
global_config = ConfigFile('~/.gitconfig')
401
local_config = ConfigFile('.git/config')
402
403
stacked = StackedConfig([system_config, global_config, local_config],
404
writable=local_config)
405
406
# Get value (searches from local to system)
407
core_editor = stacked.get(b'core', b'editor')
408
409
# Set value (writes to writable backend)
410
stacked.set(b'user', b'name', b'Jane Doe'.encode())
411
```
412
413
### Submodule Configuration
414
415
```python
416
from dulwich.config import ConfigFile, parse_submodules
417
418
# Read .gitmodules file
419
gitmodules = ConfigFile('.gitmodules')
420
421
# Parse submodule configuration
422
submodules = parse_submodules(gitmodules)
423
424
for submodule_name, submodule_config in submodules.items():
425
path = submodule_config[b'path']
426
url = submodule_config[b'url']
427
print(f"Submodule {submodule_name.decode()}: {path.decode()} -> {url.decode()}")
428
```
429
430
### URL Rewriting
431
432
```python
433
from dulwich.config import ConfigFile, apply_instead_of
434
435
# Configure URL rewriting
436
config = ConfigFile('.git/config')
437
config.set(b'url', b'https://github.com/', b'git@github.com:')
438
config.set(b'url "https://github.com/"', b'insteadOf', b'gh:')
439
440
# Apply rewriting
441
original_url = b'gh:user/repo.git'
442
rewritten_url = apply_instead_of(config, original_url)
443
print(f"Rewritten: {original_url.decode()} -> {rewritten_url.decode()}")
444
```
445
446
### Multi-value Configuration
447
448
```python
449
from dulwich.config import ConfigFile
450
451
config = ConfigFile('.git/config')
452
453
# Set multiple values for same key
454
config.set(b'remote "origin"', b'fetch', b'+refs/heads/*:refs/remotes/origin/*')
455
config.set(b'remote "origin"', b'fetch', b'+refs/pull/*/head:refs/remotes/origin/pr/*')
456
457
# Get all values
458
fetch_specs = config.get_multivar(b'remote "origin"', b'fetch')
459
for spec in fetch_specs:
460
print(f"Fetch spec: {spec.decode()}")
461
```