Skip to content

fix(commit): parse the encoding header when deserializing - #2286

Open
Keerthana-64 wants to merge 1 commit into
gitpython-developers:mainfrom
Keerthana-64:commit-encoding-header
Open

Keerthana-64 wants to merge 1 commit into
gitpython-developers:mainfrom
Keerthana-64:commit-encoding-header

Conversation

@Keerthana-64

Copy link
Copy Markdown
Contributor

Commit._deserialize tests each header line with buf[0:10] == b"encoding ". The slice is 10 bytes, the literal is 9, and buf is stripped, so the comparison never matches and the branch that reads a commit's declared encoding is unreachable: every commit read from the object database is decoded with the default UTF-8. For a repository committed under i18n.commitencoding = ISO-8859-1:

git log:    André | Résumé
GitPython:  encoding='UTF-8', author.name='Andr\ufffd', message='R\ufffdsum\ufffd\n'

so the identity and message GitPython reports for a commit differ from what git shows for the same object, and re-serializing such a commit drops its encoding header and stores the garbled text. Commit headers come from whoever authored the commit, including commits fetched from untrusted repositories.

Fixing the slice alone would introduce a crash: the identity lines decode with errors="replace", which does not guard against an unknown codec name, so a commit declaring encoding pony-speak would raise LookupError from any attribute access. The declared encoding is adopted only when Python has a text codec for it, probed with a one-byte decode because decoding b"" skips the codec lookup; an unknown name keeps the previous default-encoding behavior and logs the error. Adds regression tests for both cases in test/test_commit.py; the first fails before the change.

`Commit._deserialize` compared a 10-byte slice of each stripped header
line against the 9-byte literal `b"encoding "`, so the comparison never
matched and the branch reading a commit's declared encoding was
unreachable. Every commit parsed from the object database was decoded
with the default UTF-8: `Commit.encoding` reported `UTF-8` regardless of
the header, and the author, committer, and message of a commit written
under `i18n.commitencoding` came back with U+FFFD replacement characters
while `git log` shows them correctly. Re-serializing such a commit also
dropped its `encoding` header and stored the garbled text.

Compare the right slice length so the header is read. Adopt the declared
encoding only when Python has a text codec for it: the identity lines
are decoded with `errors="replace"`, which does not guard against an
unknown codec name, so a commit declaring one would otherwise raise
`LookupError` on attribute access. An unknown name keeps the previous
behavior (the default encoding) and logs the error.

Validated against a repository committed under `i18n.commitencoding =
ISO-8859-1`: `commit.encoding`, `commit.author.name`, and
`commit.message` now match what `git log` shows. Adds regression tests
in `test/test_commit.py` that fail before the change.
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.

1 participant