def metadata(): base = "repo: %s\nnode: %s\nbranch: %s\n" % (hex(repo.changelog.node(0)), hex(node), ctx.branch()) tags = "".join("tag: %s\n" % t for t in ctx.tags() if repo.tagtype(t) == "global") if not tags: repo.ui.pushbuffer() opts = {"template": "{latesttag}\n{latesttagdistance}", "style": "", "patch": None, "git": None} cmdutil.show_changeset(repo.ui, repo, opts).show(ctx) ltags, dist = repo.ui.popbuffer().split("\n") tags = "".join("latesttag: %s\n" % t for t in ltags.split(":")) tags += "latesttagdistance: %s\n" % dist return base + tags
def graphlog(ui, repo, path=None, **opts): """show revision history alongside an ASCII revision graph Print a revision history alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) limit = cmdutil.loglimit(opts) start, stop = get_revs(repo, opts["rev"]) if start == nullrev: return if path: path = util.canonpath(repo.root, os.getcwd(), path) if path: # could be reset in canonpath revdag = graphmod.filerevs(repo, path, start, stop, limit) else: if limit is not None: stop = max(stop, start - limit + 1) revdag = graphmod.revisions(repo, start, stop) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges)
def children(ui, repo, file_=None, **opts): """show the children of the given or working directory revision Print the children of the working directory's revisions. If a revision is given via -r/--rev, the children of that revision will be printed. If a file argument is given, revision in which the file was last changed (after the working directory revision or the argument to --rev if given) is printed. Please use :hg:`log` instead:: hg children => hg log -r 'children()' hg children -r REV => hg log -r 'children(REV)' See :hg:`help log` and :hg:`help revsets.children`. """ rev = opts.get('rev') if file_: fctx = repo.filectx(file_, changeid=rev) childctxs = [fcctx.changectx() for fcctx in fctx.children()] else: ctx = repo[rev] childctxs = ctx.children() displayer = cmdutil.show_changeset(ui, repo, opts) for cctx in childctxs: displayer.show(cctx) displayer.close()
def render_changesets(ui, repo, changesets, config): url = config.commit_url webroot = web_path(repo.root, config) if url: url = url.format(reporoot=repo.root, webroot=webroot, reponame=config.repo_name, rev="{node|short}") node_template = "<{url}|{{node|short}}>".format(url=url) else: node_template = "{node|short}" template = "{0}\\n".format(" | ".join([ "{branch}", node_template, "{date(date, '%Y-%m-%d [%H:%M:%S]')}", "{author|user}", "{desc|strip|firstline}", ])) displayer = show_changeset(ui, repo, {'template': template}) ui.pushbuffer() for rev in changesets: displayer.show(repo[rev]) return ui.popbuffer()
def metadata(): base = 'repo: %s\nnode: %s\nbranch: %s\n' % ( hex(repo.changelog.node(0)), hex(node), ctx.branch()) tags = ''.join('tag: %s\n' % t for t in ctx.tags() if repo.tagtype(t) == 'global') if not tags: repo.ui.pushbuffer() opts = {'template': '{latesttag}\n{latesttagdistance}', 'style': '', 'patch': None, 'git': None} cmdutil.show_changeset(repo.ui, repo, opts).show(ctx) ltags, dist = repo.ui.popbuffer().split('\n') tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':')) tags += 'latesttagdistance: %s\n' % dist return base + tags
def goutgoing(ui, repo, dest=None, **opts): """show the outgoing changesets alongside an ASCII revision graph Print the outgoing changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev')) other = hg.repository(cmdutil.remoteui(ui, opts), dest) if revs: revs = [repo.lookup(rev) for rev in revs] ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = repo.findoutgoing(other, force=opts.get('force')) if not o: ui.status(_("no changes found\n")) return o = repo.changelog.nodesbetween(o, revs)[0] revdag = graphrevs(repo, o, opts) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges)
def graphlog(ui, repo, *pats, **opts): """show revision history alongside an ASCII revision graph Print a revision history alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ revs, expr, filematcher = getlogrevs(repo, pats, opts) revs = sorted(revs, reverse=1) limit = cmdutil.loglimit(opts) if limit is not None: revs = revs[:limit] revdag = graphmod.dagwalker(repo, revs) getrenamed = None if opts.get('copies'): endrev = None if opts.get('rev'): endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges, getrenamed, filematcher)
def outgoing(self): limit = cmdutil.loglimit(opts) dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) if revs: revs = [repo.lookup(rev) for rev in revs] other = hg.repository(cmdutil.remoteui(repo, opts), dest) ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = repo.findoutgoing(other, force=opts.get('force')) if not o: ui.status(_("no changes found\n")) return 1 o = repo.changelog.nodesbetween(o, revs)[0] if opts.get('newest_first'): o.reverse() displayer = cmdutil.show_changeset(ui, repo, opts) count = 0 for n in o: if count >= limit: break parents = [p for p in repo.changelog.parents(n) if p != nullid] if opts.get('no_merges') and len(parents) == 2: continue count += 1 displayer.show(repo[n])
def get_rev_msg(self, revision_hash, template=TEMPLATE): self.displayer = show_changeset(self.ui, self.repo, {'template': template}, False) self.ui.pushbuffer() rev = self.repo.lookup(revision_hash) ctx = context.changectx(self.repo, rev) self.displayer.show(ctx) msg = self.ui.popbuffer() return msg
def push_notify(ui, repo, node, node_last, url, **kwargs): notify_url = ui.config('gchat', 'notify_url') if not notify_url: ui.warn( "Skipping push_notify hook because notify_url is not set for gchat\n" ) return True tpl = ui.config( 'gchat', 'notify_template', "{count} changesets {action} from repository _{url}_:\n\n{log}\n") log_tpl = ui.config('gchat', 'notify_log_template', 'status') try: orig_color = ui.config('ui', 'color') ui.setconfig('ui', 'color', 'off') color.setup(ui) except ImportError: pass revs = repo.revs('{}:{}'.format(node_last, node)) disp = cmdutil.show_changeset(ui, repo, {'template': log_tpl}) logtext = '' for rev in revs: ui.pushbuffer(labeled=False) disp.show(repo[rev]) newtext = ui.popbuffer() if len(logtext) + len(newtext) + len(tpl) > 4000: logtext += "\n*Changeset log truncated...*" break logtext += newtext disp.close() try: ui.setconfig('ui', 'color', orig_color) color.setup(ui) except ImportError: pass args = { 'count': len(revs), 'action': 'pushed' if kwargs['source'] == 'serve' else kwargs['source'].rstrip('e') + 'ed', 'source': kwargs['source'], 'url': url, 'log': logtext } text = tpl.format(**args) if len(text) > 4096: text = text[:4096 - 16] + "_<truncated...>_" req = urllib2.Request(notify_url, json.dumps({'text': text}), {'Content-Type': 'application/json'}) urllib2.urlopen(req, timeout=10)
def heads(self, repo): """ Show the head revisions """ heads = repo.heads() repo.ui.pushbuffer() displayer = cmdutil.show_changeset(repo.ui, repo, {}) for n in heads: displayer.show(changenode=n) text = repo.ui.popbuffer() return text
def incoming(self): limit = cmdutil.loglimit(opts) source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev')) other = hg.repository(cmdutil.remoteui(repo, opts), source) ui.status(_('comparing with %s\n') % url.hidepassword(source)) if revs: revs = [other.lookup(rev) for rev in revs] common, incoming, rheads = repo.findcommonincoming(other, heads=revs, force=opts["force"]) if not incoming: try: os.unlink(opts["bundle"]) except: pass ui.status(_("no changes found\n")) return 1 cleanup = None try: fname = opts["bundle"] if fname or not other.local(): # create a bundle (uncompressed if other repo is not local) if revs is None and other.capable('changegroupsubset'): revs = rheads if revs is None: cg = other.changegroup(incoming, "incoming") else: cg = other.changegroupsubset(incoming, revs, 'incoming') bundletype = other.local() and "HG10BZ" or "HG10UN" fname = cleanup = changegroup.writebundle(cg, fname, bundletype) # keep written bundle? if opts["bundle"]: cleanup = None if not other.local(): # use the created uncompressed bundlerepo other = bundlerepo.bundlerepository(ui, repo.root, fname) o = other.changelog.nodesbetween(incoming, revs)[0] if opts.get('newest_first'): o.reverse() displayer = cmdutil.show_changeset(ui, other, opts) count = 0 for n in o: if count >= limit: break parents = [p for p in other.changelog.parents(n) if p != nullid] if opts.get('no_merges') and len(parents) == 2: continue count += 1 displayer.show(other[n]) finally: if hasattr(other, 'close'): other.close() if cleanup: os.unlink(cleanup)
def gincoming(ui, repo, source="default", **opts): """show the incoming changesets alongside an ASCII revision graph Print the incoming changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(cmdutil.remoteui(repo, opts), source) revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev')) ui.status(_('comparing with %s\n') % url.hidepassword(source)) if revs: revs = [other.lookup(rev) for rev in revs] incoming = repo.findincoming(other, heads=revs, force=opts["force"]) if not incoming: try: os.unlink(opts["bundle"]) except: pass ui.status(_("no changes found\n")) return cleanup = None try: fname = opts["bundle"] if fname or not other.local(): # create a bundle (uncompressed if other repo is not local) if revs is None: cg = other.changegroup(incoming, "incoming") else: cg = other.changegroupsubset(incoming, revs, 'incoming') bundletype = other.local() and "HG10BZ" or "HG10UN" fname = cleanup = changegroup.writebundle(cg, fname, bundletype) # keep written bundle? if opts["bundle"]: cleanup = None if not other.local(): # use the created uncompressed bundlerepo other = bundlerepo.bundlerepository(ui, repo.root, fname) chlist = other.changelog.nodesbetween(incoming, revs)[0] revdag = graphrevs(other, chlist, opts) displayer = show_changeset(ui, other, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges) finally: if hasattr(other, 'close'): other.close() if cleanup: os.unlink(cleanup)
def parents(self, repo): """ Show the parent revisions """ p = repo.dirstate.parents() repo.ui.pushbuffer() displayer = cmdutil.show_changeset(repo.ui, repo, {}) for n in p: if n != nullid: displayer.show(changenode=n) text = repo.ui.popbuffer() return text
def asciiformat(ui, repo, revdag, opts, parentrepo=None): """formats a changelog DAG walk for ASCII output""" if parentrepo is None: parentrepo = repo showparents = [ctx.node() for ctx in parentrepo[None].parents()] displayer = show_changeset(ui, repo, opts, buffered=True) for (id, type, ctx, parentids) in revdag: if type != graphmod.CHANGESET: continue displayer.show(ctx) lines = displayer.hunk.pop(ctx.rev()).split('\n')[:-1] char = ctx.node() in showparents and '@' or 'o' yield (id, ASCIIDATA, (char, lines), parentids)
def parents(orig, ui, repo, *args, **opts): """show Mercurial & Subversion parents of the working dir or revision """ if not opts.get('svn', False): return orig(ui, repo, *args, **opts) meta = repo.svnmeta() hashes = meta.revmap.hashes() ha = util.parentrev(ui, repo, meta, hashes) if ha.node() == node.nullid: raise hgutil.Abort('No parent svn revision!') displayer = cmdutil.show_changeset(ui, repo, opts, buffered=False) displayer.show(ha) return 0
def fxheads(ui, repo, **opts): """Show last known head commits for pulled Firefox trees. The displayed list may be out of date. Pull before running to ensure data is current. """ if not isfirefoxrepo(repo): raise util.Abort(_('fxheads is only available on Firefox repos')) displayer = cmdutil.show_changeset(ui, repo, opts) for tag, node, tree, uri in get_firefoxtrees(repo): ctx = repo[node] displayer.show(ctx) displayer.close()
def _showchangesets(ui, repo, contexts=None, revs=None): """Pretty print a list of changesets. Can take either a list of change contexts or a list of revision numbers. """ if contexts is None: contexts = [] if revs is not None: contexts.extend(repo[r] for r in revs) showopts = { 'template': '[{shortest(node, 6)}] {if(bookmarks, "({bookmarks}) ")}' '{desc|firstline}\n' } displayer = cmdutil.show_changeset(ui, repo, showopts) for ctx in contexts: displayer.show(ctx)
def browserevs(ui, repo, nodes, opts): """interactively transplant changesets""" def browsehelp(ui): ui.write( _( "y: transplant this changeset\n" "n: skip this changeset\n" "m: merge at this changeset\n" "p: show patch\n" "c: commit selected changesets\n" "q: cancel transplant\n" "?: show this help\n" ) ) displayer = cmdutil.show_changeset(ui, repo, opts) transplants = [] merges = [] for node in nodes: displayer.show(repo[node]) action = None while not action: action = ui.prompt(_("apply changeset? [ynmpcq?]:")) if action == "?": browsehelp(ui) action = None elif action == "p": parent = repo.changelog.parents(node)[0] for chunk in patch.diff(repo, parent, node): ui.write(chunk) action = None elif action not in ("y", "n", "m", "c", "q"): ui.write(_("no such option\n")) action = None if action == "y": transplants.append(node) elif action == "m": merges.append(node) elif action == "c": break elif action == "q": transplants = () merges = () break displayer.close() return (transplants, merges)
def children(ui, repo, file_=None, **opts): """show the children of the given or working directory revision Print the children of the working directory's revisions. If a revision is given via -r/--rev, the children of that revision will be printed. If a file argument is given, revision in which the file was last changed (after the working directory revision or the argument to --rev if given) is printed. """ rev = opts.get('rev') if file_: ctx = repo.filectx(file_, changeid=rev) else: ctx = repo[rev] displayer = cmdutil.show_changeset(ui, repo, opts) for cctx in ctx.children(): displayer.show(cctx)
def children(ui, repo, file_=None, **opts): """show the children of the given or working dir revision Print the children of the working directory's revisions. If a revision is given via --rev, the children of that revision will be printed. If a file argument is given, revision in which the file was last changed (after the working directory revision or the argument to --rev if given) is printed. """ rev = opts.get('rev') if file_: ctx = repo.filectx(file_, changeid=rev) else: ctx = repo.changectx(rev) displayer = cmdutil.show_changeset(ui, repo, opts) for node in [cp.node() for cp in ctx.children()]: displayer.show(changenode=node)
def fxheads(ui, repo, **opts): """Show last known head commits for pulled Firefox trees. The displayed list may be out of date. Pull before running to ensure data is current. """ if not isfirefoxrepo(repo): raise util.Abort(_('fxheads is only available on Firefox repos')) displayer = cmdutil.show_changeset(ui, repo, opts) for tag, node in sorted(repo.tags().items()): if not resolve_trees_to_uris([tag])[0][1]: continue ctx = repo[node] displayer.show(ctx) displayer.close()
def jcheck(ui, repo, **opts): """check changesets against JDK standards""" ui.debug("jcheck repo=%s opts=%s\n" % (repo.path, opts)) repocompat(repo) if not repo.local(): raise error_Abort("repository '%s' is not local" % repo.path) if not os.path.exists(os.path.join(repo.root, ".jcheck")): ui.status("jcheck not enabled (no .jcheck in repository root)\n") return Pass if len(opts["rev"]) == 0: opts["rev"] = ["tip"] strict = opts.has_key("strict") and opts["strict"] lax = opts.has_key("lax") and opts["lax"] if strict: lax = False ch = checker(ui, repo, strict, lax) ch.check_repo() try: nop = lambda c, fns: None iter = cmdutil.walkchangerevs(repo, _matchall(repo), opts, nop) for ctx in iter: ch.check(ctx.rev(), ctx.node()) except (AttributeError, TypeError): # AttributeError: matchall does not exist in hg < 1.1 # TypeError: walkchangerevs args differ in hg <= 1.3.1 get = util.cachefunc(lambda r: repo.changectx(r).changeset()) changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get, opts) if ui.debugflag: displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn) for st, rev, fns in changeiter: if st == 'add': node = repo.changelog.node(rev) if ui.debugflag: displayer.show(rev, node, copies=False) ch.check(rev, node) elif st == 'iter': if ui.debugflag: displayer.flush(rev) if ch.rv == Fail: ui.status("\n") return ch.rv
def fxheads(ui, repo, **opts): """Show last known head commits for pulled Firefox trees. The displayed list may be out of date. Pull before running to ensure data is current. """ if not isfirefoxrepo(repo): raise util.Abort(_('fxheads is only available on Firefox repos')) displayer = cmdutil.show_changeset(ui, repo, opts) seen = set() for tag, node, tree, uri in get_firefoxtrees(repo): if node in seen: continue seen.add(node) ctx = repo[node] displayer.show(ctx) displayer.close()
def render_changesets(ui, repo, changesets, config): url = config.commit_url if url: node_template = "<{url}{{node|short}}|{{node|short}}>".format(url=url) else: node_template = "{node|short}" template = "{0}\\n".format(" | ".join([ "{branch}", node_template, "{date(date, '%Y-%m-%d [%H:%M:%S]')}", "{desc|strip|firstline}", ])) displayer = show_changeset(ui, repo, {'template': template}) ui.pushbuffer() for rev in changesets: displayer.show(repo[rev]) return ui.popbuffer()
def children(ui, repo, file_=None, **opts): """show the children of the given or working directory revision Print the children of the working directory's revisions. If a revision is given via -r/--rev, the children of that revision will be printed. If a file argument is given, revision in which the file was last changed (after the working directory revision or the argument to --rev if given) is printed. """ rev = opts.get("rev") if file_: ctx = repo.filectx(file_, changeid=rev) else: ctx = repo[rev] displayer = cmdutil.show_changeset(ui, repo, opts) for cctx in ctx.children(): displayer.show(cctx) displayer.close()
def browserevs(ui, repo, nodes, opts): '''interactively transplant changesets''' def browsehelp(ui): ui.write( _('y: transplant this changeset\n' 'n: skip this changeset\n' 'm: merge at this changeset\n' 'p: show patch\n' 'c: commit selected changesets\n' 'q: cancel transplant\n' '?: show this help\n')) displayer = cmdutil.show_changeset(ui, repo, opts) transplants = [] merges = [] for node in nodes: displayer.show(repo[node]) action = None while not action: action = ui.prompt(_('apply changeset? [ynmpcq?]:')) if action == '?': browsehelp(ui) action = None elif action == 'p': parent = repo.changelog.parents(node)[0] for chunk in patch.diff(repo, parent, node): ui.write(chunk) action = None elif action not in ('y', 'n', 'm', 'c', 'q'): ui.write(_('no such option\n')) action = None if action == 'y': transplants.append(node) elif action == 'm': merges.append(node) elif action == 'c': break elif action == 'q': transplants = () merges = () break displayer.close() return (transplants, merges)
def goutgoing(ui, repo, dest=None, **opts): """show the outgoing changesets alongside an ASCII revision graph Print the outgoing changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) o = hg._outgoing(ui, repo, dest, opts) if o is None: return revdag = graphrevs(repo, o, opts) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges)
def browserevs(ui, repo, nodes, opts): '''interactively transplant changesets''' def browsehelp(ui): ui.write(_('y: transplant this changeset\n' 'n: skip this changeset\n' 'm: merge at this changeset\n' 'p: show patch\n' 'c: commit selected changesets\n' 'q: cancel transplant\n' '?: show this help\n')) displayer = cmdutil.show_changeset(ui, repo, opts) transplants = [] merges = [] for node in nodes: displayer.show(repo[node]) action = None while not action: action = ui.prompt(_('apply changeset? [ynmpcq?]:')) if action == '?': browsehelp(ui) action = None elif action == 'p': parent = repo.changelog.parents(node)[0] for chunk in patch.diff(repo, parent, node): ui.write(chunk) action = None elif action not in ('y', 'n', 'm', 'c', 'q'): ui.write(_('no such option\n')) action = None if action == 'y': transplants.append(node) elif action == 'm': merges.append(node) elif action == 'c': break elif action == 'q': transplants = () merges = () break displayer.close() return (transplants, merges)
def graphlog(ui, repo, *pats, **opts): """show revision history alongside an ASCII revision graph Print a revision history alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(pats, opts) revs = sorted(scmutil.revrange(repo, [revset(pats, opts)]), reverse=1) limit = cmdutil.loglimit(opts) if limit is not None: revs = revs[:limit] revdag = graphmod.dagwalker(repo, revs) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges)
def browserevs(ui, repo, nodes, opts): '''interactively transplant changesets''' displayer = cmdutil.show_changeset(ui, repo, opts) transplants = [] merges = [] prompt = _('apply changeset? [ynmpcq?]:' '$$ &yes, transplant this changeset' '$$ &no, skip this changeset' '$$ &merge at this changeset' '$$ show &patch' '$$ &commit selected changesets' '$$ &quit and cancel transplant' '$$ &? (show this help)') for node in nodes: displayer.show(repo[node]) action = None while not action: action = 'ynmpcq?'[ui.promptchoice(prompt)] if action == '?': for c, t in ui.extractchoices(prompt)[1]: ui.write('%s: %s\n' % (c, t)) action = None elif action == 'p': parent = repo.changelog.parents(node)[0] for chunk in patch.diff(repo, parent, node): ui.write(chunk) action = None if action == 'y': transplants.append(node) elif action == 'm': merges.append(node) elif action == 'c': break elif action == 'q': transplants = () merges = () break displayer.close() return (transplants, merges)
def tip(self, repo): """ Show the tip revision """ repo.ui.pushbuffer() cmdutil.show_changeset(repo.ui, repo, {}).show(nullrev+repo.changelog.count()) text = repo.ui.popbuffer() return text
def _smartlog(ui, repo, *pats, **opts): masterstring = opts.get('master') masterrevset = _masterrevset(ui, repo, masterstring) revs = set() global hiddenchanges hiddenchanges = 0 global commit_info commit_info = opts.get('commit_info') if not opts.get('rev'): if opts.get('all'): recentdays = -1 else: recentdays = 14 revstring = revsetlang.formatspec('smartlog(%s, %s)', masterrevset, recentdays) revs.update(scmutil.revrange(repo, [revstring])) masterrev = _masterrev(repo, masterrevset) else: revs.update(scmutil.revrange(repo, opts.get('rev'))) try: masterrev = repo.revs('.').first() except error.RepoLookupError: masterrev = revs[0] if -1 in revs: revs.remove(-1) # It's important that these function caches come after the revsets above, # because the revsets may cause extra nodes to become visible, which in # turn invalidates the changelog instance. rev = repo.changelog.rev ancestor = repo.changelog.ancestor node = repo.changelog.node # Find lowest common ancestors of revs. If we have multiple roots in the # repo the following will find one ancestor per group of revs with the # same root. ancestors = set() for r in revs: added = False for anc in list(ancestors): lca = rev(ancestor(node(anc), node(r))) if lca != -1: if anc != lca: ancestors.discard(anc) ancestors.add(lca) added = True if not added: ancestors.add(r) revs |= ancestors revs = sorted(list(revs), reverse=True) if len(revs) == 0: return # Print it! overrides = {} if ui.config('experimental', 'graphstyle.grandparent') == '|': overrides[('experimental', 'graphstyle.grandparent')] = '2.' with ui.configoverride(overrides, 'smartlog'): revdag = getdag(ui, repo, revs, masterrev) displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True) ui.pager('smartlog') cmdutil.displaygraph( ui, repo, revdag, displayer, graphmod.asciiedges, None, None) try: with open(repo.vfs.join('completionhints'), 'w+') as f: for rev in revdag: commit_hash = rev[2].node() # Skip fakectxt nodes if commit_hash != '...': f.write(nodemod.short(commit_hash) + '\n') except IOError: # No write access. No big deal. pass if hiddenchanges: msg = _( "note: hiding %s old heads without bookmarks\n") % hiddenchanges hint = _("(use --all to see them)\n") ui.warn(msg) ui.warn(hint)
def _smartlog(ui, repo, *pats, **opts): masterstring = opts.get('master') masterrevset = _masterrevset(ui, repo, masterstring) revs = set() global hiddenchanges hiddenchanges = 0 global commit_info commit_info = opts.get('commit_info') if not opts.get('rev'): if opts.get('all'): recentdays = -1 else: recentdays = 14 masterrev = _masterrev(repo, masterrevset) revstring = revsetlang.formatspec('smartlog(%s, %s)', masterrev or '', recentdays) revs.update(scmutil.revrange(repo, [revstring])) else: revs.update(scmutil.revrange(repo, opts.get('rev'))) try: masterrev = repo.revs('.').first() except error.RepoLookupError: masterrev = revs[0] if -1 in revs: revs.remove(-1) # It's important that these function caches come after the revsets above, # because the revsets may cause extra nodes to become visible, which in # turn invalidates the changelog instance. rev = repo.changelog.rev ancestor = repo.changelog.ancestor node = repo.changelog.node # Find lowest common ancestors of revs. If we have multiple roots in the # repo the following will find one ancestor per group of revs with the # same root. ancestors = set() for r in revs: added = False for anc in list(ancestors): lca = rev(ancestor(node(anc), node(r))) if lca != -1: if anc != lca: ancestors.discard(anc) ancestors.add(lca) added = True if not added: ancestors.add(r) revs |= ancestors revs = sorted(list(revs), reverse=True) if len(revs) == 0: return # Print it! overrides = {} if ui.config('experimental', 'graphstyle.grandparent', '2.') == '|': overrides[('experimental', 'graphstyle.grandparent')] = '2.' with ui.configoverride(overrides, 'smartlog'): revdag = getdag(ui, repo, revs, masterrev) displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True) ui.pager('smartlog') cmdutil.displaygraph( ui, repo, revdag, displayer, graphmod.asciiedges, None, None) try: with open(repo.vfs.join('completionhints'), 'w+') as f: for rev in revdag: commit_hash = rev[2].node() # Skip fakectxt nodes if commit_hash != '...': f.write(nodemod.short(commit_hash) + '\n') except IOError: # No write access. No big deal. pass if hiddenchanges: msg = _( "note: hiding %s old heads without bookmarks\n") % hiddenchanges hint = _("(use --all to see them)\n") ui.warn(msg) ui.warn(hint)
def graphlog(ui, repo, path=None, **opts): """show revision history alongside an ASCII revision graph Print a revision history alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ limit = get_limit(opts["limit"]) (start_rev, stop_rev) = get_revs(repo, opts["rev"]) stop_rev = max(stop_rev, start_rev - limit + 1) if start_rev == nullrev: return cs_printer = show_changeset(ui, repo, opts) if path: cpath = canonpath(repo.root, os.getcwd(), path) grapher = filelog_grapher(repo, cpath, start_rev, stop_rev) else: grapher = revision_grapher(repo, start_rev, stop_rev) repo_parents = repo.dirstate.parents() prev_n_columns_diff = 0 prev_node_index = 0 for (rev, node, node_index, edges, n_columns, n_columns_diff) in grapher: # log_strings is the list of all log strings to draw alongside # the graph. ui.pushbuffer() cs_printer.show(rev, node) log_strings = ui.popbuffer().split("\n")[:-1] if n_columns_diff == -1: # Transform # # | | | | | | # o | | into o---+ # |X / |/ / # | | | | fix_long_right_edges(edges) # add_padding_line says whether to rewrite # # | | | | | | | | # | o---+ into | o---+ # | / / | | | # <--- padding line # o | | | / / # o | | add_padding_line = (len(log_strings) > 2 and n_columns_diff == -1 and [x for (x, y) in edges if x + 1 < y]) # fix_nodeline_tail says whether to rewrite # # | | o | | | | o | | # | | |/ / | | |/ / # | o | | into | o / / # <--- fixed nodeline tail # | |/ / | |/ / # o | | o | | fix_nodeline_tail = len(log_strings) <= 2 and not add_padding_line # nodeline is the line containing the node character (@ or o). nodeline = ["|", " "] * node_index if node in repo_parents: node_ch = "@" else: node_ch = "o" nodeline.extend([node_ch, " "]) nodeline.extend( get_nodeline_edges_tail( node_index, prev_node_index, n_columns, n_columns_diff, prev_n_columns_diff, fix_nodeline_tail)) # shift_interline is the line containing the non-vertical # edges between this entry and the next. shift_interline = ["|", " "] * node_index if n_columns_diff == -1: n_spaces = 1 edge_ch = "/" elif n_columns_diff == 0: n_spaces = 2 edge_ch = "|" else: n_spaces = 3 edge_ch = "\\" shift_interline.extend(n_spaces * [" "]) shift_interline.extend([edge_ch, " "] * (n_columns - node_index - 1)) # Draw edges from the current node to its parents. draw_edges(edges, nodeline, shift_interline) # lines is the list of all graph lines to print. lines = [nodeline] if add_padding_line: lines.append(get_padding_line(node_index, n_columns, edges)) lines.append(shift_interline) # Make sure that there are as many graph lines as there are # log strings. while len(log_strings) < len(lines): log_strings.append("") if len(lines) < len(log_strings): extra_interline = ["|", " "] * (n_columns + n_columns_diff) while len(lines) < len(log_strings): lines.append(extra_interline) # Print lines. indentation_level = max(n_columns, n_columns + n_columns_diff) for (line, logstr) in zip(lines, log_strings): ui.write(format_line(line, indentation_level, logstr)) # ...and start over. prev_node_index = node_index prev_n_columns_diff = n_columns_diff
def journal(ui, repo, *args, **opts): """show the previous position of bookmarks and the working copy The journal is used to see the previous commits that bookmarks and the working copy pointed to. By default the previous locations for the working copy. Passing a bookmark name will show all the previous positions of that bookmark. Use the --all switch to show previous locations for all bookmarks and the working copy; each line will then include the bookmark name, or '.' for the working copy, as well. If `name` starts with `re:`, the remainder of the name is treated as a regular expression. To match a name that actually starts with `re:`, use the prefix `literal:`. By default hg journal only shows the commit hash and the command that was running at that time. -v/--verbose will show the prior hash, the user, and the time at which it happened. Use -c/--commits to output log information on each commit hash; at this point you can use the usual `--patch`, `--git`, `--stat` and `--template` switches to alter the log output for these. `hg journal -T json` can be used to produce machine readable output. """ name = '.' if opts.get('all'): if args: raise error.Abort( _("You can't combine --all and filtering on a name")) name = None if args: name = args[0] fm = ui.formatter('journal', opts) if opts.get("template") != "json": if name is None: displayname = _('the working copy and bookmarks') else: displayname = "'%s'" % name ui.status(_("previous locations of %s:\n") % displayname) limit = cmdutil.loglimit(opts) entry = None for count, entry in enumerate(repo.journal.filtered(name=name)): if count == limit: break newhashesstr = fm.formatlist(map(fm.hexfunc, entry.newhashes), name='node', sep=',') oldhashesstr = fm.formatlist(map(fm.hexfunc, entry.oldhashes), name='node', sep=',') fm.startitem() fm.condwrite(ui.verbose, 'oldhashes', '%s -> ', oldhashesstr) fm.write('newhashes', '%s', newhashesstr) fm.condwrite(ui.verbose, 'user', ' %-8s', entry.user) fm.condwrite( opts.get('all') or name.startswith('re:'), 'name', ' %-8s', entry.name) timestring = fm.formatdate(entry.timestamp, '%Y-%m-%d %H:%M %1%2') fm.condwrite(ui.verbose, 'date', ' %s', timestring) fm.write('command', ' %s\n', entry.command) if opts.get("commits"): displayer = cmdutil.show_changeset(ui, repo, opts, buffered=False) for hash in entry.newhashes: try: ctx = repo[hash] displayer.show(ctx) except error.RepoLookupError as e: fm.write('repolookuperror', "%s\n\n", str(e)) displayer.close() fm.end() if entry is None: ui.status(_("no recorded locations\n"))