changeset 5532:5a70669beaa3

branching: merge with stable
author Anton Shestakov <av6@dwimlabs.net>
date Tue, 08 Sep 2020 11:56:17 +0800
parents af835b32e155 (current diff) 3e23bedf8d38 (diff)
children 9f9f04301df0
files CHANGELOG debian/changelog hgext3rd/evolve/cmdrewrite.py hgext3rd/evolve/evolvecmd.py hgext3rd/evolve/metadata.py hgext3rd/topic/__init__.py hgext3rd/topic/revset.py tests/test-topic.t
diffstat 9 files changed, 173 insertions(+), 182 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Sep 04 21:33:11 2020 +0200
+++ b/.hgtags	Tue Sep 08 11:56:17 2020 +0800
@@ -88,3 +88,4 @@
 8d955635cf457aaa4810d77740721d4275001f74 9.3.1
 27d57ca8686590867e62e3d42c96bad84a5f56ef 10.0.0
 fb543438704b73b22023a493c9ef76fc8746b796 10.0.1
+1cce884c944830a7b331a17fd18614b93cbac987 10.0.2
--- a/CHANGELOG	Fri Sep 04 21:33:11 2020 +0200
+++ b/CHANGELOG	Tue Sep 08 11:56:17 2020 +0800
@@ -12,12 +12,22 @@
 
   * stack: support foo#stack relation revset (hg-5.4+ only)
 
-10.0.2 - in progress
+10.0.2 -- 2020-09-08
 --------------------
 
   * py3: use '%d' for formatting revision numbers in stable range cache warning
     (issue6390)
 
+  * split: correctly handle discard action after previously splitting changes
+    into more than one commit
+
+  * uncommit: fix situation where added file would be left in a wrong state
+
+topic (0.19.2)
+
+  * revset: when processing `topic(REVSET)`, no longer return changesets
+    without topic from REVSET
+
 10.0.1 -- 2020-07-31
 --------------------
 
--- a/debian/changelog	Fri Sep 04 21:33:11 2020 +0200
+++ b/debian/changelog	Tue Sep 08 11:56:17 2020 +0800
@@ -1,3 +1,9 @@
+mercurial-evolve (10.0.2-1) unstable; urgency=medium
+
+  * new upstream release
+
+ -- Anton Shestakov <av6@dwimlabs.net>  Tue, 08 Sep 2020 11:18:54 +0800
+
 mercurial-evolve (10.0.1-1) unstable; urgency=medium
 
   * new upstream release
--- a/hgext3rd/evolve/cmdrewrite.py	Fri Sep 04 21:33:11 2020 +0200
+++ b/hgext3rd/evolve/cmdrewrite.py	Tue Sep 08 11:56:17 2020 +0800
@@ -341,100 +341,49 @@
     newid = repo.commitctx(new)
     return newid
 
