Repository navigation
Commit 5a86a1d
committed
fix(config): read an option on the same line as its section header
`GitConfigParser._read` recognized a section header with the inherited
`configparser` pattern `\[(?P<header>.+)\]`, matched against the
stripped line, and discarded everything after the match. git ends a
header at its first `]` outside a quoted subsection name and parses the
rest of the line as an ordinary config line, so `[core] bare = true`
sets `core.bare` in git and nothing in GitPython.
`.gitmodules` is read with this parser and is controlled by whoever
authored the superproject. For
[submodule "lib"]
path = lib
url = https://good.example/lib
[submodule "lib"] url = https://evil.example/lib
`git config -f .gitmodules --list` shows both URLs, and
`git submodule init` registers and later clones
`https://evil.example/lib`, while `Repo.submodules` reports
`https://good.example/lib`. A tool that uses GitPython to check which
URLs a repository's submodules point at approves a different URL than
the one git fetches. The greedy match also misread other lines:
`[c] k = v ]` became a section named `c] k = v` with no options, and
`[d] k = "multi\` continued on the next line produced an option named
`line"` instead of `d.k = multi line`.
The header now ends at the first unquoted `]`, with backslash escapes
honored inside the quoted subsection name, and the text after it is fed
back through the parse loop as a line of its own. That reuses the
existing comment, option, continuation and header handling, so
`[e] ; comment` adds nothing, `[b]flag` is an implicit boolean, and
`[f] [g] k = v` sets `g.k`, all as git reads them. A header with
unbalanced quotes keeps the previous reading up to the last `]`, and
files whose headers stand alone on their lines parse exactly as before.
`test_option_after_section_header_is_read_like_git` in
`test/test_config.py` checks each case above against what
`git config -f <file> --list` prints on git 2.54.0. It fails before this
change and passes after. `ruff check`, `ruff format --check` and `mypy`
pass. In a full clone prepared with `init-tests-after-clone.sh`, the
pytest suite passes except `test_diff_with_staged_file`,
`test_empty_repo` and `test_rebasing`, which fail the same way without
this change.1 parent ccc4811 commit 5a86a1d
2 files changed
Lines changed: 69 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
578 | 578 | | |
579 | 579 | | |
580 | 580 | | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
581 | 603 | | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
588 | | - | |
589 | | - | |
590 | | - | |
591 | | - | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
592 | 617 | | |
593 | 618 | | |
594 | 619 | | |
| |||
599 | 624 | | |
600 | 625 | | |
601 | 626 | | |
602 | | - | |
| 627 | + | |
| 628 | + | |
603 | 629 | | |
604 | 630 | | |
605 | 631 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
462 | 462 | | |
463 | 463 | | |
464 | 464 | | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
465 | 497 | | |
466 | 498 | | |
467 | 499 | | |
| |||
0 commit comments