diff --git a/accounts/tests.py b/accounts/tests.py
index bc6c48e501..93fa971288 100644
--- a/accounts/tests.py
+++ b/accounts/tests.py
@@ -21,32 +21,61 @@ def test_username_is_page_title(self):
         response = self.client.get(self.user1_url)
         self.assertContains(response, "
user1
", html=True)
 
-    def test_stat_commits(self):
+    def test_stat_commits_no_commits(self):
+        user1_response = self.client.get(self.user1_url)
+        self.assertNotContains(user1_response, "Commits")
+
+    def test_stat_commits_commiter_full_name(self):
+        User.objects.create_user(
+            first_name="James",
+            last_name="Bond",
+            username="007",
+            email="007@mi5.co.uk",
+            password="*****************",
+        )
         Revision.objects.create(
-            author="user1",
+            author="James Bond <007@mi5.co.uk>",
             rev="91c879eda595c12477bbfa6f51115e88b75ddf88",
             _time=1731669560,
         )
         Revision.objects.create(
-            author="user1",
+            author="James Bonderson ",
             rev="da2432cccae841f0d7629f17a5d79ec47ed7b7cb",
             _time=1731669560,
         )
+        user1_response = self.client.get(reverse("user_profile", args=["007"]))
+        self.assertContains(
+            user1_response,
+            'Commits: 1.',
+            html=True,
+        )
+
+    def test_stat_commits_commiter_username(self):
+        User.objects.create_user(
+            first_name="James",
+            last_name="Bond",
+            username="007",
+            email="007@mi5.co.uk",
+            password="*****************",
+        )
         Revision.objects.create(
-            author="user3",
+            author="007 <007@mi5.co.uk>",
+            rev="91c879eda595c12477bbfa6f51115e88b75ddf88",
+            _time=1731669560,
+        )
+        Revision.objects.create(
+            author="Elizabeth Bennet <300792567+pnp@users.noreply.github.com>",
             rev="63dbe30d3363715deaf280214d75b03f6d65a571",
             _time=1731669560,
         )
-
-        user1_response = self.client.get(self.user1_url)
-        user2_response = self.client.get(self.user2_url)
+        user1_response = self.client.get(reverse("user_profile", args=["007"]))
         self.assertContains(
             user1_response,
             'Commits: 2.',
+            '?author=007">Commits: 1.',
             html=True,
         )
-        self.assertNotContains(user2_response, "Commits")
 
     def test_stat_tickets(self):
         Ticket.objects.create(status="new", reporter="user1")
diff --git a/accounts/views.py b/accounts/views.py
index bbdf888dbd..81b1303b49 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -40,7 +40,7 @@ def get_user_stats(user):
     key = "user_vital_status:%s" % hashlib.md5(username).hexdigest()
     info = c.get(key)
     if info is None:
-        info = trac_stats.get_user_stats(user.username)
+        info = trac_stats.get_user_stats(user)
         # Hide any stat with a value = 0 so that we don't accidentally insult
         # non-contributors.
         for k, v in list(info.items()):
diff --git a/tracdb/stats.py b/tracdb/stats.py
index 2cfa6c1b21..853c179331 100644
--- a/tracdb/stats.py
+++ b/tracdb/stats.py
@@ -6,6 +6,7 @@
 from collections import OrderedDict, namedtuple
 
 from django.conf import settings
+from django.db.models import Q
 
 from .models import Revision, Ticket, TicketChange
 
@@ -34,44 +35,46 @@ def _inner(f):
     return _inner
 
 
-def get_user_stats(username):
+def get_user_stats(user):
     stats = OrderedDict()
     for func in sorted(_statfuncs, key=operator.attrgetter("title")):
-        stats[func.title] = func(username)
+        stats[func.title] = func(user)
     return stats
 
 
 @stat("Commits")
-def commit_count(username):
-    count = Revision.objects.filter(author=username).count()
-    # This assumes that the username is their GitHub username, this is very
-    # often the case. If this is incorrect, the GitHub will show no commits.
-    link = f"https://github.com/django/django/commits/main/?author={username}"
+def commit_count(user):
+    count = Revision.objects.filter(
+        Q(author__istartswith=f"{user.username} <")
+        | Q(author__istartswith=f"{user.get_full_name()} <")
+    ).count()
+    # This assumes that the username is their GitHub username.
+    link = f"https://github.com/django/django/commits/main/?author={user.username}"
     return StatData(count=count, link=link)
 
 
 @stat("Tickets fixed")
-def tickets_fixed(username):
-    query = f"owner={username}&resolution=fixed"
+def tickets_fixed(user):
+    query = f"owner={user.username}&resolution=fixed"
     count = Ticket.objects.from_querystring(query).count()
     link = get_trac_link(query)
     return StatData(count=count, link=link)
 
 
 @stat("Tickets opened")
-def tickets_opened(username):
-    query = f"reporter={username}"
+def tickets_opened(user):
+    query = f"reporter={user.username}"
     count = Ticket.objects.from_querystring(query).count()
     link = get_trac_link(query)
     return StatData(count=count, link=link)
 
 
 @stat("New tickets triaged")
-def new_tickets_reviewed(username):
+def new_tickets_reviewed(user):
     # We don't want to de-dup as for tickets_closed: multiple reviews of the
     # same ticket should "count" as a review.
     qs = TicketChange.objects.filter(
-        author=username, field="stage", oldvalue="Unreviewed"
+        author=user.username, field="stage", oldvalue="Unreviewed"
     )
     qs = qs.exclude(newvalue="Unreviewed")
     return StatData(count=qs.count(), link=None)