# HG changeset patch # User Anton Shestakov # Date 1599537377 -28800 # Node ID 5a70669beaa3f5a97029a2e3e6be509c9df63fd6 # Parent af835b32e15523c52939aaa74428cb3578184573# Parent 3e23bedf8d384eaf5ce65588ff2591f2f6e95d4e branching: merge with stable diff -r af835b32e155 -r 5a70669beaa3 .hgtags --- 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 diff -r af835b32e155 -r 5a70669beaa3 CHANGELOG --- 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 -------------------- diff -r af835b32e155 -r 5a70669beaa3 debian/changelog --- 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 Tue, 08 Sep 2020 11:18:54 +0800 + mercurial-evolve (10.0.1-1) unstable; urgency=medium * new upstream release diff -r af835b32e155 -r 5a70669beaa3 hgext3rd/evolve/cmdrewrite.py --- 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() diff -r af835b32e155 -r 5a70669beaa3 hgext3rd/evolve/evolvecmd.py --- 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""" diff -r af835b32e155 -r 5a70669beaa3 hgext3rd/evolve/metadata.py diff -r af835b32e155 -r 5a70669beaa3 hgext3rd/topic/__init__.py diff -r af835b32e155 -r 5a70669beaa3 hgext3rd/topic/revset.py --- 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 diff -r af835b32e155 -r 5a70669beaa3 tests/test-split.t --- 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 .. diff -r af835b32e155 -r 5a70669beaa3 tests/test-topic.t --- 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) diff -r af835b32e155 -r 5a70669beaa3 tests/test-uncommit.t --- 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)