# HG changeset patch # User Pierre-Yves David # Date 1392254330 28800 # Node ID 5af3098650405e474ea4d0a7853bb476c2de87b0 # Parent 0d2bb0282e780c1e8c5f83ec1d52c812816039b7 drophack: add a new drop hack extension for Matt Mackall usage This extension is hacky and not intended for real world usage. See documentation for details. diff -r 0d2bb0282e78 -r 5af309865040 hgext/drophack.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/drophack.py Wed Feb 12 17:18:50 2014 -0800 @@ -0,0 +1,163 @@ +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +'''This extension add a hacky command to drop changeset during review + +This extension is intended as a temporary hack to allow Matt Mackall to use +evolve in the Mercurial review it self. You should probably not use it if your +name is not Matt Mackall. +''' + +import os +import time +import contextlib + +from mercurial.i18n import _ +from mercurial import cmdutil +from mercurial import repair +from mercurial import scmutil +from mercurial import lock as lockmod +from mercurial import util +from mercurial import commands + +cmdtable = {} +command = cmdutil.command(cmdtable) + + +@contextlib.contextmanager +def timed(ui, caption): + ostart = os.times() + cstart = time.time() + yield + cstop = time.time() + ostop = os.times() + wall = cstop - cstart + user = ostop[0] - ostart[0] + sys = ostop[1] - ostart[1] + comb = user + sys + ui.write("%s: wall %f comb %f user %f sys %f\n" + % (caption, wall, comb, user, sys)) + +def obsmarkerchainfrom(obsstore, nodes): + """return all marker chain starting from node + + Starting from mean "use as successors".""" + # XXX need something smarter for descendant of bumped changeset + seennodes = set(nodes) + seenmarkers = set() + pendingnodes = set(nodes) + precursorsmarkers = obsstore.precursors + while pendingnodes: + current = pendingnodes.pop() + new = set() + for precmark in precursorsmarkers.get(current, ()): + if precmark in seenmarkers: + continue + seenmarkers.add(precmark) + new.add(precmark[0]) + yield precmark + new -= seennodes + pendingnodes |= new + +def stripmarker(ui, repo, markers): + """remove from the repo obsstore + + The old obsstore content is saved in a `obsstore.prestrip` file + """ + repo = repo.unfiltered() + repo.destroying() + oldmarkers = list(repo.obsstore._all) + util.rename(repo.sjoin('obsstore'), + repo.join('obsstore.prestrip')) + del repo.obsstore # drop the cache + newstore = repo.obsstore + assert not newstore # should be empty after rename + tr = repo.transaction('drophack') + try: + for m in oldmarkers: + if m not in markers: + newstore.add(tr, [m]) + tr.close() + finally: + tr.release() + repo.destroyed() + + +@command('drop', [('r', 'rev', [], 'revision to update')], _('[-r] revs')) +def cmddrop(ui, repo, *revs, **opts): + """I'm hacky do not use me! + + This command strip a changeset, its precursors and all obsolescence marker + associated to its chain. + + There is no way to limit the extend of the purge yet. You may have to + repull from other source to get some changeset and obsolescence marker + back. + + This intended for Matt Mackall usage only. do not use me. + """ + revs = list(revs) + revs.extend(opts['rev']) + if not revs: + revs = ['.'] + # get the changeset + revs = scmutil.revrange(repo, revs) + if not revs: + ui.write_err('no revision to drop\n') + return 1 + # lock from the beginning to prevent race + wlock = lock = None + try: + lock = repo.wlock() + lock = repo.lock() + # check they have no children + if repo.revs('%ld and public()', revs): + ui.write_err('cannot drop public revision') + return 1 + if repo.revs('children(%ld) - %ld', revs, revs): + ui.write_err('cannot drop revision with children') + return 1 + if repo.revs('. and %ld', revs): + newrevs = repo.revs('max(::. - %ld)', revs) + if newrevs: + assert len(newrevs) == 1 + newrev = newrevs[0] + else: + newrev = -1 + commands.update(ui, repo, newrev) + ui.status(_('working directory now at %s\n') % repo[newrev]) + # get all markers and successors up to root + nodes = [repo[r].node() for r in revs] + with timed(ui, 'search obsmarker'): + markers = set(obsmarkerchainfrom(repo.obsstore, nodes)) + ui.write('%i obsmarkers found\n' % len(markers)) + cl = repo.unfiltered().changelog + with timed(ui, 'search nodes'): + allnodes = set(nodes) + allnodes.update(m[0] for m in markers if cl.hasnode(m[0])) + ui.write('%i nodes found\n' % len(allnodes)) + cl = repo.changelog + visiblenodes = set(n for n in allnodes if cl.hasnode(n)) + # check constraint again + if repo.revs('%ln and public()', visiblenodes): + ui.write_err('cannot drop public revision') + return 1 + if repo.revs('children(%ln) - %ln', visiblenodes, visiblenodes): + ui.write_err('cannot drop revision with children') + return 1 + + if markers: + # strip them + with timed(ui, 'strip obsmarker'): + stripmarker(ui, repo, markers) + # strip the changeset + with timed(ui, 'strip nodes'): + repair.strip(ui, repo, allnodes, backup="all", topic='drophack') + + finally: + lockmod.release(lock, wlock) + + # rewrite the whole file. + # print data. + # - time to compute the chain + # - time to strip the changeset + # - time to strip the obs marker. diff -r 0d2bb0282e78 -r 5af309865040 tests/test-drop.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-drop.t Wed Feb 12 17:18:50 2014 -0800 @@ -0,0 +1,267 @@ + + $ cat >> $HGRCPATH < [extensions] + > hgext.rebase= + > hgext.graphlog= + > EOF + $ echo "drophack=$(echo $(dirname $TESTDIR))/hgext/drophack.py" >> $HGRCPATH + $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH + $ mkcommit() { + > echo "$1" > "$1" + > hg add "$1" + > hg ci -m "add $1" + > } + $ summary() { + > echo ============ graph ============== + > hg log -G + > echo ============ hidden ============= + > hg log --hidden -G + > echo ============ obsmark ============ + > hg debugobsolete + > } + + + $ hg init repo + $ cd repo + $ mkcommit base + +drop a single changeset without any rewrite +================================================ + + + $ mkcommit simple-single + $ summary + ============ graph ============== + @ changeset: 1:d4e7845543ff + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add simple-single + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 1:d4e7845543ff + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add simple-single + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + $ hg drop . + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + working directory now at b4952fcf48cf + search obsmarker: wall * comb * user * sys * (glob) + 0 obsmarkers found + search nodes: wall * comb * user * sys * (glob) + 1 nodes found + saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d4e7845543ff-drophack.hg + strip nodes: wall * comb * user * sys * (glob) + $ summary + ============ graph ============== + @ changeset: 0:b4952fcf48cf + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 0:b4952fcf48cf + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + +Try to drop a changeset with children +================================================ + + $ mkcommit parent + $ mkcommit child + $ summary + ============ graph ============== + @ changeset: 2:34b6c051bf1f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 2:34b6c051bf1f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + $ hg drop 1 + cannot drop revision with children (no-eol) + [1] + $ summary + ============ graph ============== + @ changeset: 2:34b6c051bf1f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 2:34b6c051bf1f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + +Try to drop a public changeset +================================================ + + $ hg phase --public 2 + $ hg drop 2 + cannot drop public revision (no-eol) + [1] + + +Try to drop a changeset with rewrite +================================================ + + $ hg phase --force --draft 2 + $ echo babar >> child + $ hg commit --amend + $ summary + ============ graph ============== + @ changeset: 4:a2c06c884bfe + | tag: tip + | parent: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 4:a2c06c884bfe + | tag: tip + | parent: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + | x changeset: 3:87ea30a976fd + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: temporary amend commit for 34b6c051bf1f + | | + | x changeset: 2:34b6c051bf1f + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add child + | + o changeset: 1:19509a42b0d0 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + 34b6c051bf1f78db6aef400776de5cb964470207 a2c06c884bfe53d3840026248bd8a7eafa152df8 0 {'date': '* *', 'user': 'test'} (glob) + 87ea30a976fdf235bf096f04899cb02a903873e2 0 {'date': '* *', 'user': 'test'} (glob) + $ hg drop . + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + working directory now at 19509a42b0d0 + search obsmarker: wall * comb * user * sys * (glob) + 1 obsmarkers found + search nodes: wall * comb * user * sys * (glob) + 2 nodes found + strip obsmarker: wall * comb * user * sys * (glob) + saved backup bundle to $TESTTMP/repo/.hg/strip-backup/a2c06c884bfe-drophack.hg (glob) + strip nodes: wall * comb * user * sys * (glob) + $ summary + ============ graph ============== + @ changeset: 1:19509a42b0d0 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ hidden ============= + @ changeset: 1:19509a42b0d0 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: add parent + | + o changeset: 0:b4952fcf48cf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: add base + + ============ obsmark ============ + 87ea30a976fdf235bf096f04899cb02a903873e2 0 {'date': '* *', 'user': 'test'} (glob)