Patchwork [1,of,6] revert: triage "deleted" files into more appropriate categories

login
register
mail settings
Submitter Pierre-Yves David
Date Aug. 14, 2014, 9:35 p.m.
Message ID <961f7bc8ba57c53eb9bf.1408052155@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/5395/
State Accepted
Headers show

Comments

Pierre-Yves David - Aug. 14, 2014, 9:35 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1406944673 25200
#      Fri Aug 01 18:57:53 2014 -0700
# Node ID 961f7bc8ba57c53eb9bfed1be1a06a672cbf77d6
# Parent  8bd56983281db28fbefb6058c8f6ec5dc61ea8e8
revert: triage "deleted" files into more appropriate categories

Status can return file as "deleted". This is only a special case related to
working directory state: file is recorded as tracked but no file exists on disk.
This will never be a state obtainable from manifests comparison.

"deleted" file have another working directory status shadowed by the lack of
file. They will -alway- be touched by revert. The "lack of file" can be seen as
a modification. The file will never match the same "content" as in the revert
target. From there we have two options:

1. The file exists in the target and can be seen as "modified".
2. The file does not exist in the target and can be seen as "added".

So now we just dispatch elements from delete into appropriate categories.

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2371,11 +2371,20 @@  def revert(ui, repo, ctx, parents, *pats
 
         changes = repo.status(node1=node, match=m, clean=True)
         modified = set(changes[0])
         added    = set(changes[1])
         removed  = set(changes[2])
-        deleted  = set(changes[3])
+        _deleted  = set(changes[3])
+
+        # split between files known in target manifest and the others
+        smf = set(mf)
+
+        # determine the exact nature of the deleted changesets
+        _deletedadded = _deleted - smf
+        _deletedmodified = _deleted - _deletedadded
+        added |= _deletedadded
+        modified |= _deletedmodified
 
         # We need to account for the state of file in the dirstate
         #
         # Even, when we revert agains something else than parent. this will
         # slightly alter the behavior of revert (doing back up or not, delete
@@ -2388,10 +2397,12 @@  def revert(ui, repo, ctx, parents, *pats
         else:
             changes = repo.status(node1=parent, match=m)
             dsmodified = set(changes[0])
             dsadded    = set(changes[1])
             dsremoved  = set(changes[2])
+            dsadded |= _deletedadded
+            dsmodified |= _deletedmodified
 
         # if f is a rename, update `names` to also revert the source
         cwd = repo.getcwd()
         for f in dsadded:
             src = repo.dirstate.copied(f)
@@ -2404,21 +2415,16 @@  def revert(ui, repo, ctx, parents, *pats
         def removeforget(abs):
             if repo.dirstate[abs] == 'a':
                 return _('forgetting %s\n')
             return _('removing %s\n')
 
-        # split between files known in target manifest and the others
-        smf = set(mf)
-
         missingmodified = dsmodified - smf
         dsmodified -= missingmodified
         missingadded = dsadded - smf
         dsadded -= missingadded
         missingremoved = dsremoved - smf
         dsremoved -= missingremoved
-        missingdeleted = deleted - smf
-        deleted -= missingdeleted
 
         # action to be actually performed by revert
         # (<list of file>, message>) tuple
         actions = {'revert': ([], _('reverting %s\n')),
                    'add': ([], _('adding %s\n')),
@@ -2434,12 +2440,10 @@  def revert(ui, repo, ctx, parents, *pats
             (missingmodified,  (actions['remove'],   True)),
             (dsadded,          (actions['revert'],   True)),
             (missingadded,     (actions['remove'],   False)),
             (dsremoved,        (actions['undelete'], True)),
             (missingremoved,   (None,                False)),
-            (deleted,          (actions['revert'],   False)),
-            (missingdeleted,   (actions['remove'],   False)),
             )
 
         for abs, (rel, exact) in sorted(names.items()):
             # hash on file in target manifest (or None if missing from target)
             mfentry = mf.get(abs)