Patchwork D9127: changing-files: add clean computation of changed files for linear changesets

login
register
mail settings
Submitter phabricator
Date Sept. 30, 2020, 1:11 p.m.
Message ID <differential-rev-PHID-DREV-cmq5lcikutn7dm2k3xjd-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/47343/
State Superseded
Headers show

Comments

phabricator - Sept. 30, 2020, 1:11 p.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  The `files` field is not reliable, so we need to compute things from scratch. We
  deal with the second simplest case, linear changesets. We diff the current
  manifest with the parent manifest. This reveal the file added, changed and
  removed.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D9127

AFFECTED FILES
  mercurial/metadata.py

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/metadata.py b/mercurial/metadata.py
--- a/mercurial/metadata.py
+++ b/mercurial/metadata.py
@@ -231,6 +231,14 @@ 
     p2 = ctx.p2()
     if p1.rev() == node.nullrev and p2.rev() == node.nullrev:
         return _process_root(ctx)
+    elif p1.rev() != node.nullrev and p2.rev() == node.nullrev:
+        return _process_linear(p1, ctx)
+    elif p1.rev() == node.nullrev and p2.rev() != node.nullrev:
+        # In the wild, one can encounter changeset where p1 is null but p2 is not
+        return _process_linear(p1, ctx, parent=2)
+    elif p1.rev() == p2.rev():
+        # In the wild, one can encounter such "non-merge"
+        return _process_linear(p1, ctx)
     filescopies = computechangesetcopies(ctx)
     filesadded = computechangesetfilesadded(ctx)
     filesremoved = computechangesetfilesremoved(ctx)
@@ -256,6 +264,41 @@ 
     return md
 
 
+def _process_linear(parent_ctx, children_ctx, parent=1):
+    """compute the appropriate changed files for a changeset with a single parent
+    """
+    md = ChangingFiles()
+    parent_manifest = parent_ctx.manifest()
+    children_manifest = children_ctx.manifest()
+
+    copies_candidate = []
+
+    for filename, d in parent_manifest.diff(children_manifest).items():
+        if d[1][0] is None:
+            md.mark_removed(filename)
+        else:
+            copies_candidate.append(filename)
+            if d[0][0] is None:
+                md.mark_added(filename)
+            else:
+                md.mark_touched(filename)
+
+    if parent == 1:
+        copied = md.mark_copied_from_p1
+    elif parent == 2:
+        copied = md.mark_copied_from_p2
+    else:
+        assert False, "bad parent value %d" % parent
+
+    for filename in copies_candidate:
+        copy_info = children_ctx[filename].renamed()
+        if copy_info:
+            source, srcnode = copy_info
+            copied(source, filename)
+
+    return md
+
+
 def computechangesetfilesadded(ctx):
     """return the list of files added in a changeset
     """