def getrevs(ui, repo, masterstring, **opts): global hiddenchanges hiddenchanges = 0 global commit_info commit_info = opts.get("commit_info") headrevs = opts.get("rev") if headrevs: headspec = revsetlang.formatspec("%lr", headrevs) else: if opts.get("all"): datefilter = "_all()" else: before = ui.config("smartlog", "hide-before") if before: datefilter = revsetlang.formatspec("date(%s)", ">%s" % before) else: # last 2 weeks datefilter = "date(-14)" # Calculate hiddenchanges allheads = repo.revs("heads(draft()) - . - interestingbookmarks()") visibleheads = repo.revs("%ld & %r", allheads, datefilter) hiddenchanges = len(allheads) - len(visibleheads) headspec = revsetlang.formatspec( "interestingbookmarks() + (heads(draft()) & %r) + .", datefilter ) revstring = revsetlang.formatspec( "smartlog(heads=%r, master=%r)", headspec, masterstring ) return set(repo.anyrevs([revstring], user=True))
def getrevs(ui, repo, masterstring, **opts): global commit_info commit_info = opts.get("commit_info") headrevs = opts.get("rev") if headrevs: headspec = revsetlang.formatspec("%lr", headrevs) else: headspec = "interestingbookmarks() + heads(draft()) + ." revstring = revsetlang.formatspec("smartlog(heads=%r, master=%r)", headspec, masterstring) return set(repo.anyrevs([revstring], user=True))
def _cachedgetoldworkingcopyparent(repo, wkpnode): if not util.safehasattr(repo, "_undooldworkingparentcache"): repo._undooldworkingparentcache = {} cache = repo._undooldworkingparentcache key = wkpnode if key not in cache: oldworkingparent = _readnode(repo, "workingparent.i", wkpnode) oldworkingparent = filter(None, oldworkingparent.split("\n")) oldwkprevstring = revsetlang.formatspec("%ls", oldworkingparent) urepo = repo.unfiltered() cache[key] = smartset.baseset(urepo.revs(oldwkprevstring)) return cache[key]
def _localbranch(repo, subset, x): """``_localbranch(changectx)`` localbranch changesets Returns all commits within the same localbranch as the changeset(s). A local branch is all draft changesets that are connected, uninterupted by public changesets. Any draft commit within a branch, or a public commit at the base of the branch, can be used to identify localbranches. """ # executed on an filtered repo args = revset.getargsdict(x, "branchrevset", "changectx") revstring = revsetlang.getstring( args.get("changectx"), _("localbranch argument must be a changectx")) revs = repo.revs(revstring) # we assume that there is only a single rev if repo[revs.first()].phase() == phases.public: querystring = revsetlang.formatspec("(children(%d) & draft())::", revs.first()) else: querystring = revsetlang.formatspec("((::%ld) & draft())::", revs) return subset & smartset.baseset(repo.revs(querystring))
def debugbruterebase(ui, repo, source, dest): """for every non-empty subset of source, run rebase -r subset -d dest Print one line summary for each subset. Assume obsstore is enabled. """ srevs = list(repo.revs(source)) with repo.wlock(), repo.lock(): repolen = len(repo) cl = repo.changelog newrevs = [] def getdesc(rev): result = cl.changelogrevision(rev).description if rev in newrevs: result += "'" return result for i in xrange(1, 2**len(srevs)): subset = [rev for j, rev in enumerate(srevs) if i & (1 << j) != 0] spec = revsetlang.formatspec("%ld", subset) tr = repo.transaction("rebase") tr.report = lambda x: 0 # hide "transaction abort" oldnodes = set(repo.nodes("all()")) ui.pushbuffer() try: rebase.rebase(ui, repo, dest=dest, rev=[spec]) except error.Abort as ex: summary = "ABORT: %s" % ex except Exception as ex: summary = "CRASH: %s" % ex else: # short summary about new nodes cl = repo.changelog descs = [] newnodes = set(repo.nodes("all()")) newrevs = list(map(cl.rev, newnodes - oldnodes)) for rev in sorted(newrevs): desc = "%s:" % getdesc(rev) for prev in cl.parentrevs(rev): if prev > -1: desc += getdesc(prev) descs.append(desc) descs.sort() summary = " ".join(descs) ui.popbuffer() repo.localvfs.tryunlink("rebasestate") subsetdesc = "".join(getdesc(rev) for rev in subset) ui.write(("%s: %s\n") % (subsetdesc.rjust(len(srevs)), summary)) tr.abort()
def oldworkingparenttemplate(context, mapping, args): """String. Workingcopyparent reverseindex repo states ago.""" reverseindex = templater.evalinteger( context, mapping, args[0], _("undonecommits needs an integer argument")) repo = mapping["ctx"]._repo ctx = mapping["ctx"] revstring = revsetlang.formatspec("oldworkingcopyparent(%d)", reverseindex) nodes = list(repo.nodes(revstring)) if ctx.node() in nodes: result = ctx.hex() else: result = None return result
def _cachedgetolddrafts(repo, nodedict): if not util.safehasattr(repo, "_undoolddraftcache"): repo._undoolddraftcache = {} cache = repo._undoolddraftcache if repo.ui.configbool("experimental", "narrow-heads"): headnode = key = nodedict["visibleheads"] if key not in cache: oldheads = _readnode(repo, "visibleheads.i", headnode).split("\n") cache[key] = repo.revs("(not public()) & ::%ls", oldheads) else: draftnode = nodedict["draftheads"] obsnode = nodedict["draftobsolete"] key = draftnode + obsnode if key not in cache: olddraftheads = _readnode(repo, "draftheads.i", draftnode) oldheadslist = olddraftheads.split("\n") oldobs = _readnode(repo, "draftobsolete.i", obsnode) oldobslist = filter(None, oldobs.split("\n")) oldlogrevstring = revsetlang.formatspec( "(draft() & ancestors(%ls)) - %ls", oldheadslist, oldobslist) urepo = repo.unfiltered() cache[key] = smartset.baseset(urepo.revs(oldlogrevstring)) return cache[key]
def _donehexnodes(repo, reverseindex): repo = repo.unfiltered() revstring = revsetlang.formatspec("olddraft(%d)", reverseindex) revs = repo.revs(revstring) tonode = repo.changelog.node return [tonode(x) for x in revs]
def _logdraftobsolete(repo, tr): spec = revsetlang.formatspec("draft() & obsolete()") hexnodes = tohexnode(repo, spec) revstring = "\n".join(sorted(hexnodes)) return writelog(repo, tr, "draftobsolete.i", revstring)
def _preview(ui, repo, reverseindex): # Print smartlog like preview of undo # Input: # ui: # repo: mercurial.localrepo # Output: # returns 1 on index error, 0 otherwise # override "UNDOINDEX" as a variable usable in template if not _gapcheck(ui, repo, reverseindex): repo.ui.status( _("WARN: missing history between present and this" " state\n")) overrides = {("templates", "UNDOINDEX"): str(reverseindex)} opts = {} opts["template"] = "{undopreview}" repo = repo.unfiltered() try: nodedict = _readindex(repo, reverseindex) curdict = _readindex(repo, reverseindex) except IndexError: return 1 bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"]) oldmarks = bookstring.split("\n") oldpairs = set() for mark in oldmarks: kv = mark.rsplit(" ", 1) if len(kv) == 2: oldpairs.update(kv) bookstring = _readnode(repo, "bookmarks.i", curdict["bookmarks"]) curmarks = bookstring.split("\n") curpairs = set() for mark in curmarks: kv = mark.rsplit(" ", 1) if len(kv) == 2: curpairs.update(kv) diffpairs = oldpairs.symmetric_difference(curpairs) # extract hashes from diffpairs bookdiffs = [] for kv in diffpairs: bookdiffs += kv[0] revstring = revsetlang.formatspec( "ancestor(olddraft(0), olddraft(%s)) +" "(draft() & ::((olddraft(0) - olddraft(%s)) + " "(olddraft(%s) - olddraft(0)) + %ls + '.' + " "oldworkingcopyparent(%s)))", reverseindex, reverseindex, reverseindex, bookdiffs, reverseindex, ) opts["rev"] = [revstring] try: with ui.configoverride(overrides): cmdutil.graphlog(ui, repo, None, opts) # informative output nodedict = _readindex(repo, reverseindex) time = _readnode(repo, "date.i", nodedict["date"]) time = util.datestr([float(x) for x in time.split(" ")]) except IndexError: # don't print anything return 1 try: nodedict = _readindex(repo, reverseindex - 1) commandstr = _readnode(repo, "command.i", nodedict["command"]) commandlist = commandstr.split("\0")[1:] commandstr = " ".join(commandlist) uimessage = _("undo to %s, before %s\n") % (time, commandstr) repo.ui.status((uimessage)) except IndexError: repo.ui.status( _("most recent state: undoing here won't change" " anything\n")) return 0
def _findnextdelta(repo, reverseindex, branch, direction): # finds closest repos state making changes to branch in direction # input: # repo: mercurial.localrepo # reverseindex: positive int for index.i # branch: string changectx (commit hash) # direction: positive or negative int # output: # int index with next branch delta # this is the first repo state that makes a changectx, bookmark or working # copy parent change that effects the given branch if 0 == direction: # no infinite cycles guarantee raise error.ProgrammingError repo = repo.unfiltered() # current state try: nodedict = _readindex(repo, reverseindex) except IndexError: raise error.Abort(_("index out of bounds")) alphaworkingcopyparent = _readnode(repo, "workingparent.i", nodedict["workingparent"]) alphabookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"]) incrementalindex = reverseindex spec = revsetlang.formatspec("_localbranch(%s)", branch) hexnodes = tohexnode(repo, spec) done = False while not done: # move index incrementalindex += direction # check this index try: nodedict = _readindex(repo, incrementalindex) except IndexError: raise error.Abort(_("index out of bounds")) # skip interupted commands if "True" == nodedict["unfinished"]: break # check wkp, commits, bookmarks workingcopyparent = _readnode(repo, "workingparent.i", nodedict["workingparent"]) bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"]) # local changes in respect to visible changectxs # disjunctive union of present and old = changes # intersection of changes and local = localchanges localctxchanges = revsetlang.formatspec( "((olddraft(%d) + olddraft(%d)) -" "(olddraft(%d) and olddraft(%d)))" " and _localbranch(%s)", incrementalindex, reverseindex, incrementalindex, reverseindex, branch, ) done = done or repo.revs(localctxchanges) if done: # perf boost break # bookmark changes if alphabookstring != bookstring: diff = set(alphabookstring.split("\n")) ^ set( bookstring.split("\n")) for mark in diff: if mark: kv = mark.rsplit(" ", 1) # was or will the mark be in the localbranch if kv[1] in hexnodes: done = True break # working copy parent changes # for workingcopyparent, only changes within the scope are interesting if alphaworkingcopyparent != workingcopyparent: done = done or (workingcopyparent in hexnodes and alphaworkingcopyparent in hexnodes) return incrementalindex
def _computerelative(repo, reverseindex, absolute=False, branch=""): # allows for relative undos using # redonode storage # allows for branch undos using # findnextdelta logic if reverseindex != 0: sign = reverseindex / abs(reverseindex) else: sign = None if not absolute: try: # attempt to get relative shift nodebranch = repo.localvfs.read("undolog/redonode").split("\0") hexnode = nodebranch[0] try: oldbranch = nodebranch[1] except IndexError: oldbranch = "" rlog = _getrevlog(repo, "index.i") rev = rlog.rev(bin(hexnode)) shiftedindex = _invertindex(rlog, rev) except (IOError, error.RevlogError): # no shift shiftedindex = 0 oldbranch = "" else: shiftedindex = 0 oldbranch = "" if not branch: if not oldbranch: reverseindex = shiftedindex + reverseindex # else: previous command was branch undo # perform absolute undo (no shift) else: # check if relative branch if (branch != oldbranch) and (oldbranch != ""): rootdelta = revsetlang.formatspec( "roots(_localbranch(%s)) - roots(_localbranch(%s))", branch, oldbranch) if repo.revs(rootdelta): # different group of commits shiftedindex = 0 # from shifted index, find reverse index # of states that change # branch # remember that reverseindex can be negative sign = reverseindex / abs(reverseindex) for count in range(abs(reverseindex)): shiftedindex = _findnextdelta(repo, shiftedindex, branch, direction=sign) reverseindex = shiftedindex # skip interupted commands if sign: done = False rlog = _getrevlog(repo, "index.i") while not done: indexdict = _readindex(repo, reverseindex, rlog) if "True" == indexdict["unfinished"]: reverseindex += sign else: done = True return reverseindex
def _undoto(ui, repo, reverseindex, keep=False, branch=None): # undo to specific reverseindex # branch is a changectx hash (potentially short form) # which identifies its branch via localbranch revset if branch and repo.ui.configbool("experimental", "narrow-heads"): raise error.Abort( _("'undo --branch' is no longer supported in the current setup")) if repo != repo.unfiltered(): raise error.ProgrammingError(_("_undoto expects unfilterd repo")) try: nodedict = _readindex(repo, reverseindex) except IndexError: raise error.Abort(_("index out of bounds")) # bookmarks bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"]) booklist = bookstring.split("\n") if branch: spec = revsetlang.formatspec("_localbranch(%s)", branch) branchcommits = tohexnode(repo, spec) else: branchcommits = False # copy implementation for bookmarks itercopy = [] for mark in pycompat.iteritems(repo._bookmarks): itercopy.append(mark) bmremove = [] for mark in itercopy: if not branchcommits or hex(mark[1]) in branchcommits: bmremove.append((mark[0], None)) repo._bookmarks.applychanges(repo, repo.currenttransaction(), bmremove) bmchanges = [] for mark in booklist: if mark: kv = mark.rsplit(" ", 1) if not branchcommits or kv[1] in branchcommits or ( kv[0], None) in bmremove: bmchanges.append((kv[0], bin(kv[1]))) repo._bookmarks.applychanges(repo, repo.currenttransaction(), bmchanges) # working copy parent workingcopyparent = _readnode(repo, "workingparent.i", nodedict["workingparent"]) if not keep: if not branchcommits or workingcopyparent in branchcommits: # bailifchanged is run, so this should be safe hg.clean(repo, workingcopyparent, show_stats=False) elif not branchcommits or workingcopyparent in branchcommits: # keeps working copy files prednode = bin(workingcopyparent) predctx = repo[prednode] changedfiles = [] wctx = repo[None] wctxmanifest = wctx.manifest() predctxmanifest = predctx.manifest() dirstate = repo.dirstate diff = predctxmanifest.diff(wctxmanifest) changedfiles.extend(pycompat.iterkeys(diff)) with dirstate.parentchange(): dirstate.rebuild(prednode, predctxmanifest, changedfiles) # we want added and removed files to be shown # properly, not with ? and ! prefixes for filename, data in pycompat.iteritems(diff): if data[0][0] is None: dirstate.add(filename) if data[1][0] is None: dirstate.remove(filename) # visible changesets addedrevs = revsetlang.formatspec("olddraft(0) - olddraft(%d)", reverseindex) removedrevs = revsetlang.formatspec("olddraft(%d) - olddraft(0)", reverseindex) if not branch: if repo.ui.configbool("experimental", "narrow-heads"): # Assuming mutation and visibility are used. Restore visibility heads # directly. _restoreheads(repo, reverseindex) else: # Legacy path. smarthide(repo, addedrevs, removedrevs) revealcommits(repo, removedrevs) else: localadds = revsetlang.formatspec( "(olddraft(0) - olddraft(%d)) and" " _localbranch(%s)", reverseindex, branch) localremoves = revsetlang.formatspec( "(olddraft(%d) - olddraft(0)) and" " _localbranch(%s)", reverseindex, branch) smarthide(repo, localadds, removedrevs) smarthide(repo, addedrevs, localremoves, local=True) revealcommits(repo, localremoves) # informative output time = _readnode(repo, "date.i", nodedict["date"]) time = util.datestr([float(x) for x in time.split(" ")]) nodedict = _readindex(repo, reverseindex - 1) commandstr = _readnode(repo, "command.i", nodedict["command"]) commandlist = commandstr.split("\0")[1:] commandstr = " ".join(commandlist) uimessage = _("undone to %s, before %s\n") % (time, commandstr) if reverseindex == 1 and commandlist[0] in ("commit", "amend"): command = commandlist[0] if command == "commit" and "--amend" in commandlist: command = "amend" oldcommithash = _readnode(repo, "workingparent.i", nodedict["workingparent"]) shorthash = short(bin(oldcommithash)) hintutil.trigger("undo-uncommit-unamend", command, shorthash) repo.ui.status((uimessage))
def _donehexnodes(repo, reverseindex): repo = repo.unfiltered() revstring = revsetlang.formatspec("olddraft(%d)", reverseindex) return list(repo.nodes(revstring))
def _undonehexnodes(repo, reverseindex): revstring = revsetlang.formatspec("olddraft(0) - olddraft(%d)", reverseindex) return list(repo.nodes(revstring))
def _smartlogrevset(orig, repo, subset, x): revs = orig(repo, subset, x) snapshotstring = revsetlang.formatspec("snapshot()") return smartset.addset( revs, repo.unfiltered().anyrevs([snapshotstring], user=True))
def _getscratchbranchpartsimpl( repo, peer, outgoing, confignonforwardmove, ui, bookmark, create, bookmarknode=None ): _validaterevset(repo, revsetlang.formatspec("%ln", outgoing.missing), bookmark) supportedversions = changegroup.supportedoutgoingversions(repo) # Explicitly avoid using '01' changegroup version in infinitepush to # support general delta supportedversions.discard("01") cgversion = min(supportedversions) _handlelfs(repo, outgoing.missing) cg = changegroup.makestream(repo, outgoing, cgversion, "push") params = {} params["cgversion"] = cgversion if bookmark: params["bookmark"] = bookmark if bookmarknode: params["bookmarknode"] = bookmarknode if create: params["create"] = "1" if confignonforwardmove: params["force"] = "1" parts = [] # .upper() marks this as a mandatory part: server will abort if there's no # handler parts.append( bundle2.bundlepart( constants.scratchbranchparttype.upper(), advisoryparams=pycompat.iteritems(params), data=cg, ) ) if mutation.enabled(repo): entries = mutation.entriesforbundle(repo, outgoing.missing) if entries: if constants.scratchmutationparttype not in bundle2.bundle2caps(peer): repo.ui.warn( _("no server support for %r - skipping\n") % constants.scratchmutationparttype ) else: parts.append( bundle2.bundlepart( constants.scratchmutationparttype, data=mutation.bundleentries(entries), ) ) try: treemod = extensions.find("treemanifest") remotefilelog = extensions.find("remotefilelog") sendtrees = remotefilelog.shallowbundle.cansendtrees(repo, outgoing.missing) if sendtrees != remotefilelog.shallowbundle.NoTrees: parts.append( treemod.createtreepackpart( repo, outgoing, treemod.TREEGROUP_PARTTYPE2, sendtrees=sendtrees ) ) except KeyError: pass try: snapshot = extensions.find("snapshot") except KeyError: pass else: snapshot.bundleparts.appendsnapshotmetadatabundlepart( repo, outgoing.missing, parts ) return parts
def _logdraftheads(repo, tr): spec = revsetlang.formatspec("heads(draft())") hexnodes = tohexnode(repo, spec) revstring = "\n".join(sorted(hexnodes)) return writelog(repo, tr, "draftheads.i", revstring)