-def _uncommitdirstate(repo, oldctx, match, interactive):
-    """Fix the dirstate after switching the working directory from
-    oldctx to a copy of oldctx not containing changed files matched by
-    match.
+# TODO: call core's version once we've dropped support for hg <= 4.9
+def movedirstate(repo, newctx, match=None):
+    """Move the dirstate to newctx and adjust it as necessary.
+
+    A matcher can be provided as an optimization. It is probably a bug to pass
+    a matcher that doesn't match all the differences between the parent of the
+    working copy and newctx.
     """
-    ctx = repo[b'.']
+    oldctx = repo[b'.']
     ds = repo.dirstate
-    copies = dict(ds.copies())
-    if interactive:
-        # In interactive cases, we will find the status between oldctx and ctx
-        # and considering only the files which are changed between oldctx and
-        # ctx, and the status of what changed between oldctx and ctx will help
-        # us in defining the exact behavior
-        st = repo.status(oldctx, ctx, match=match)
-        for f in st.modified:
-            # These are files which are modified between oldctx and ctx which
-            # contains two cases: 1) Were modified in oldctx and some
-            # modifications are uncommitted
-            # 2) Were added in oldctx but some part is uncommitted (this cannot
-            # contain the case when added files are uncommitted completely as
-            # that will result in status as removed not modified.)
-            # Also any modifications to a removed file will result the status as
-            # added, so we have only two cases. So in either of the cases, the
-            # resulting status can be modified or clean.
-            if ds[f] == b'r':
-                # But the file is removed in the working directory, leaving that
-                # as removed
-                continue
+    dscopies = dict(ds.copies())
+    ds.setparents(newctx.node(), node.nullid)
+    s = newctx.status(oldctx, match=match)
+    for f in s.modified:
+        if ds[f] == b'r':
+            # modified + removed -> removed
+            continue
+        ds.normallookup(f)
+
+    for f in s.added:
+        if ds[f] == b'r':
+            # added + removed -> unknown
+            ds.drop(f)
+        elif ds[f] != b'a':
+            ds.add(f)
+
+    for f in s.removed:
+        if ds[f] == b'a':
+            # removed + added -> normal
             ds.normallookup(f)
-
-        for f in st.added:
-            # These are the files which are added between oldctx and ctx(new
-            # one), which means the files which were removed in oldctx
-            # but uncommitted completely while making the ctx
-            # This file should be marked as removed if the working directory
-            # does not adds it back. If it's adds it back, we do a normallookup.
-            # The file can't be removed in working directory, because it was
-            # removed in oldctx
-            if ds[f] == b'a':
-                ds.normallookup(f)
-                continue
+        elif ds[f] != b'r':
             ds.remove(f)
 
-        for f in st.removed:
-            # These are files which are removed between oldctx and ctx, which
-            # means the files which were added in oldctx and were completely
-            # uncommitted in ctx. If a added file is partially uncommitted, that
-            # would have resulted in modified status, not removed.
-            # So a file added in a commit, and uncommitting that addition must
-            # result in file being stated as unknown.
-            if ds[f] == b'r':
-                # The working directory say it's removed, so lets make the file
-                # unknown
-                ds.drop(f)
-                continue
-            ds.add(f)
-    else:
-        st = repo.status(oldctx.p1(), oldctx, match=match)
-        for f in st.modified:
-            if ds[f] == b'r':
-                # modified + removed -> removed
-                continue
-            ds.normallookup(f)
-
-        for f in st.added:
-            if ds[f] == b'r':
-                # added + removed -> unknown
-                ds.drop(f)
-            elif ds[f] != b'a':
-                ds.add(f)
-
-        for f in st.removed:
-            if ds[f] == b'a':
-                # removed + added -> normal
-                ds.normallookup(f)
-            elif ds[f] != b'r':
-                ds.remove(f)
-
     # Merge old parent and old working dir copies
-    oldcopies = {}
-    if interactive:
-        # Interactive had different meaning of the variables so restoring the
-        # original meaning to use them
-        st = repo.status(oldctx.p1(), oldctx, match=match)
-    for f in (st.modified + st.added):
-        src = oldctx[f].renamed()
-        if src:
-            oldcopies[f] = src[0]
-    oldcopies.update(copies)
-    copies = dict((dst, oldcopies.get(src, src))
-                  for dst, src in oldcopies.items())
+    oldcopies = copies.pathcopies(newctx, oldctx, match)
+    oldcopies.update(dscopies)
+    newcopies = {
+        dst: oldcopies.get(src, src)
+        for dst, src in oldcopies.items()
+    }
     # Adjust the dirstate copies
-    for dst, src in copies.items():
-        if (src not in ctx or dst in ctx or ds[dst] != b'a'):
+    for dst, src in newcopies.items():
+        if src not in newctx or dst in newctx or ds[dst] != b'a':
             src = None
         ds.copy(src, dst)
 
@@ -567,8 +516,7 @@
             hg.updaterepo(repo, newid, True)
         else:
             with repo.dirstate.parentchange(), compat.parentchange(repo):
-                repo.dirstate.setparents(newid, node.nullid)
-                _uncommitdirstate(repo, old, match, interactive)
+                movedirstate(repo, repo[newid], match)
         if not repo[newid].files():
             ui.warn(_(b"new changeset is empty\n"))
             ui.status(_(b"(use 'hg prune .' to remove it)\n"))
@@ -1309,14 +1257,13 @@
                         # diff action or by showing the remaining and
                         # prompting for confirmation
                         ui.status(_(b'discarding remaining changes\n'))
-                        target = newcommits[0]
+                        target = newcommits[-1]
                         args = []
                         kwargs = {}
                         code = cmdutil.revert.__code__
                         # hg <= 5.5 (8c466bcb0879)
                         if r'parents' in code.co_varnames[:code.co_argcount]:
                             args.append((target, node.nullid))
-                        assert target.node() == repo.dirstate.p1()
                         if pats:
                             status = repo.status(match=matcher)
                             dirty = set()
--- a/hgext3rd/evolve/evolvecmd.py	Fri Sep 04 21:33:11 2020 +0200
+++ b/hgext3rd/evolve/evolvecmd.py	Tue Sep 08 11:56:17 2020 +0800
@@ -637,8 +637,7 @@
         otherdiv = repo[othernode]
 
         with repo.dirstate.parentchange(), compat.parentchange(repo):
-            repo.dirstate.setparents(publicnode, nodemod.nullid)
-            dirstatedance(repo, divergent, publicnode, None)
+            cmdrewrite.movedirstate(repo, repo[publicnode])
         # check if node to be committed has changes same as public one
         s = publicdiv.status()
         if not (s.added or s.removed or s.deleted or s.modified):
@@ -650,9 +649,7 @@
             return (True, publicnode)
 
     with repo.dirstate.parentchange(), compat.parentchange(repo):
-        repo.dirstate.setparents(resparent, nodemod.nullid)
-
-    dirstatedance(repo, divergent, resparent, None)
+        cmdrewrite.movedirstate(repo, repo[resparent])
 
     # merge the branches
     mergebranches(repo, divergent, other, base)
@@ -793,73 +790,6 @@
                              metadata=metadata, ui=repo.ui)
         repo.filteredrevcache.clear()
 
-def dirstatedance(repo, oldparent, newparent, match):
-    """utility function to fix the dirstate when we change parents from
-    oldparent to newparent with a dirty working directory using
-    repo.dirstate.setparents()
-
-    Lets refer oldparent as Pold
-               newparent as Pnew
-
-    Now when we are on oldparent with a dirty working directory, there are three
-    types of files which we are concerned about. They are files having modified,
-    added and removed status.
-
-    Lets refer modified files as Fm
-               added files as Fa
-               removed files as Fr
-
-    Now, between Pold and Pnew, files can be modified, files can be added, files
-    can be removed.
-
-    Lets refer modification of a file between Pold to Pnew as Cm
-               addition of a file between Pold to Pnew as Ca
-               removal of a file between Pold to Pnew as Cr
-
-    Now let's play combinations and permutations:
-
-    |---------------------------------------------------------------|
-    | Type of file |  Changes between |   End status with Pnew as   |
-    |   in wdir    |    Pold -> Pnew  |       wdir parent           |
-    |--------------|------------------|-----------------------------|
-    |              |                  |                             |
-    |   Fm         |      Cm          |       Modified or clean     |
-    |--------------|------------------|-----------------------------|
-    |   Fm         |      Cr          |           Added             |
-    |--------------|------------------|-----------------------------|
-    |   Fm         |      Ca          |       Not possible (1)      |
-    |--------------|------------------|-----------------------------|
-    |   Fa         |      Ca          |       Modified or clean     |
-    |--------------|------------------|-----------------------------|
-    |   Fa         |      Cm          |       Not possible (2)      |
-    |--------------|------------------|-----------------------------|
-    |   Fa         |      Cr          |       Not possible (2)      |
-    |--------------|------------------|-----------------------------|
-    |   Fr         |      Cr          | File should be untracked (3)|
-    |--------------|------------------|-----------------------------|
-    |   Fr         |      Ca          |       Not possible (4)      |
-    |--------------|------------------|-----------------------------|
-    |   Fr         |      Cm          |           Removed           |
-    |--------------|------------------|-----------------------------|
-
-    (1): File is modified in wdir, it means file was present in Pold, so
-         addition of that file between Pold to Pnew is not possible
-
-    (2): File was added in wdir, it means file was not present in Pold, so
-         deletion or modification of that file from Pold to Pnew is not possible
-
-    (3): File should be dropped from the dirstate, Pnew has it removed, so no
-         need to mark that removed again
-
-    (4): File was removed in wdir, it means file was present in Pold, so
-         addition of that file between Pold to Pnew is not possible
-
-    """
-
-    # falling back to an existing function, in future we should have logic in
-    # this function only
-    cmdrewrite._uncommitdirstate(repo, oldparent, match, True)
-
 def mergehook(repo, base, divergent, other):
     """function which extensions can wrap and merge data introduced by them
     while resolving content-divergence"""
--- a/hgext3rd/topic/revset.py	Fri Sep 04 21:33:11 2020 +0200
+++ b/hgext3rd/topic/revset.py	Tue Sep 08 11:56:17 2020 +0800
@@ -67,8 +67,6 @@
     topics.discard(b'')
 
     def matches(r):
-        if r in s:
-            return True
         topic = repo[r].topic()
         if not topic:
             return False
--- a/tests/test-split.t	Fri Sep 04 21:33:11 2020 +0200
+++ b/tests/test-split.t	Tue Sep 08 11:56:17 2020 +0800
@@ -1285,3 +1285,85 @@
      @@ -0,0 +1,1 @@
      +a
   
+  $ cd ..
+
+Discard after splitting into more than one changeset
+
+  $ hg init discard-after-many
+  $ cd discard-after-many
+
+  $ echo 0 > num
+  $ cat > editor.sh << '__EOF__'
+  > NUM=$(cat num)
+  > NUM=`expr "$NUM" + 1`
+  > echo "$NUM" > num
+  > echo "split$NUM" > "$1"
+  > __EOF__
+  $ export HGEDITOR="\"sh\" \"editor.sh\""
+
+  $ echo a > a
+  $ echo b > b
+  $ echo c > c
+  $ hg add a b c
+  $ hg ci -m 'a b c'
+
+XXX: this shouldn't ask to re-examine changes in b and definitely shouldn't revert b
+
+  $ hg split << EOF
+  > f
+  > d
+  > y
+  > f
+  > d
+  > d
+  > EOF
+  0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  adding a
+  adding b
+  adding c
+  diff --git a/a b/a
+  new file mode 100644
+  examine changes to 'a'?
+  (enter ? for help) [Ynesfdaq?] f
+  
+  diff --git a/b b/b
+  new file mode 100644
+  examine changes to 'b'?
+  (enter ? for help) [Ynesfdaq?] d
+  
+  created new head
+  (consider using topic for lightweight branches. See 'hg help topic')
+  continue splitting? [Ycdq?] y
+  diff --git a/b b/b
+  new file mode 100644
+  examine changes to 'b'?
+  (enter ? for help) [Ynesfdaq?] f
+  
+  diff --git a/c b/c
+  new file mode 100644
+  examine changes to 'c'?
+  (enter ? for help) [Ynesfdaq?] d
+  
+  continue splitting? [Ycdq?] d
+  discarding remaining changes
+  forgetting c
+
+  $ hg glog -p
+  @  2:c2c6f4d8c766 split2 (draft)
+  |  diff --git a/b b/b
+  |  new file mode 100644
+  |  --- /dev/null
+  |  +++ b/b
+  |  @@ -0,0 +1,1 @@
+  |  +b
+  |
+  o  1:fb91c6249a20 split1 (draft)
+     diff --git a/a b/a
+     new file mode 100644
+     --- /dev/null
+     +++ b/a
+     @@ -0,0 +1,1 @@
+     +a
+  
+
+  $ cd ..
--- a/tests/test-topic.t	Fri Sep 04 21:33:11 2020 +0200
+++ b/tests/test-topic.t	Tue Sep 08 11:56:17 2020 +0800
@@ -750,12 +750,18 @@
      fran (1 changesets)
   $ hg log -r 'topic(.)'
 (no output is expected)
+
+  $ hg up 8
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo test > gamma
+  $ hg ci -m non-topic
+  $ hg log -r 'topic(.)'
+
   $ hg co fran
   switching to topic fran
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg log -r 'topic(.)'
   changeset:   9:0469d521db49
-  tag:         tip
   topic:       fran
   parent:      3:a53952faf762
   user:        test
@@ -801,19 +807,26 @@
   created new head
   (consider using topic for lightweight branches. See 'hg help topic')
   $ hg log -Gr 'draft()'
-  @  changeset:   10:4073470c35e1
+  @  changeset:   11:4073470c35e1
   |  tag:         tip
+  |  parent:      9:0469d521db49
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
   |  summary:     fran?
   |
-  o  changeset:   9:0469d521db49
-  |  topic:       fran
-  |  parent:      3:a53952faf762
-  |  user:        test
-  |  date:        Thu Jan 01 00:00:00 1970 +0000
-  |  summary:     start on fran
-  |
+  | o  changeset:   10:de75ec1bdbe8
+  | |  parent:      8:ae074045b7a7
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     non-topic
+  | |
+  o |  changeset:   9:0469d521db49
+  | |  topic:       fran
+  | |  parent:      3:a53952faf762
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     start on fran
+  | |
 
   $ hg topics
      fran (1 changesets)
--- a/tests/test-uncommit.t	Fri Sep 04 21:33:11 2020 +0200
+++ b/tests/test-uncommit.t	Tue Sep 08 11:56:17 2020 +0800
@@ -355,6 +355,8 @@
   $ hg cat b --rev 0
   b: no such file in rev 07f494440405
   [1]
+  $ hg status
+  A aa
   $ hg uncommit --rev . b
   abort: cannot uncommit to parent changeset
   [255]
@@ -362,6 +364,9 @@
   $ hg cat b --rev .
   b: no such file in rev 5b27f6b17da2
   [1]
+  $ hg status
+  A aa
+  A b
 
 Test uncommiting predecessors
 
@@ -421,9 +426,9 @@
   R m
   R n
   $ hg status
+  M b
   M d
   A aa
-  R b
   $ hg amend --extract j
   $ hg status --change .
   M o
@@ -438,10 +443,10 @@
   R m
   R n
   $ hg status
+  M b
   M d
   M j
   A aa
-  R b
 
 (with all)
 
@@ -450,6 +455,7 @@
   (use 'hg prune .' to remove it)
   $ hg status --change .
   $ hg status
+  M b
   M d
   M j
   M o
@@ -459,7 +465,6 @@
   A h
   A k
   A l
-  R b
   R c
   R f
   R g
@@ -472,11 +477,10 @@
 
   $ hg amend
   $ hg status
-  ? b
 
   $ hg diff -c . --stat
    aa |  1 +
-   b  |  1 -
+   b  |  1 +
    c  |  1 -
    d  |  1 +
    e  |  1 +
@@ -490,7 +494,7 @@
    m  |  1 -
    n  |  1 -
    o  |  1 +
-   15 files changed, 9 insertions(+), 6 deletions(-)
+   15 files changed, 10 insertions(+), 5 deletions(-)
   $ hg uncommit --revert --all
   new changeset is empty
   (use 'hg prune .' to remove it)