Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions git/objects/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -892,10 +892,13 @@ def _deserialize(self, stream: BytesIO) -> "Commit":
self.encoding = self.default_encoding
self.gpgsig = ""

# Read headers.
enc = next_line
buf = enc.strip()
while buf:
# Read headers. Like git, end them only at an empty line. A line holding only
# whitespace (such as "\r" or a bare continuation space) is still a header
# line, and only trailing whitespace is stripped, so a continuation line is
# never read as a header of its own.
line = next_line
while line not in (b"", b"\n"):
buf = line.rstrip()
if buf[0:9] == b"encoding ":
raw_encoding = buf[9:]
try:
Expand All @@ -917,15 +920,15 @@ def _deserialize(self, stream: BytesIO) -> "Commit":
if not sigbuf:
break
if sigbuf[0:1] != b" ":
buf = sigbuf.strip()
line = sigbuf
is_next_header = True
break
sig_lines.append(sigbuf[1:])
# END read all signature
self.gpgsig = b"".join(sig_lines).rstrip(b"\n").decode(self.encoding, "ignore")
if is_next_header:
continue
buf = readline().strip()
line = readline()

# Decode the author's name.
try:
Expand Down
22 changes: 22 additions & 0 deletions test/test_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,28 @@ def test_deserialization_multiple_encoding_headers(self):
self.assertEqual(cmt.committer.name, "André")
self.assertEqual(cmt.message, "Résumé\n")

def test_deserialization_headers_end_at_empty_line(self):
# Git ends the headers only at an empty line. A line holding only whitespace
# belongs to the headers, so what follows it is not the message.
for blank in (b"\r\n", b" \n", b"\t\n"):
with self.subTest(blank=blank):
data = (
b"tree 3385f7b1e5f91930a3bd3e07105e113fca29981d\n"
b"author Andr\xe9 <andre@example.com> 1112591163 +0200\n"
b"committer Andr\xe9 <andre@example.com> 1112591163 +0200\n"
b"x-note a\n" + blank + b"Co-authored-by: Mallory <mallory@example.com>\n"
b"encoding ISO-8859-1\n"
b"\n"
b"R\xe9sum\xe9\n"
)
cmt = self.rorepo.commit()
cmt._deserialize(BytesIO(data))

self.assertEqual(cmt.encoding, "ISO-8859-1")
self.assertEqual(cmt.author.name, "André")
self.assertEqual(cmt.message, "Résumé\n")
self.assertEqual(cmt.co_authors, [])

@with_rw_directory
def test_identity_cannot_alter_headers(self, rw_dir):
"""A name or email must not add header lines or present another identity."""
Expand Down
Loading