mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
Add alternative linkrev lookup logic
Summary: The old linkrev lookup logic depended on the repo containing the latest commit to have contained that particular version of the file. If the latest version had been stripped however (like what happens in rebase --abort currently), the linkrev function would attempt to scan history from the current rev, trying to find the linkrev node. If the filectx was not provided with a 'current node', the linkrev function would return None. This caused certain places to break, like the Mercurial merge conflict resolution logic (which constructs a filectx using only a fileid, and no changeid, for the merge ancestor). The fix is to allow scanning all the latest commits in the repo, looking for the appropriate linkrev. This is pretty slow (1 second for every 14,000 commits inspected), but is better than just returning None and crashing. Test Plan: Manually repro'd the issue by making a commit, amending it, stripping the amended version and going back to the original, making two sibling commits on top of the original, then rebasing sibling 1 onto sibling 2 (so that the original commit that had the bad linknode data was the ancestor during the merge). Previously this failed, now it passes. I'd write a test, but it's 11pm and I'm tired and I need this in by early tomorrow morning to make the cut. Reviewers: #sourcecontrol, ttung, rmcelroy Reviewed By: rmcelroy Subscribers: trunkagent, rmcelroy Differential Revision: https://phabricator.fb.com/D2826850 Signature: t1:2826850:1452680293:cb8c1f8c20ce13ad632925137dbdce6e994ab360
This commit is contained in:
parent
707f243248
commit
13c2a7823f
@ -56,7 +56,26 @@ class remotefilectx(context.filectx):
|
||||
if rev is not None:
|
||||
return rev
|
||||
|
||||
# TODO: look up alternate histories in historical blob files
|
||||
# Search all commits for the appropriate linkrev (slow, but uncommon)
|
||||
path = self._path
|
||||
fileid = self._fileid
|
||||
cl = self._repo.unfiltered().changelog
|
||||
ma = self._repo.manifest
|
||||
|
||||
# If we don't find it within the top 100,000 commits, it probably
|
||||
# doesn't exist, so give up early instead of wasting the user's time.
|
||||
searchlimit = max(0, len(cl) - 100000)
|
||||
for rev in range(len(cl) - 1, searchlimit, -1):
|
||||
node = cl.node(rev)
|
||||
data = cl.read(node) # get changeset data (we avoid object creation)
|
||||
if path in data[3]: # checking the 'files' field.
|
||||
# The file has been touched, check if the hash is what we're
|
||||
# looking for.
|
||||
if fileid == ma.readfast(data[0]).get(path):
|
||||
return rev
|
||||
|
||||
# Couldn't find the linkrev. This should generally not happen, and will
|
||||
# likely cause a crash.
|
||||
return None
|
||||
|
||||
def introrev(self):
|
||||
|
Loading…
Reference in New Issue
Block a user