Skip to content

Add Subsections and Subsection for Git-style section names - #436

Merged
unknwon merged 5 commits into
mainfrom
git-style-subsections
Nov 11, 2026
Merged

unknwon merged 5 commits into
mainfrom
git-style-subsections

Conversation

@unknwon

@unknwon unknwon commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

Describe the pull request

Adds File.Subsections(name) and File.Subsection(name, sub) for Git config-style section names such as [forge "github.com"], so callers like git-lfs-server no longer cut prefixes and quotes off Section.Name() by hand.

for host, sec := range f.Subsections("forge") { ... }
f.Subsection("storage", "r2").Key("TYPE").SetValue("s3-presign") // adds [storage "r2"]

Both return the *Section of each header, so MapTo, %(name)s references and shadows work as usual. Section headers are read as Git reads them:

  • [name "sub"] and the older [name.sub] both count, with a dotted sub lowercased. The name matches in any case. A dot in the name moves the rest into the sub, so [forge.a "b"] has sub a.b. Spaces and tabs are allowed between the parts but not around them. In a quoted sub, \" and \\ read as " and \, and a backslash before another character is dropped.
  • Headers that don't split this way, such as [ forge "x"] or [forge "x" ], are skipped without an error.
  • Subsections reads the sections each time it is ranged over.
  • Subsection returns the section written as [name "sub"], or else the first match. If there is none, it returns a section that reads as empty, like Section does, and a change adds it with " and \ in the sub escaped, lowercased under the case-insensitive options.

Section names are parsed when they are read, not by the lexer, so parsing and stored section names are unchanged. That leaves three differences from Git, all documented:

  • The name may have any character but a space, a tab or ", so [for_ge "x"] is read where Git rejects it.
  • Headers spelled differently for the same sub, such as [forge "x"], [Forge "x"] and [forge.x], are separate sections, and Subsections yields the sub once for each, so callers can detect them. Headers spelled the same are one section, as they are for Section.
  • With CaseInsensitive or CaseInsensitiveSections, the loader lowercases whole section names, so [forge "X"] and [forge "x"] are one section with sub x, where Git keeps them separate.

Link to the issue: n/a

Checklist

  • I agree to follow the Code of Conduct by submitting this pull request.
  • I have read and acknowledge the Contributing guide.
  • I have added test cases to cover the new code.

AI usage

Written with Amp (Claude), reviewed by the author.

Read [name "sub"] headers, such as [forge "github.com"], without
parsing section names by hand. Names are parsed when read, so the lexer
and stored section names are unchanged.
Subsections captured the section list when called, so sections added
afterwards were missed. The docstrings now also say that only spacing
between the parts matches Git, that name case merges sections under the
case-insensitive options, and that Subsection writes a lowercased header
with those options.
Subsections and Subsection now follow Git's header rules at read time:
both [name "sub"] and [name.sub] forms, Git's name characters, no
spaces around the parts, and headers Git takes as the same subsection
merged into one read-only Subsection, with keys read from the last
section that has them. CaseInsensitive lowercasing the sub is documented
as a difference from Git.
A merged read-only Subsection could not keep Git's last value when the
loader had already merged same-spelled headers, and lost MapTo, %(name)s
references and shadows. Subsections and Subsection now return the
*Section of each header, keeping Git's header rules, and document that
headers spelled differently for the same sub are not merged. An empty
name, as in [ "x"], is read as Git reads it.
Drop Git's name character check so names such as for_ge are read, and
document it as a difference from Git. The Subsection docstring now says
an added header is lowercased with the case-insensitive options.
@unknwon
unknwon merged commit 090c562 into main Nov 11, 2026
10 checks passed
@unknwon
unknwon deleted the git-style-subsections branch November 11, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant