Commit a44f8d9
feat: rewrite config parser to be consistent with Git
Previously it was based on an ini-parser, which depends on the
Python version and also isn't actually dealing with the Git's
specific grammar and rules.
Now it's much more consistent, albeit probably also slower.
--- agent
Replace the line-oriented INI parsing logic in GitConfigParser with a
character-stream parser modeled on Git's config.c implementation.
The inherited configparser section matcher treats everything between the
first opening bracket and the last closing bracket as one section name.
Consequently, GitPython interpreted a header such as:
[user] [other]
as one section named "user] [other", while Git interpreted it as two
successive section headers and assigned following values to "other".
Writing opaque section names through the INI serializer could therefore
change the configuration's meaning when Git subsequently read it.
Implement Git's configuration grammar directly, following the behavior of
git_parse_source(), get_base_var(), get_value(), and parse_value(). The new
parser handles:
- basic and quoted-subsection section headers
- multiple section headers in the same character stream
- comments introduced by '#' or ';'
- quoted and unquoted values
- supported backslash escapes
- backslash-newline continuations
- leading and trailing whitespace rules
- CRLF input and UTF-8 byte-order marks
- entries without values, represented semantically as boolean true
- duplicate options while preserving their order
Reject syntax that Git itself rejects, including colon delimiters,
underscore-containing option names, malformed section headers, unknown
value escapes, and unterminated quoted values.
Replace the raw value writer with a canonical Git-config serializer.
Values are always quoted, with backslashes, quotes, newlines, tabs, and
backspaces escaped. Quoted subsection names are parsed and re-escaped
canonically before being written. Comments and original whitespace remain
intentionally unpreserved when a dirty configuration is flushed.
Validate section names by parsing them as complete Git section headers.
This ensures each supplied name identifies exactly one section and
prevents unquoted closing brackets from injecting another section.
Validate option names against Git's ASCII letter, digit, and hyphen
grammar as well.
Update fixtures that previously depended on INI syntax rejected by Git,
and adjust expectations for decoded value escapes and valueless boolean
entries.
Add coverage for:
- the differing interpretation of adjacent section headers
- BOM, CRLF, comments, continuations, and valueless entries
- malformed syntax rejected by Git
- canonical value serialization and reparsing
- real `git config` interoperability
- closing brackets inside quoted subsection names
- quotes and backslashes inside subsection names
- invalid section and option names
- duplicate-value behavior with Git-compatible option names
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>1 parent 6a5eb6a commit a44f8d9
9 files changed
Lines changed: 846 additions & 388 deletions
File tree
- git
- objects/submodule
- test
- fixtures
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
19 | | - | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
172 | 173 | | |
173 | 174 | | |
174 | 175 | | |
175 | | - | |
| 176 | + | |
176 | 177 | | |
177 | 178 | | |
178 | 179 | | |
| |||
1503 | 1504 | | |
1504 | 1505 | | |
1505 | 1506 | | |
1506 | | - | |
| 1507 | + | |
1507 | 1508 | | |
1508 | 1509 | | |
1509 | 1510 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
113 | | - | |
| 113 | + | |
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | | - | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
577 | 578 | | |
578 | 579 | | |
579 | 580 | | |
580 | | - | |
| 581 | + | |
581 | 582 | | |
582 | 583 | | |
583 | 584 | | |
| |||
619 | 620 | | |
620 | 621 | | |
621 | 622 | | |
622 | | - | |
| 623 | + | |
623 | 624 | | |
624 | 625 | | |
625 | | - | |
| 626 | + | |
626 | 627 | | |
627 | 628 | | |
628 | 629 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | | - | |
| 25 | + | |
27 | 26 | | |
28 | 27 | | |
29 | 28 | | |
| |||
43 | 42 | | |
44 | 43 | | |
45 | 44 | | |
46 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
8 | 6 | | |
9 | 7 | | |
0 commit comments