diff --git a/hgext3rd/undo.py b/hgext3rd/undo.py --- a/hgext3rd/undo.py +++ b/hgext3rd/undo.py @@ -57,7 +57,9 @@ # Check wether undolog is consistent # ie check wether the undo ext was # off before this command - safelog(repo, [""]) + changes = safelog(repo, [""]) + if changes: + _recordnewgap(repo) result = orig(lui, repo, cmd, fullargs, *args) @@ -73,6 +75,10 @@ with repo.lock(): with lighttransaction(repo): changes = log(repo.filtered('visible'), command) + # allow for relative undos: + if changes and not ("undo" == command[0] or "redo" == + command[0]): + _delundoredo(repo) return changes def lighttransaction(repo): @@ -155,6 +161,14 @@ path = os.path.join('undolog', 'redo.i') repo.svfs.tryunlink(path) +def _recordnewgap(repo, absoluteindex=None): + path = os.path.join('undolog', 'gap') + if absoluteindex is None: + rlog = _getrevlog(repo, 'index.i') + repo.svfs.write(path, str(len(rlog) - 1)) + else: + repo.svfs.write(path, str(absoluteindex)) + # Read def _readindex(repo, reverseindex, prefetchedrevlog=None): @@ -177,6 +191,29 @@ rlog = _getrevlog(repo, filename) return rlog.revision(bin(hexnode)) +def _gapcheck(repo, reverseindex): + rlog = _getrevlog(repo, 'index.i') + absoluteindex = _invertindex(rlog, reverseindex) + path = os.path.join('undolog', "gap") + try: + result = absoluteindex >= int(repo.svfs.read(path)) + except IOError: + # recreate file + repo.ui.debug("failed to read gap file in %s, attempting recreation\n" + % path) + rlog = _getrevlog(repo, 'index.i') + i = 0 + while i < (len(rlog)): + indexdict = _readindex(repo, i, rlog) + if "" == _readnode(repo, "command.i", indexdict["command"]): + break + i += 1 + # defaults to before oldest command + _recordnewgap(repo, _invertindex(rlog, i)) + result = absoluteindex >= _invertindex(rlog, i) + finally: + return result + # Visualize """debug commands and instrumentation for the undo extension @@ -298,6 +335,7 @@ @command('undo', [ ('n', 'index', 1, _("how many steps to undo back")), + ('f', 'force', False, _("undo across a gap in memory (ADVANCED)")), ('a', 'absolute', False, _("absolute based on command index instead of " "relative undo")), ]) @@ -332,6 +370,14 @@ Undo states are also distinct repo states and can thereby be inspected using debugundohistory and specifically jumped to using undo --index --absolute. + + If you run a command with the extension on, and the recorded undo-data does + not match the pre-command state, a blank command is recorded before your new + command is run. This can happen when you first start the extension, turn + the extension off and on again, corrupt/edit/delete the storage files or the + repo or another command breaks something. Undoing across this "gap" can be + forced, but isn't advised unless its known how the before and after states + are connected. Undoing up to a gap is safe. """ reverseindex = opts.get("index") relativeundo = not opts.get("absolute") @@ -343,6 +389,9 @@ repo = repo.unfiltered() if relativeundo: reverseindex = _computerelative(repo, reverseindex) + if not (opts.get("force") or _gapcheck(repo, reverseindex)): + raise error.Abort(_("attempted risky undo across" + " missing history")) _undoto(ui, repo, reverseindex) # store undo data # for absolute undos, think of this as a reset diff --git a/tests/test-undo.t b/tests/test-undo.t --- a/tests/test-undo.t +++ b/tests/test-undo.t @@ -186,78 +186,93 @@ $ hg update 0a3dd3e15e65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg undo - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log -G -T compact | head -1 - @ 8[tip][master]:4 0a3dd3e15e65 1970-01-01 00:00 +0000 test + @ 9[tip][master] 1dafc0b43612 1970-01-01 00:00 +0000 test $ touch c11 && hg add c11 $ hg commit --amend $ hg log -G -T compact | head -1 - @ 12[tip][master]:4 55c537d18276 1970-01-01 00:00 +0000 test + @ 12[tip][master]:8 2dca609174c2 1970-01-01 00:00 +0000 test $ hg undo - 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg log -G -T compact | head -10 - o 7[tip][feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test + @ 9[tip][master] 1dafc0b43612 1970-01-01 00:00 +0000 test + | cmiss + | + o 8:4 0a3dd3e15e65 1970-01-01 00:00 +0000 test + | words + | + | o 7[feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test + |/ d + | + o 4 38d85b506754 1970-01-01 00:00 +0000 test + $ hg graft 296fda51a303 + grafting 7:296fda51a303 "d" (feature2) + $ hg log -G -T compact | head -4 + @ 13[tip]:9 f007a7cf4c3d 1970-01-01 00:00 +0000 test | d | - @ 4[master] 38d85b506754 1970-01-01 00:00 +0000 test - | c2 - | - o 3:1 ec7553f7b382 1970-01-01 00:00 +0000 test - | c1 - | - | o 2[feature1] 49cdb4091aca 1970-01-01 00:00 +0000 test - $ hg graft 296fda51a303 - grafting 7:296fda51a303 "d" (tip feature2) - $ hg log -G -T compact | head -4 - @ 13[tip]:4 3d8a976116c0 1970-01-01 00:00 +0000 test - | d - | - | o 7[feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test + o 9[master] 1dafc0b43612 1970-01-01 00:00 +0000 test + $ hg undo + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ hg log -G -T compact | head -1 + @ 9[tip][master] 1dafc0b43612 1970-01-01 00:00 +0000 test + $ hg book test + $ hg undo + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg bookmarks + feature1 2:49cdb4091aca + feature2 7:296fda51a303 + master 9:1dafc0b43612 + +hg redo test + $ hg redo + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg log -G -T compact | head -1 + @ 9[tip][master,test] 1dafc0b43612 1970-01-01 00:00 +0000 test $ hg undo 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log -G -T compact | head -1 - @ 7[tip][feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test - $ hg book test - $ hg undo - 0 files updated, 0 files merged, 1 files removed, 0 files unresolved - $ hg bookmarks - feature1 2:49cdb4091aca - feature2 5:db92053d5c83 - master 4:38d85b506754 - -hg redo test - $ hg redo - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + @ 9[tip][master] 1dafc0b43612 1970-01-01 00:00 +0000 test + $ hg undo -n 5 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg redo -n 5 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log -G -T compact | head -1 - @ 7[tip][feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test - $ hg undo - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved - $ hg log -G -T compact | head -1 - @ 4[tip][feature2,master] 38d85b506754 1970-01-01 00:00 +0000 test - $ hg undo -n 5 - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved - $ hg redo -n 5 - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg log -G -T compact | head -1 - @ 4[tip][feature2,master] 38d85b506754 1970-01-01 00:00 +0000 test + @ 9[tip][master,test] 1dafc0b43612 1970-01-01 00:00 +0000 test $ hg redo -n 100 abort: index out of bounds [255] hg undo --absolute tests $ hg undo -a - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg redo - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg undo -a - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg redo - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg undo -n 5 - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log -G -T compact | head -1 - @ 7[tip][feature2]:4 296fda51a303 1970-01-01 00:00 +0000 test + @ 9[tip][master] 1dafc0b43612 1970-01-01 00:00 +0000 test $ hg undo -a - 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log -G -T compact | head -1 - @ 4[tip][feature2,master] 38d85b506754 1970-01-01 00:00 +0000 test + @ 9[tip][master,test] 1dafc0b43612 1970-01-01 00:00 +0000 test + +hg undo --force tests + $ hg debugundohistory -l 13 + 13: undo + 14: commit --amend + 15: undo + 16: update 0a3dd3e15e65 + 17: undo + $ hg undo -a -n 20 + abort: attempted risky undo across missing history + [255] + $ hg undo -a -n 20 -f + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg undo -a + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved