# HG changeset patch # User Sushil khanchi # Date 1626723486 -19800 # Tue Jul 20 01:08:06 2021 +0530 # Node ID 15be32f8c8f7672ce8e766a2cfa986f0c901857e # Parent 3a3341e44a0e9a3234d4403c41b5ff493e099b09 # EXP-Topic fix-s0-amend-issue topic: document topic("name")#s[N] revset diff --git a/hgext3rd/topic/__init__.py b/hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py +++ b/hgext3rd/topic/__init__.py @@ -775,6 +775,14 @@ hg topics + Revset for a revision with a specific topic and position in stack:: + + topic("")#stack[N] + + or + + topic("")#s[N] + List of topics sorted according to their last touched time displaying last touched time and the user who last touched the topic:: @@ -902,6 +910,14 @@ List the current topic by default. + Revset for a revision with a specific topic and position in stack:: + + topic("")#stack[N] + + or + + topic("")#s[N] + The --verbose version shows short nodes for the commits also. """ if not topic: diff --git a/tests/test-topic.t b/tests/test-topic.t --- a/tests/test-topic.t +++ b/tests/test-topic.t @@ -197,6 +197,14 @@ hg topics + Revset for a revision with a specific topic and position in stack: + + topic("")#stack[N] + + or + + topic("")#s[N] + List of topics sorted according to their last touched time displaying last touched time and the user who last touched the topic: # HG changeset patch # User Sushil khanchi # Date 1611512742 -19800 # Sun Jan 24 23:55:42 2021 +0530 # Node ID b6aab5fcb6d494b40f7baa1ec08808c1f7231a6c # Parent 15be32f8c8f7672ce8e766a2cfa986f0c901857e # EXP-Topic fix-s0-amend-issue tests: add test to show an issue with amending on s0 If we check out to s0 (base of a topic stack) using `hg prev` it will preserve the topic from previous working copy parent. Now, amending some changes on s0 also change the topic. Note that we can't make `hg amend` to abort in every case whenever there is any active topic (which seems the way to solve this problem but it's not) because the same applies to branches. But in case of branches there is no such problem of s0, so we need to recognise that case precisely and abort. This patch also removes some *now* unnecessary occurences of `--config extensions.evolve=` from test file as we have fully enabled the evolve extension. Next patch will be fixing this. diff --git a/tests/test-topic-stack.t b/tests/test-topic-stack.t --- a/tests/test-topic-stack.t +++ b/tests/test-topic-stack.t @@ -6,8 +6,8 @@ $ cat << EOF >> $HGRCPATH > [ui] > logtemplate = {rev} {branch} \{{get(namespaces, "topics")}} {phase} {desc|firstline}\n - > [experimental] - > evolution=all + > [extensions] + > evolve= > EOF $ hg init main @@ -937,7 +937,7 @@ s2@ c_G (current) s1: c_D s0^ c_A (base) - $ hg --config extensions.evolve= --config ui.interactive=yes split << EOF + $ hg --config ui.interactive=yes split << EOF > y > y > n @@ -977,7 +977,7 @@ 3bfe800e04863d23f909f8d98848656b7b5a971a 662ff4ad29901b325a64c39f7850e3efaaeeccc5 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '4', 'operation': 'rebase', 'user': 'test'} 907f7d3c2333082d62942ac3a47e466ce03d82b9 b24bab30ac12f6124a52e74aaf46b7468e42526c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'} b24bab30ac12f6124a52e74aaf46b7468e42526c dde94df880e97f4a1ee8c5408254b429b3d90204 e7ea874afbd5c17aeee366d39a828dbcb01682ce 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '12', 'operation': 'split', 'user': 'test'} - $ hg --config extensions.evolve= obslog --all + $ hg obslog --all o dde94df880e9 (21) c_G | split(parent, content) from b24bab30ac12 using split by test (Thu Jan 01 00:00:00 1970 +0000) | @@ -1036,3 +1036,77 @@ s2: c_G s1: c_D s0^ c_A (base) + +case amending on s0 +------------------- + + $ hg init amend-s0 + $ cd amend-s0 + $ echo 1 > root + $ hg add root + $ hg commit -m root + $ echo a > a + $ hg add a + $ hg commit -m c_a + $ hg topic feature + marked working directory as topic: feature + $ echo b > b + $ hg add b + $ hg commit -m c_b + active topic 'feature' grew its first changeset + (see 'hg help topics' for more information) + + $ hg prev + preserving the current topic 'feature' + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [1] c_a + $ echo aa > a + + $ hg stack + ### topic: feature + ### target: default (branch) + s1: c_b + s0^ c_a (base current) + + $ hg amend + 1 new orphan changesets + +The amend should be blocked + + $ hg log --graph + @ 3 default {feature} draft c_a + | + | * 2 default {feature} draft c_b + | | + | x 1 default {} draft c_a + |/ + o 0 default {} draft root + + +And the stack should stay the same size + + $ hg stack + ### topic: feature + ### target: default (branch), 1 behind + s2$ c_b (orphan) + s1@ c_a (current) + s0^ root (base) + +Check we can still change topic and amend a changeset that happend to be the s0 of something else + + $ hg up . + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ echo aa >> a + + $ hg amend + + $ hg log --graph + @ 4 default {feature} draft c_a + | + | * 2 default {feature} draft c_b + | | + | x 1 default {} draft c_a + |/ + o 0 default {} draft root + # HG changeset patch # User Sushil khanchi # Date 1628234104 -19800 # Fri Aug 06 12:45:04 2021 +0530 # Node ID 25fe9e40f69f9de51338c70b5d47b19372a279e8 # Parent b6aab5fcb6d494b40f7baa1ec08808c1f7231a6c # EXP-Topic fix-s0-amend-issue amend: abort if amending s0 with a different topic This patch fixes issue of silently changing topic when amending on s0 (base of a topic stack) by aborting in that case. We suggest to run `hg update .`, which will checkout the topic of 's0' if it has one, otherwise clear the current topic. Changes in test file reflect the added behavior. diff --git a/hgext3rd/evolve/cmdrewrite.py b/hgext3rd/evolve/cmdrewrite.py --- a/hgext3rd/evolve/cmdrewrite.py +++ b/hgext3rd/evolve/cmdrewrite.py @@ -125,10 +125,12 @@ if opts.get('patch') and opts.get('extract'): raise error.Abort(_(b'cannot use both --patch and --extract')) if opts.get('patch'): + precheck_s0_amendment(repo) return amendpatch(ui, repo, *pats, **opts) if opts.get('extract'): return uncommit(ui, repo, *pats, **opts) else: + precheck_s0_amendment(repo) if opts.pop('all', False): # add an include for all include = list(opts.get('include')) @@ -144,6 +146,23 @@ rewriteutil.precheck(repo, [repo[b'.'].rev()], action=b'amend') return commitcmd[0](ui, repo, *pats, **opts) +def precheck_s0_amendment(repo): + wdp = repo[b'.'] + if not util.safehasattr(wdp, 'topic'): + return + activetopic = getattr(repo, 'currenttopic', b'') + if not activetopic: + return + childtopics = [ctx.topic() for ctx in wdp.children() if ctx.topic()] + if activetopic in childtopics and activetopic != wdp.topic(): + # amending on s0 + hint = _( + b"run 'hg update .' to checkout topic of 's0', if any\n" + b"Learn about 's#' changeset reference aliases in current" + b" stack from `hg help -e topic`") + raise error.Abort(_(b"amend would change the topic of 's0'"), + hint=hint) + def amendpatch(ui, repo, *pats, **opts): """logic for --patch flag of `hg amend` command.""" with repo.wlock(), repo.lock(), repo.transaction(b'amend') as tr: diff --git a/tests/test-topic-stack.t b/tests/test-topic-stack.t --- a/tests/test-topic-stack.t +++ b/tests/test-topic-stack.t @@ -1069,17 +1069,18 @@ s0^ c_a (base current) $ hg amend - 1 new orphan changesets + abort: amend would change the topic of 's0' + (run 'hg update .' to checkout topic of 's0', if any + Learn about 's#' changeset reference aliases in current stack from `hg help -e topic`) + [255] The amend should be blocked $ hg log --graph - @ 3 default {feature} draft c_a + o 2 default {feature} draft c_b | - | * 2 default {feature} draft c_b - | | - | x 1 default {} draft c_a - |/ + @ 1 default {} draft c_a + | o 0 default {} draft root @@ -1087,10 +1088,9 @@ $ hg stack ### topic: feature - ### target: default (branch), 1 behind - s2$ c_b (orphan) - s1@ c_a (current) - s0^ root (base) + ### target: default (branch) + s1: c_b + s0^ c_a (base current) Check we can still change topic and amend a changeset that happend to be the s0 of something else @@ -1100,9 +1100,10 @@ $ echo aa >> a $ hg amend + 1 new orphan changesets $ hg log --graph - @ 4 default {feature} draft c_a + @ 3 default {} draft c_a | | * 2 default {feature} draft c_b | |