Skip to content

Fix case-insensitive Git config name matching - #2241

Merged
Byron merged 1 commit into
mainfrom
case-insensitive-gitconfig
Sep 14, 2026
Merged

Fix case-insensitive Git config name matching#2241
Byron merged 1 commit into
mainfrom
case-insensitive-gitconfig

Conversation

@Byron

@Byron Byron commented Sep 14, 2026

Copy link
Copy Markdown
Member

Tasks

This section is for Byron only. Models continuing this PR must not add, remove, check, uncheck, rename, or reorder checkboxes here.

  • refackiew

Everything below this line was generated by Codex GPT-6.

Created by Codex on behalf of Byron. Byron will review before this is ready to merge.

Fixes #2240.

GitConfigParser now matches section and option names without regard to case, so get_value("CORE", "bigname") can read [core] BigName = 1. Quoted subsection names remain case-sensitive: remote "Origin" and remote "origin" are distinct.

The existing ordered multi-dictionary indexes normalized names while retaining the first spelling for enumeration and write-back. Case variants merge into one setting with values in read order, and reads, additions, updates, removals, and renames share the same matching rules. Include sections and remote discovery also accept mixed-case section names.

Regression coverage checks duplicate values, implicit booleans, subsection case, original spelling, mutations, included files, and remote discovery. The three new regression tests failed before the fix.

Validation:

  • Python 3.9.6: config suite and remote creation/removal and multiple-URL tests — 47 passed, 2 existing skips.
  • Python 3.14.7: config suite — 45 passed, 2 existing skips.
  • Repository-wide Ruff lint and formatting, mypy, and basedpyright passed.
  • Codespell 2.4.3 and the affected write test pass after correcting the CI test value spelling.
  • A scaling check parsed 1,000 and 10,000 remote sections in approximately 0.008 and 0.080 seconds.

Git behavior was checked against Git 2.50.1 and the local Git reference at 1630431f326e15fcde608827b5ff38422528eb59, particularly Documentation/config.adoc and the mixed-case/subsection tests in t/t1300-config.sh.

Commits: 94a591d4 (config matching) and c4beffeb (test value spelling).

Each commit received one codex review --commit attempt. Both attempts failed because the CLI login has expired (HTTP 401), so no Codex review result is available.

Byron pushed a commit that referenced this pull request Sep 14, 2026
The lint job on PR #2241 failed in the codespell pre-commit hook because
the new write-preservation regression used "readded" as a sample value.
The same two diagnostics reproduce with codespell 2.4.3 locally.

Use "again" in both the assignment and assertion. The value is arbitrary:
the regression checks the spelling of a removed and recreated option,
so this satisfies lint without changing the behavior under test.

Validation: codespell passes for the three PR files; the affected test
passes on Python 3.14.7; Ruff lint and formatting pass for test_config.py.
Mostly a rubber-stamp, impl seems sane and tests seem to cover the important bits.

<!-- agent -->
GitConfigParser required exact section and option spelling, so valid Git
configuration such as core.BigName could not be read as CORE.bigname.
Differently cased sections and options also stayed separate, causing
lookups to miss later values and writers to create duplicate settings.

Index the ordered multi-dictionary by normalized names while retaining
the first spelling in storage. Lowercase the section/option portion only;
quoted subsection names remain case-sensitive. The shared mapping covers
the inherited ConfigParser accessors, multivalue reads, and mutations
without scanning all stored names. Case variants now merge in read order,
and enumeration and write-back use the first spelling for each name.
Normalize include section matching and remote discovery as well, while
keeping include conditions and remote names case-sensitive.

Add regressions for case variants, duplicate values, implicit booleans,
quoted subsections, spelling-preserving writes, removal and renaming,
included files, and remote discovery. The three new regression tests
failed before the fix. Extend the existing setlast check to cover mixed
case and clearing the name index.

The behavior follows Documentation/config.adoc and the mixed-case and
subsection tests in t/t1300-config.sh from the local Git reference at
1630431f326e15fcde608827b5ff38422528eb59. Regression comparisons with
git config --get and --get-all used Git 2.50.1 (Apple Git-155).

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
@Byron
Byron force-pushed the case-insensitive-gitconfig branch from c4beffe to fb8a0bd Compare September 14, 2026 04:49
@Byron
Byron marked this pull request as ready for review September 14, 2026 05:17
Copilot AI lite review requested due to automatic review settings September 14, 2026 05:17
@Byron
Byron merged commit 92dfd89 into main Sep 14, 2026
54 checks passed
@Byron
Byron deleted the case-insensitive-gitconfig branch September 14, 2026 05:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved moderate and critical issues remain in git/config.py.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This pull request makes Git configuration section and option matching case-insensitive while preserving quoted subsection case sensitivity.

Changes:

  • Normalizes config lookups and mutations.
  • Supports mixed-case include sections and remote discovery.
  • Adds regression coverage for reads, writes, includes, remotes, and booleans.
File summaries
File Summary
test/test_config.py Adds regression coverage.
git/remote.py Supports mixed-case remote sections.
git/config.py Implements normalized config-name matching.
Review details

Suppressed comments (1)

git/config.py:217

  • _keymap is only populated by setall, but the constructor delegates initial entries to OrderedDict and never rebuilds the index. This matters for items_all(), which constructs _OMD(self._defaults): copied default entries can remain unindexed, so a default option spelled Foo and a section option spelled foo are treated as different keys and case-insensitive enumeration/mutation is lost. Populate the map from the entries loaded by the constructor (while preserving the existing list values).
    def __init__(self, *args: Any, **kwargs: Any) -> None:
        self._keymap: Dict[str, str] = {}
        super().__init__(*args, **kwargs)
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread git/config.py
Comment on lines +219 to +221
def _key(self, key: str) -> str:
stored = self._keymap.get(_normalize_name(key), key)
return stored if super().__contains__(stored) else key
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Config lookups are case-sensitive, where git's section and variable names are not

2 participants