diff --git a/hgitaly/service/commit.py b/hgitaly/service/commit.py
index c77043842f651f3d1be13cb55de522028c63bf37_aGdpdGFseS9zZXJ2aWNlL2NvbW1pdC5weQ==..798ac9c4d639537f8750fd3bfbf6e1f4dc7c91cd_aGdpdGFseS9zZXJ2aWNlL2NvbW1pdC5weQ== 100644
--- a/hgitaly/service/commit.py
+++ b/hgitaly/service/commit.py
@@ -1018,6 +1018,11 @@
     return dt.isoformat()
 
 
+def ancestors_inclusive(changeset):
+    yield changeset
+    yield from changeset.ancestors()
+
+
 def latest_changeset_for_path(path, seen_from):
     """Return latest ancestor of ``seen_from`` that touched the given path.
 
@@ -1029,17 +1034,19 @@
         # all changesets change.
         return seen_from
 
-    # gracinet: just hoping that performance wise, this does the right
-    # thing, i.e do any scanning from the end
-    # While we can be reasonably confident that the file exists
-    # in the given revision, there are cases where deduplication implies
-    # that the filelog() predicate would not see any new file revision
-    # in some subgraph, because it's identical to another one that's not
-    # in that subgraph. Hence using the slower `file` is the only way
-    # to go.
-    repo = seen_from.repo()
-    rev = repo.revs('file(%s) and ::%s', b'path:' + path, seen_from).last()
-    return None if rev is None else repo[rev]
+    if path.endswith(b'/'):
+        dir_prefix = path
+    else:
+        dir_prefix = path + b'/'
+
+    for changeset in ancestors_inclusive(seen_from):
+        files = changeset.files()
+        # TODO some performance improvement possible with a binary
+        # search if changeset files are guaranteed to be sorted
+        # but it'd probably make more of a difference in a Rust impl
+        for fpath in files:
+            if fpath == path or fpath.startswith(dir_prefix):
+                return changeset
 
 
 def blamelines(repo, ctx, file):