Skip to content

Commit 8afd1fd

Browse files
codexByron
authored andcommitted
fix: restore Actor.name_email_regex (#2220)
<!-- agent --> GitPython 3.1.60 removed the Actor.name_email_regex class attribute while replacing internal actor parsing, which broke downstream consumers such as python-semantic-release. Restore the historical compiled pattern as a compatibility API while leaving Actor._from_string on its linear delimiter parser. The regression covers the public match behavior and verifies the parser remains independent of the regex, preserving the GHSA-g5vv-9gxw-82hx fix. Assisted-by: GPT 5.6 Co-authored-by: GPT 5.6 <codex@openai.com>
1 parent a9fb008 commit 8afd1fd

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

git/util.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,10 @@ class Actor:
858858
committers and authors or anything with a name and an email as mentioned in the git
859859
log entries."""
860860

861+
# Kept for compatibility only: searching long malformed strings with this regex can
862+
# take quadratic time. ``_from_string`` deliberately uses delimiter scans instead.
863+
name_email_regex = re.compile(r"(.*) <(.*?)>")
864+
861865
# ENVIRONMENT VARIABLES
862866
# These are read when creating new commits.
863867
env_author_name = "GIT_AUTHOR_NAME"

test/test_actor.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# This module is part of GitPython and is released under the
44
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
55

6+
from unittest import mock
7+
68
from git import Actor
79

810
from test.lib import TestBase
@@ -29,10 +31,15 @@ def test_from_string_should_handle_just_name(self):
2931

3032
def test_from_string_handles_unterminated_email_without_regex_backtracking(self):
3133
value = "A" * 20_000 + " <unterminated"
32-
actor = Actor._from_string(value)
33-
self.assertNotIn("name_email_regex", vars(Actor))
34+
with mock.patch.object(Actor, "name_email_regex", None):
35+
actor = Actor._from_string(value)
3436
self.assertEqual(actor, Actor(value, None))
3537

38+
def test_name_email_regex_is_available(self):
39+
match = Actor.name_email_regex.match("Michael Trier <mtrier@example.com>")
40+
self.assertIsNotNone(match)
41+
self.assertEqual(match.groups(), ("Michael Trier", "mtrier@example.com"))
42+
3643
def test_from_string_does_not_parse_across_lines(self):
3744
self.assertEqual(Actor._from_string("x <a>\n y <b>"), Actor("x", "a"))
3845

0 commit comments

Comments
 (0)