Skip to content

fix: join backslash line continuations when reading config values - #2227

Merged
Byron merged 3 commits into
gitpython-developers:mainfrom
nkbeast:fix-config-backslash-continuation
Sep 4, 2026
Merged

fix: join backslash line continuations when reading config values#2227
Byron merged 3 commits into
gitpython-developers:mainfrom
nkbeast:fix-config-backslash-continuation

Conversation

@nkbeast

@nkbeast nkbeast commented Sep 3, 2026

Copy link
Copy Markdown

git config joins an unquoted value that ends in a backslash with the next line: the backslash and the newline are removed and the next line is appended verbatim. Reproducing with git itself:

$ printf '[a]\n\tk = line1\\\n line2\n' > g.cfg
$ git config -f g.cfg a.k
line1 line2

GitPython only implemented multi-line values for quoted strings. For unquoted values the continuation line was silently dropped — GitConfigParser read back line1\ and the line2 content vanished, truncating whatever the user had stored (aliases, hook commands, any hand-edited multi-line value).

The fix reads the continuation inside _read and joins it, chaining across lines that themselves end in a backslash, with the exact rules git uses:

  • a single trailing backslash → continuation, next line appended verbatim (leading whitespace included)
  • an even number of trailing backslashes → an escaped one, value ends there (val\\\\ stays val\\\\)
  • a lone backslash right at end-of-file → dropped

All five cases are asserted against git's own output in the new test.

@nkbeast
nkbeast force-pushed the fix-config-backslash-continuation branch from 1f4913b to 22b4db5 Compare September 3, 2026 21:06
git config joins an unquoted value that ends in a backslash with the
next line: the backslash and the newline are removed and the next line
is appended verbatim, so 'k = line1\' followed by ' line2' reads back
as 'line1 line2'. GitPython only implemented multi-line values for
quoted strings; for unquoted values the continuation line was silently
dropped, truncating whatever was stored in the config.

Read the continuation inside _read and join it, chaining across lines
that themselves end in a backslash. An even number of trailing
backslashes is an escaped one, so the value ends there; a single
backslash right at end-of-file is dropped, matching git. Verified
against git itself for every case covered by the new tests.
@nkbeast
nkbeast force-pushed the fix-config-backslash-continuation branch from 22b4db5 to 075a664 Compare September 3, 2026 21:10
Byron and others added 2 commits September 4, 2026 06:26
<!-- agent -->
Git treats # and ; outside quotes as the start of a comment. A trailing
backslash in that ignored text therefore cannot continue the value.

The continuation loop counted trailing slashes without lexical context, so
it consumed the next option and a later writable flush silently dropped that
setting.

- Track quote and escape state while checking the accumulated value.
- Stop continuation scanning at an unquoted comment.
- Cover preservation of the following option across a writable flush.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <codex@openai.com>
Git removes each backslash-newline pair before parsing the resulting logical
value. Appending physical lines after processing only the first line left
trailing whitespace, comments, quotes, and recognized escapes literal.

That divergence returned values unlike git config and could preserve comment
text as configuration data.

- Accumulate continuation text before parsing it.
- Apply whitespace, comment, quote, and escape handling once to the complete value.
- Cover each affected syntax form with Git-compatible expectations.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <codex@openai.com>
@Byron

Byron commented Sep 4, 2026

Copy link
Copy Markdown
Member

Thanks!

As a note: The current Git configuration file parser is inherently insufficient and has many bugs. Fixing them all isn't the goal for GitPython 3.X, it's only remedy.
Version 4 will address these issues (much more) properly

@Byron
Byron merged commit 9ebf8b6 into gitpython-developers:main Sep 4, 2026
53 checks passed
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.

2 participants