author | mpm@selenic.com |
Wed, 24 Aug 2005 13:31:46 -0700 | |
changeset 1035 | bcb44382b0d0 |
parent 1023 | bc806ba72959 (current diff) |
parent 1034 | 8dbbea5bc844 (diff) |
child 1036 | 7c00f5f2c967 |
child 1037 | c0a1abf562eb |
--- a/contrib/mercurial.el Wed Aug 24 03:33:54 2005 -0700 +++ b/contrib/mercurial.el Wed Aug 24 13:31:46 2005 -0700 @@ -47,6 +47,7 @@ (require 'cl) (require 'diff-mode) (require 'easymenu) +(require 'executable) (require 'vc) @@ -91,6 +92,11 @@ :type 'sexp :group 'mercurial) +(defcustom hg-log-mode-hook nil + "Hook run after a buffer is filled with log information." + :type 'sexp + :group 'mercurial) + (defcustom hg-global-prefix "\C-ch" "The global prefix for Mercurial keymap bindings." :type 'sexp @@ -124,6 +130,20 @@ :type 'boolean :group 'mercurial) +(defcustom hg-incoming-repository "default" + "The repository from which changes are pulled from by default. +This should be a symbolic repository name, since it is used for all +repository-related commands." + :type 'string + :group 'mercurial) + +(defcustom hg-outgoing-repository "default-push" + "The repository to which changes are pushed to by default. +This should be a symbolic repository name, since it is used for all +repository-related commands." + :type 'string + :group 'mercurial) + ;;; Other variables. @@ -151,6 +171,7 @@ "The name to use for Mercurial output buffers.") (defvar hg-file-history nil) +(defvar hg-repo-history nil) (defvar hg-rev-history nil) @@ -233,6 +254,7 @@ (defvar hg-commit-mode-map (make-sparse-keymap)) (define-key hg-commit-mode-map "\C-c\C-c" 'hg-commit-finish) (define-key hg-commit-mode-map "\C-c\C-k" 'hg-commit-kill) +(define-key hg-commit-mode-map "\C-xv=" 'hg-diff-repo) (defvar hg-commit-mode-file-map (make-sparse-keymap)) (define-key hg-commit-mode-file-map @@ -295,6 +317,17 @@ (car res)) (cdr res)))) +(defun hg-sync-buffers (path) + "Sync buffers visiting PATH with their on-disk copies. +If PATH is not being visited, but is under the repository root, sync +all buffers visiting files in the repository." + (let ((buf (find-buffer-visiting path))) + (if buf + (with-current-buffer buf + (vc-buffer-sync)) + (hg-do-across-repo path + (vc-buffer-sync))))) + (defun hg-buffer-commands (pnt) "Use the properties of a character to do something sensible." (interactive "d") @@ -358,13 +391,84 @@ 'hg-file-history)) path)))) +(defun hg-read-config () + "Return an alist of (key . value) pairs of Mercurial config data. +Each key is of the form (section . name)." + (let (items) + (dolist (line (split-string (hg-chomp (hg-run0 "debugconfig")) "\n") items) + (string-match "^\\([^=]*\\)=\\(.*\\)" line) + (let* ((left (substring line (match-beginning 1) (match-end 1))) + (right (substring line (match-beginning 2) (match-end 2))) + (key (split-string left "\\.")) + (value (hg-replace-in-string right "\\\\n" "\n" t))) + (setq items (cons (cons (cons (car key) (cadr key)) value) items)))))) + +(defun hg-config-section (section config) + "Return an alist of (name . value) pairs for SECTION of CONFIG." + (let (items) + (dolist (item config items) + (when (equal (caar item) section) + (setq items (cons (cons (cdar item) (cdr item)) items)))))) + +(defun hg-string-starts-with (sub str) + "Indicate whether string STR starts with the substring or character SUB." + (if (not (stringp sub)) + (and (> (length str) 0) (equal (elt str 0) sub)) + (let ((sub-len (length sub))) + (and (<= sub-len (length str)) + (string= sub (substring str 0 sub-len)))))) + +(defun hg-complete-repo (string predicate all) + "Attempt to complete a repository name. +We complete on either symbolic names from Mercurial's config or real +directory names from the file system. We do not penalise URLs." + (or (if all + (all-completions string hg-repo-completion-table predicate) + (try-completion string hg-repo-completion-table predicate)) + (let* ((str (expand-file-name string)) + (dir (file-name-directory str)) + (file (file-name-nondirectory str))) + (if all + (let (completions) + (dolist (name (delete "./" (file-name-all-completions file dir)) + completions) + (let ((path (concat dir name))) + (when (file-directory-p path) + (setq completions (cons name completions)))))) + (let ((comp (file-name-completion file dir))) + (if comp + (hg-abbrev-file-name (concat dir comp)))))))) + +(defun hg-read-repo-name (&optional prompt initial-contents default) + "Read the location of a repository." + (save-excursion + (while hg-prev-buffer + (set-buffer hg-prev-buffer)) + (let (hg-repo-completion-table) + (if current-prefix-arg + (progn + (dolist (path (hg-config-section "paths" (hg-read-config))) + (setq hg-repo-completion-table + (cons (cons (car path) t) hg-repo-completion-table)) + (unless (hg-string-starts-with directory-sep-char (cdr path)) + (setq hg-repo-completion-table + (cons (cons (cdr path) t) hg-repo-completion-table)))) + (completing-read (format "Repository%s: " (or prompt "")) + 'hg-complete-repo + nil + nil + initial-contents + 'hg-repo-history + default)) + default)))) + (defun hg-read-rev (&optional prompt default) "Read a revision or tag, offering completions." (save-excursion (while hg-prev-buffer (set-buffer hg-prev-buffer)) (let ((rev (or default "tip"))) - (if (or (not rev) current-prefix-arg) + (if current-prefix-arg (let ((revs (split-string (hg-chomp (hg-run0 "-q" "log" "-r" (format "-%d" @@ -732,8 +836,7 @@ modified-files) (unless root (error "Cannot commit outside a repository!")) - (hg-do-across-repo - (vc-buffer-sync)) + (hg-sync-buffers root) (setq modified-files (hg-chomp (hg-run0 "--cwd" root "status" "-arm"))) (when (and (= (length modified-files) 0) (not hg-commit-allow-empty-file-list)) @@ -787,17 +890,21 @@ (hg-read-rev " to start with") (let ((rev2 (hg-read-rev " to end with" 'working-dir))) (and (not (eq rev2 'working-dir)) rev2)))) - (unless rev1 - (setq rev1 "-1")) + (hg-sync-buffers path) (let ((a-path (hg-abbrev-file-name path)) + (r1 (or rev1 "tip")) diff) - (hg-view-output ((if (equal rev1 rev2) - (format "Mercurial: Rev %s of %s" rev1 a-path) - (format "Mercurial: Rev %s to %s of %s" - rev1 (or rev2 "Current") a-path))) + (hg-view-output ((cond + ((and (equal r1 "tip") (not rev2)) + (format "Mercurial: Diff against tip of %s" a-path)) + ((equal r1 rev2) + (format "Mercurial: Diff of rev %s of %s" r1 a-path)) + (t + (format "Mercurial: Diff from rev %s to %s of %s" + r1 (or rev2 "Current") a-path)))) (if rev2 - (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path) - (call-process (hg-binary) nil t nil "diff" "-r" rev1 path)) + (call-process (hg-binary) nil t nil "diff" "-r" r1 "-r" rev2 path) + (call-process (hg-binary) nil t nil "diff" "-r" r1 path)) (diff-mode) (setq diff (not (= (point-min) (point-max)))) (font-lock-fontify-buffer)) @@ -822,32 +929,47 @@ (with-current-buffer buf (hg-mode-line))))) -(defun hg-incoming () - (interactive) - (error "not implemented")) +(defun hg-incoming (&optional repo) + "Display changesets present in REPO that are not present locally." + (interactive (list (hg-read-repo-name " where changes would come from"))) + (hg-view-output ((format "Mercurial: Incoming from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-incoming-repository)))) + (call-process (hg-binary) nil t nil "incoming" + (or repo hg-incoming-repository)) + (hg-log-mode))) (defun hg-init () (interactive) (error "not implemented")) +(defun hg-log-mode () + "Mode for viewing a Mercurial change log." + (goto-char (point-min)) + (when (looking-at "^searching for changes") + (kill-entire-line)) + (run-hooks 'hg-log-mode-hook)) + (defun hg-log (path &optional rev1 rev2) "Display the revision history of PATH, between REV1 and REV2. -REV1 defaults to the initial revision, while REV2 defaults to the tip. -With a prefix argument, prompt for each parameter. -Variable hg-log-limit controls the number of log entries displayed." +REV1 defaults to hg-log-limit changes from the tip revision, while +REV2 defaults to the tip. +With a prefix argument, prompt for each parameter." (interactive (list (hg-read-file-name " to log") (hg-read-rev " to start with" "-1") (hg-read-rev " to end with" (format "-%d" hg-log-limit)))) - (let ((a-path (hg-abbrev-file-name path))) - (hg-view-output ((if (equal rev1 rev2) - (format "Mercurial: Rev %s of %s" rev1 a-path) - (format "Mercurial: Rev %s to %s of %s" - rev1 (or rev2 "Current") a-path))) + (let ((a-path (hg-abbrev-file-name path)) + (r1 (or rev1 (format "-%d" hg-log-limit))) + (r2 (or rev2 rev1 "-1"))) + (hg-view-output ((if (equal r1 r2) + (format "Mercurial: Log of rev %s of %s" rev1 a-path) + (format "Mercurial: Log from rev %s to %s of %s" + r1 r2 a-path))) (if (> (length path) (length (hg-root path))) - (call-process (hg-binary) nil t nil "log" "-r" rev1 "-r" rev2 path) - (call-process (hg-binary) nil t nil "log" "-r" rev1 "-r" rev2)) - (diff-mode) - (font-lock-fontify-buffer)))) + (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2 path) + (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2)) + (hg-log-mode)))) (defun hg-log-repo (path &optional rev1 rev2) "Display the revision history of the repository containing PATH. @@ -859,17 +981,31 @@ (hg-read-rev " to end with" (format "-%d" hg-log-limit)))) (hg-log (hg-root path) rev1 rev2)) -(defun hg-outgoing () - (interactive) - (error "not implemented")) +(defun hg-outgoing (&optional repo) + "Display changesets present locally that are not present in REPO." + (interactive (list (hg-read-repo-name " where changes would go to" nil + hg-outgoing-repository))) + (hg-view-output ((format "Mercurial: Outgoing from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-outgoing-repository)))) + (call-process (hg-binary) nil t nil "outgoing" + (or repo hg-outgoing-repository)) + (hg-log-mode))) (defun hg-pull () (interactive) (error "not implemented")) -(defun hg-push () - (interactive) - (error "not implemented")) +(defun hg-push (&optional repo) + "Push changes to repository REPO." + (interactive (list (hg-read-repo-name " to push to"))) + (hg-view-output ((format "Mercurial: Push from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-outgoing-repository)))) + (call-process (hg-binary) nil t nil "push" + (or repo hg-outgoing-repository)))) (defun hg-revert-buffer-internal () (let ((ctx (hg-buffer-context))) @@ -919,7 +1055,7 @@ (if root (message "The root of this repository is `%s'." root) (message "The path `%s' is not in a Mercurial repository." - (abbreviate-file-name path t)))) + (hg-abbrev-file-name path)))) root) hg-root))
--- a/contrib/patchbomb Wed Aug 24 03:33:54 2005 -0700 +++ b/contrib/patchbomb Wed Aug 24 13:31:46 2005 -0700 @@ -147,7 +147,8 @@ self.container.append(''.join(self.lines).split('\n')) self.lines = [] - commands.export(ui, repo, *args, **{'output': exportee(patches)}) + commands.export(ui, repo, *args, **{'output': exportee(patches), + 'text': None}) jumbo = [] msgs = []
--- a/mercurial/commands.py Wed Aug 24 03:33:54 2005 -0700 +++ b/mercurial/commands.py Wed Aug 24 13:31:46 2005 -0700 @@ -35,7 +35,7 @@ def makewalk(repo, pats, opts, head = ''): cwd = repo.getcwd() - files, matchfn = matchpats(repo, cwd, pats, opts, head) + files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head) exact = dict(zip(files, files)) def walk(): for src, fn in repo.walk(files = files, match = matchfn): @@ -86,7 +86,7 @@ for rev in xrange(start, end, step): yield str(rev) else: - yield spec + yield str(fix(spec, None)) def make_filename(repo, r, pat, node=None, total=None, seqno=None, revwidth=None): @@ -193,29 +193,19 @@ tn = None fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text)) -def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None): +def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None): """show a single changeset or file revision""" - changelog = repo.changelog - if filelog: - log = filelog - filerev = rev - node = filenode = filelog.node(filerev) - changerev = filelog.linkrev(filenode) - changenode = changenode or changelog.node(changerev) - else: - log = changelog - changerev = rev - if changenode is None: - changenode = changelog.node(changerev) - elif not changerev: - rev = changerev = changelog.rev(changenode) - node = changenode + log = repo.changelog + if changenode is None: + changenode = log.node(rev) + elif not rev: + rev = log.rev(changenode) if ui.quiet: - ui.write("%d:%s\n" % (rev, hg.short(node))) + ui.write("%d:%s\n" % (rev, hg.short(changenode))) return - changes = changelog.read(changenode) + changes = log.read(changenode) t, tz = changes[2].split(' ') # a conversion tool was sticking non-integer offsets into repos @@ -226,22 +216,20 @@ date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36) parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p)) - for p in log.parents(node) + for p in log.parents(changenode) if ui.debugflag or p != hg.nullid] if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1: parents = [] if ui.verbose: - ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode))) + ui.write("changeset: %d:%s\n" % (rev, hg.hex(changenode))) else: - ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode))) + ui.write("changeset: %d:%s\n" % (rev, hg.short(changenode))) for tag in repo.nodetags(changenode): ui.status("tag: %s\n" % tag) for parent in parents: ui.write("parent: %d:%s\n" % parent) - if filelog: - ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode))) if brinfo and changenode in brinfo: br = brinfo[changenode] @@ -253,7 +241,7 @@ ui.status("date: %s\n" % date) if ui.debugflag: - files = repo.changes(changelog.parents(changenode)[0], changenode) + files = repo.changes(log.parents(changenode)[0], changenode) for key, value in zip(["files:", "files+:", "files-:"], files): if value: ui.note("%-12s %s\n" % (key, " ".join(value))) @@ -560,7 +548,8 @@ if not pats and cwd: opts['include'] = [os.path.join(cwd, i) for i in opts['include']] opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] - fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts) + fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '', + pats, opts) if pats: c, a, d, u = repo.changes(files = fns, match = match) files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r'] @@ -604,6 +593,13 @@ if errors: raise util.Abort(".hg/dirstate inconsistent with current parent's manifest") +def debugconfig(ui): + try: + repo = hg.repository(ui) + except: pass + for section, name, value in ui.walkconfig(): + ui.write('%s.%s=%s\n' % (section, name, value)) + def debugstate(ui, repo): """show the contents of the current dirstate""" repo.dirstate.read() @@ -842,39 +838,92 @@ else: ui.write(rel, end) -def log(ui, repo, f=None, **opts): - """show the revision history of the repository or a single file""" - if f: - files = relpath(repo, [f]) - filelog = repo.file(files[0]) - log = filelog - lookup = filelog.lookup - else: - files = None - filelog = None - log = repo.changelog - lookup = repo.lookup - revlist = [] - revs = [log.rev(lookup(rev)) for rev in opts['rev']] - while revs: - if len(revs) == 1: - revlist.append(revs.pop(0)) - else: - a = revs.pop(0) - b = revs.pop(0) - off = a > b and -1 or 1 - revlist.extend(range(a, b + off, off)) +def log(ui, repo, *pats, **opts): + """show revision history of entire repository or files""" + # This code most commonly needs to iterate backwards over the + # history it is interested in. This has awful (quadratic-looking) + # performance, so we use iterators that walk forwards through + # windows of revisions, yielding revisions in reverse order, while + # walking the windows backwards. + files, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts) + revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0'])) + wanted = {} + slowpath = anypats + window = 300 + if not slowpath and not files: + # No files, no patterns. Display all revs. + wanted = dict(zip(revs, revs)) + if not slowpath: + # Only files, no patterns. Check the history of each file. + def filerevgen(filelog): + for i in xrange(filelog.count() - 1, 0, -window): + revs = [] + for j in xrange(max(0, i - window), i): + revs.append(filelog.linkrev(filelog.node(j))) + revs.reverse() + for rev in revs: + yield rev - for i in revlist or range(log.count() - 1, -1, -1): - show_changeset(ui, repo, filelog=filelog, rev=i) + minrev, maxrev = min(revs), max(revs) + for filelog in map(repo.file, files): + # A zero count may be a directory or deleted file, so + # try to find matching entries on the slow path. + if filelog.count() == 0: + slowpath = True + break + for rev in filerevgen(filelog): + if rev <= maxrev: + if rev < minrev: break + wanted[rev] = 1 + if slowpath: + # The slow path checks files modified in every changeset. + def mfrevgen(): + for i in xrange(repo.changelog.count() - 1, 0, -window): + for j in xrange(max(0, i - window), i): + yield j, repo.changelog.read(repo.lookup(str(j)))[3] + + for rev, mf in mfrevgen(): + if filter(matchfn, mf): + wanted[rev] = 1 + + def changerevgen(): + class dui: + # Implement and delegate some ui protocol. Save hunks of + # output for later display in the desired order. + def __init__(self, ui): + self.ui = ui + self.hunk = {} + def bump(self, rev): + self.rev = rev + self.hunk[rev] = [] + def note(self, *args): + if self.verbose: self.write(*args) + def status(self, *args): + if not self.quiet: self.write(*args) + def write(self, *args): + self.hunk[self.rev].append(args) + def __getattr__(self, key): + return getattr(self.ui, key) + for i in xrange(0, len(revs), window): + nrevs = [rev for rev in revs[i : min(i + window, len(revs))] + if rev in wanted] + srevs = list(nrevs) + srevs.sort() + du = dui(ui) + for rev in srevs: + du.bump(rev) + yield rev, du + for rev in nrevs: + for args in du.hunk[rev]: + ui.write(*args) + + for rev, dui in changerevgen(): + show_changeset(dui, repo, rev) if opts['patch']: - if filelog: - filenode = filelog.node(i) - i = filelog.linkrev(filenode) - changenode = repo.changelog.node(i) + changenode = repo.changelog.node(rev) prev, other = repo.changelog.parents(changenode) - dodiff(sys.stdout, ui, repo, prev, changenode, files) - ui.write("\n\n") + dodiff(dui, dui, repo, prev, changenode, files) + du.write("\n\n") def manifest(ui, repo, rev=None): """output the latest or given revision of the project manifest""" @@ -1155,7 +1204,7 @@ ''' cwd = repo.getcwd() - files, matchfn = matchpats(repo, cwd, pats, opts) + files, matchfn, anypats = matchpats(repo, cwd, pats, opts) (c, a, d, u) = [[util.pathto(cwd, x) for x in n] for n in repo.changes(files=files, match=matchfn)] @@ -1321,6 +1370,7 @@ 'hg commit [OPTION]... [FILE]...'), "copy": (copy, [], 'hg copy SOURCE DEST'), "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'), + "debugconfig": (debugconfig, [], 'debugconfig'), "debugstate": (debugstate, [], 'debugstate'), "debugindex": (debugindex, [], 'debugindex FILE'), "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'), @@ -1370,7 +1420,9 @@ 'hg locate [OPTION]... [PATTERN]...'), "^log|history": (log, - [('r', 'rev', [], 'revision'), + [('I', 'include', [], 'include path in search'), + ('X', 'exclude', [], 'exclude path from search'), + ('r', 'rev', [], 'revision'), ('p', 'patch', None, 'show patch')], 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'), "manifest": (manifest, [], 'hg manifest [REV]'), @@ -1461,7 +1513,7 @@ ('', 'time', None, 'time how long the command takes'), ] -norepo = "clone init version help debugindex debugindexdot paths" +norepo = "clone init version help debugconfig debugindex debugindexdot paths" def find(cmd): for e in table.keys():
--- a/mercurial/ui.py Wed Aug 24 03:33:54 2005 -0700 +++ b/mercurial/ui.py Wed Aug 24 13:31:46 2005 -0700 @@ -52,6 +52,17 @@ return self.cdata.items(section) return [] + def walkconfig(self): + seen = {} + for (section, name), value in self.overlay.iteritems(): + yield section, name, value + seen[section, name] = 1 + for section in self.cdata.sections(): + for name, value in self.cdata.items(section): + if (section, name) in seen: continue + yield section, name, value.replace('\n', '\\n') + seen[section, name] = 1 + def username(self): return (os.environ.get("HGUSER") or self.config("ui", "username") or
--- a/mercurial/util.py Wed Aug 24 03:33:54 2005 -0700 +++ b/mercurial/util.py Wed Aug 24 13:31:46 2005 -0700 @@ -156,11 +156,13 @@ if exc: excmatch = matchfn(map(patkind, exc), '(?:/|$)') - return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and - (fn.endswith('/') or - (not pats and not files) or - (pats and patmatch(fn)) or - (files and filematch(fn)))) + return (roots, + lambda fn: (incmatch(fn) and not excmatch(fn) and + (fn.endswith('/') or + (not pats and not files) or + (pats and patmatch(fn)) or + (files and filematch(fn)))), + (inc or exc or (pats and pats != [('glob', '**')])) and True) def system(cmd, errprefix=None): """execute a shell command that must succeed"""
--- a/tests/test-help.out Wed Aug 24 03:33:54 2005 -0700 +++ b/tests/test-help.out Wed Aug 24 13:31:46 2005 -0700 @@ -9,7 +9,7 @@ diff diff working directory (or selected files) export dump the header and diffs for one or more changesets init create a new repository in the given directory - log show the revision history of the repository or a single file + log show revision history of entire repository or files pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit @@ -24,7 +24,7 @@ diff diff working directory (or selected files) export dump the header and diffs for one or more changesets init create a new repository in the given directory - log show the revision history of the repository or a single file + log show revision history of entire repository or files pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit @@ -53,7 +53,7 @@ incoming show new changesets found in source init create a new repository in the given directory locate locate files matching specific patterns - log show the revision history of the repository or a single file + log show revision history of entire repository or files manifest output the latest or given revision of the project manifest outgoing show changesets not found in destination parents show the parents of the working dir or revision @@ -91,7 +91,7 @@ incoming show new changesets found in source init create a new repository in the given directory locate locate files matching specific patterns - log show the revision history of the repository or a single file + log show revision history of entire repository or files manifest output the latest or given revision of the project manifest outgoing show changesets not found in destination parents show the parents of the working dir or revision @@ -186,7 +186,7 @@ diff diff working directory (or selected files) export dump the header and diffs for one or more changesets init create a new repository in the given directory - log show the revision history of the repository or a single file + log show revision history of entire repository or files pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit @@ -206,7 +206,7 @@ diff diff working directory (or selected files) export dump the header and diffs for one or more changesets init create a new repository in the given directory - log show the revision history of the repository or a single file + log show revision history of entire repository or files pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit