I solved my problem using git blame and taking a reverse approach, as suggested by torek. This works for my use case as I am attempting to show metadata alongside a file in a git repository, so I know the set of lines I'd like to find original positions for. Assuming that A is an ancestor commit of Z, we can do the following:
git blame -fns Z -- api/v3/views.py
This will give commit hashes, original tree paths, and line numbers for each line in the file, e.g.
481daae85d6 api/v3/files/views.py 2 4) from rest_framework.response import Response
^ ^ ^ ^
$1 $2 $3 $4
Let's denote a position as <hash>:<path>@<line>. This shows us that Z:api/v3/views.py@4 originally showed up as 481daae85d6:api/v3/files/views.py:2.
Last step: the position P we've identified in A might not be the original commit that included that line, which will lead to false negatives. When importing these meta annotations, we can do another git blame for that specific line in that commit to determine the original commit:
git blame -fns -L <line>,<line> A -- <path>
Then we can store the annotation on the returned commit hash, rather than A.
The open question here is whether this will be enough: code annotations will likely still be relevant even if a line was modified slightly, while this approach will cause these annotations to be "lost".