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):