##// END OF EJS Templates
incoming/outgoing: handle --graph in core
Patrick Mezard -
r17182:cdf1532d default
parent child Browse files
Show More
@@ -1,125 +1,54 b''
1 # ASCII graph log extension for Mercurial
1 # ASCII graph log extension for Mercurial
2 #
2 #
3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to view revision graphs from a shell
8 '''command to view revision graphs from a shell
9
9
10 This extension adds a --graph option to the incoming, outgoing and log
10 This extension adds a --graph option to the incoming, outgoing and log
11 commands. When this options is given, an ASCII representation of the
11 commands. When this options is given, an ASCII representation of the
12 revision graph is also shown.
12 revision graph is also shown.
13 '''
13 '''
14
14
15 from mercurial.cmdutil import show_changeset
16 from mercurial.i18n import _
15 from mercurial.i18n import _
17 from mercurial import cmdutil, commands, extensions
16 from mercurial import cmdutil, commands
18 from mercurial import hg, util, graphmod
19
17
20 cmdtable = {}
18 cmdtable = {}
21 command = cmdutil.command(cmdtable)
19 command = cmdutil.command(cmdtable)
22 testedwith = 'internal'
20 testedwith = 'internal'
23
21
24 def _checkunsupportedflags(pats, opts):
25 for op in ["newest_first"]:
26 if op in opts and opts[op]:
27 raise util.Abort(_("-G/--graph option is incompatible with --%s")
28 % op.replace("_", "-"))
29
30 @command('glog',
22 @command('glog',
31 [('f', 'follow', None,
23 [('f', 'follow', None,
32 _('follow changeset history, or file history across copies and renames')),
24 _('follow changeset history, or file history across copies and renames')),
33 ('', 'follow-first', None,
25 ('', 'follow-first', None,
34 _('only follow the first parent of merge changesets (DEPRECATED)')),
26 _('only follow the first parent of merge changesets (DEPRECATED)')),
35 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
27 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
36 ('C', 'copies', None, _('show copied files')),
28 ('C', 'copies', None, _('show copied files')),
37 ('k', 'keyword', [],
29 ('k', 'keyword', [],
38 _('do case-insensitive search for a given text'), _('TEXT')),
30 _('do case-insensitive search for a given text'), _('TEXT')),
39 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
31 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
40 ('', 'removed', None, _('include revisions where files were removed')),
32 ('', 'removed', None, _('include revisions where files were removed')),
41 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
33 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
42 ('u', 'user', [], _('revisions committed by user'), _('USER')),
34 ('u', 'user', [], _('revisions committed by user'), _('USER')),
43 ('', 'only-branch', [],
35 ('', 'only-branch', [],
44 _('show only changesets within the given named branch (DEPRECATED)'),
36 _('show only changesets within the given named branch (DEPRECATED)'),
45 _('BRANCH')),
37 _('BRANCH')),
46 ('b', 'branch', [],
38 ('b', 'branch', [],
47 _('show changesets within the given named branch'), _('BRANCH')),
39 _('show changesets within the given named branch'), _('BRANCH')),
48 ('P', 'prune', [],
40 ('P', 'prune', [],
49 _('do not display revision or any of its ancestors'), _('REV')),
41 _('do not display revision or any of its ancestors'), _('REV')),
50 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
42 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
51 ] + commands.logopts + commands.walkopts,
43 ] + commands.logopts + commands.walkopts,
52 _('[OPTION]... [FILE]'))
44 _('[OPTION]... [FILE]'))
53 def graphlog(ui, repo, *pats, **opts):
45 def graphlog(ui, repo, *pats, **opts):
54 """show revision history alongside an ASCII revision graph
46 """show revision history alongside an ASCII revision graph
55
47
56 Print a revision history alongside a revision graph drawn with
48 Print a revision history alongside a revision graph drawn with
57 ASCII characters.
49 ASCII characters.
58
50
59 Nodes printed as an @ character are parents of the working
51 Nodes printed as an @ character are parents of the working
60 directory.
52 directory.
61 """
53 """
62 return cmdutil.graphlog(ui, repo, *pats, **opts)
54 return cmdutil.graphlog(ui, repo, *pats, **opts)
63
64 def graphrevs(repo, nodes, opts):
65 limit = cmdutil.loglimit(opts)
66 nodes.reverse()
67 if limit is not None:
68 nodes = nodes[:limit]
69 return graphmod.nodes(repo, nodes)
70
71 def goutgoing(ui, repo, dest=None, **opts):
72 """show the outgoing changesets alongside an ASCII revision graph
73
74 Print the outgoing changesets alongside a revision graph drawn with
75 ASCII characters.
76
77 Nodes printed as an @ character are parents of the working
78 directory.
79 """
80
81 _checkunsupportedflags([], opts)
82 o = hg._outgoing(ui, repo, dest, opts)
83 if o is None:
84 return
85
86 revdag = graphrevs(repo, o, opts)
87 displayer = show_changeset(ui, repo, opts, buffered=True)
88 showparents = [ctx.node() for ctx in repo[None].parents()]
89 cmdutil.displaygraph(ui, revdag, displayer, showparents,
90 graphmod.asciiedges)
91
92 def gincoming(ui, repo, source="default", **opts):
93 """show the incoming changesets alongside an ASCII revision graph
94
95 Print the incoming changesets alongside a revision graph drawn with
96 ASCII characters.
97
98 Nodes printed as an @ character are parents of the working
99 directory.
100 """
101 def subreporecurse():
102 return 1
103
104 _checkunsupportedflags([], opts)
105 def display(other, chlist, displayer):
106 revdag = graphrevs(other, chlist, opts)
107 showparents = [ctx.node() for ctx in repo[None].parents()]
108 cmdutil.displaygraph(ui, revdag, displayer, showparents,
109 graphmod.asciiedges)
110
111 hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)
112
113 def uisetup(ui):
114 '''Initialize the extension.'''
115 _wrapcmd('incoming', commands.table, gincoming)
116 _wrapcmd('outgoing', commands.table, goutgoing)
117
118 def _wrapcmd(cmd, table, wrapfn):
119 '''wrap the command'''
120 def graph(orig, *args, **kwargs):
121 if kwargs['graph']:
122 return wrapfn(*args, **kwargs)
123 return orig(*args, **kwargs)
124 entry = extensions.wrapcommand(table, cmd, graph)
125 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
@@ -1,1918 +1,1931 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import subrepo, context, repair, bookmarks, graphmod, revset
13 import subrepo, context, repair, bookmarks, graphmod, revset
14
14
15 def parsealiases(cmd):
15 def parsealiases(cmd):
16 return cmd.lstrip("^").split("|")
16 return cmd.lstrip("^").split("|")
17
17
18 def findpossible(cmd, table, strict=False):
18 def findpossible(cmd, table, strict=False):
19 """
19 """
20 Return cmd -> (aliases, command table entry)
20 Return cmd -> (aliases, command table entry)
21 for each matching command.
21 for each matching command.
22 Return debug commands (or their aliases) only if no normal command matches.
22 Return debug commands (or their aliases) only if no normal command matches.
23 """
23 """
24 choice = {}
24 choice = {}
25 debugchoice = {}
25 debugchoice = {}
26
26
27 if cmd in table:
27 if cmd in table:
28 # short-circuit exact matches, "log" alias beats "^log|history"
28 # short-circuit exact matches, "log" alias beats "^log|history"
29 keys = [cmd]
29 keys = [cmd]
30 else:
30 else:
31 keys = table.keys()
31 keys = table.keys()
32
32
33 for e in keys:
33 for e in keys:
34 aliases = parsealiases(e)
34 aliases = parsealiases(e)
35 found = None
35 found = None
36 if cmd in aliases:
36 if cmd in aliases:
37 found = cmd
37 found = cmd
38 elif not strict:
38 elif not strict:
39 for a in aliases:
39 for a in aliases:
40 if a.startswith(cmd):
40 if a.startswith(cmd):
41 found = a
41 found = a
42 break
42 break
43 if found is not None:
43 if found is not None:
44 if aliases[0].startswith("debug") or found.startswith("debug"):
44 if aliases[0].startswith("debug") or found.startswith("debug"):
45 debugchoice[found] = (aliases, table[e])
45 debugchoice[found] = (aliases, table[e])
46 else:
46 else:
47 choice[found] = (aliases, table[e])
47 choice[found] = (aliases, table[e])
48
48
49 if not choice and debugchoice:
49 if not choice and debugchoice:
50 choice = debugchoice
50 choice = debugchoice
51
51
52 return choice
52 return choice
53
53
54 def findcmd(cmd, table, strict=True):
54 def findcmd(cmd, table, strict=True):
55 """Return (aliases, command table entry) for command string."""
55 """Return (aliases, command table entry) for command string."""
56 choice = findpossible(cmd, table, strict)
56 choice = findpossible(cmd, table, strict)
57
57
58 if cmd in choice:
58 if cmd in choice:
59 return choice[cmd]
59 return choice[cmd]
60
60
61 if len(choice) > 1:
61 if len(choice) > 1:
62 clist = choice.keys()
62 clist = choice.keys()
63 clist.sort()
63 clist.sort()
64 raise error.AmbiguousCommand(cmd, clist)
64 raise error.AmbiguousCommand(cmd, clist)
65
65
66 if choice:
66 if choice:
67 return choice.values()[0]
67 return choice.values()[0]
68
68
69 raise error.UnknownCommand(cmd)
69 raise error.UnknownCommand(cmd)
70
70
71 def findrepo(p):
71 def findrepo(p):
72 while not os.path.isdir(os.path.join(p, ".hg")):
72 while not os.path.isdir(os.path.join(p, ".hg")):
73 oldp, p = p, os.path.dirname(p)
73 oldp, p = p, os.path.dirname(p)
74 if p == oldp:
74 if p == oldp:
75 return None
75 return None
76
76
77 return p
77 return p
78
78
79 def bailifchanged(repo):
79 def bailifchanged(repo):
80 if repo.dirstate.p2() != nullid:
80 if repo.dirstate.p2() != nullid:
81 raise util.Abort(_('outstanding uncommitted merge'))
81 raise util.Abort(_('outstanding uncommitted merge'))
82 modified, added, removed, deleted = repo.status()[:4]
82 modified, added, removed, deleted = repo.status()[:4]
83 if modified or added or removed or deleted:
83 if modified or added or removed or deleted:
84 raise util.Abort(_("outstanding uncommitted changes"))
84 raise util.Abort(_("outstanding uncommitted changes"))
85 ctx = repo[None]
85 ctx = repo[None]
86 for s in ctx.substate:
86 for s in ctx.substate:
87 if ctx.sub(s).dirty():
87 if ctx.sub(s).dirty():
88 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
88 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
89
89
90 def logmessage(ui, opts):
90 def logmessage(ui, opts):
91 """ get the log message according to -m and -l option """
91 """ get the log message according to -m and -l option """
92 message = opts.get('message')
92 message = opts.get('message')
93 logfile = opts.get('logfile')
93 logfile = opts.get('logfile')
94
94
95 if message and logfile:
95 if message and logfile:
96 raise util.Abort(_('options --message and --logfile are mutually '
96 raise util.Abort(_('options --message and --logfile are mutually '
97 'exclusive'))
97 'exclusive'))
98 if not message and logfile:
98 if not message and logfile:
99 try:
99 try:
100 if logfile == '-':
100 if logfile == '-':
101 message = ui.fin.read()
101 message = ui.fin.read()
102 else:
102 else:
103 message = '\n'.join(util.readfile(logfile).splitlines())
103 message = '\n'.join(util.readfile(logfile).splitlines())
104 except IOError, inst:
104 except IOError, inst:
105 raise util.Abort(_("can't read commit message '%s': %s") %
105 raise util.Abort(_("can't read commit message '%s': %s") %
106 (logfile, inst.strerror))
106 (logfile, inst.strerror))
107 return message
107 return message
108
108
109 def loglimit(opts):
109 def loglimit(opts):
110 """get the log limit according to option -l/--limit"""
110 """get the log limit according to option -l/--limit"""
111 limit = opts.get('limit')
111 limit = opts.get('limit')
112 if limit:
112 if limit:
113 try:
113 try:
114 limit = int(limit)
114 limit = int(limit)
115 except ValueError:
115 except ValueError:
116 raise util.Abort(_('limit must be a positive integer'))
116 raise util.Abort(_('limit must be a positive integer'))
117 if limit <= 0:
117 if limit <= 0:
118 raise util.Abort(_('limit must be positive'))
118 raise util.Abort(_('limit must be positive'))
119 else:
119 else:
120 limit = None
120 limit = None
121 return limit
121 return limit
122
122
123 def makefilename(repo, pat, node, desc=None,
123 def makefilename(repo, pat, node, desc=None,
124 total=None, seqno=None, revwidth=None, pathname=None):
124 total=None, seqno=None, revwidth=None, pathname=None):
125 node_expander = {
125 node_expander = {
126 'H': lambda: hex(node),
126 'H': lambda: hex(node),
127 'R': lambda: str(repo.changelog.rev(node)),
127 'R': lambda: str(repo.changelog.rev(node)),
128 'h': lambda: short(node),
128 'h': lambda: short(node),
129 'm': lambda: re.sub('[^\w]', '_', str(desc))
129 'm': lambda: re.sub('[^\w]', '_', str(desc))
130 }
130 }
131 expander = {
131 expander = {
132 '%': lambda: '%',
132 '%': lambda: '%',
133 'b': lambda: os.path.basename(repo.root),
133 'b': lambda: os.path.basename(repo.root),
134 }
134 }
135
135
136 try:
136 try:
137 if node:
137 if node:
138 expander.update(node_expander)
138 expander.update(node_expander)
139 if node:
139 if node:
140 expander['r'] = (lambda:
140 expander['r'] = (lambda:
141 str(repo.changelog.rev(node)).zfill(revwidth or 0))
141 str(repo.changelog.rev(node)).zfill(revwidth or 0))
142 if total is not None:
142 if total is not None:
143 expander['N'] = lambda: str(total)
143 expander['N'] = lambda: str(total)
144 if seqno is not None:
144 if seqno is not None:
145 expander['n'] = lambda: str(seqno)
145 expander['n'] = lambda: str(seqno)
146 if total is not None and seqno is not None:
146 if total is not None and seqno is not None:
147 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
147 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
148 if pathname is not None:
148 if pathname is not None:
149 expander['s'] = lambda: os.path.basename(pathname)
149 expander['s'] = lambda: os.path.basename(pathname)
150 expander['d'] = lambda: os.path.dirname(pathname) or '.'
150 expander['d'] = lambda: os.path.dirname(pathname) or '.'
151 expander['p'] = lambda: pathname
151 expander['p'] = lambda: pathname
152
152
153 newname = []
153 newname = []
154 patlen = len(pat)
154 patlen = len(pat)
155 i = 0
155 i = 0
156 while i < patlen:
156 while i < patlen:
157 c = pat[i]
157 c = pat[i]
158 if c == '%':
158 if c == '%':
159 i += 1
159 i += 1
160 c = pat[i]
160 c = pat[i]
161 c = expander[c]()
161 c = expander[c]()
162 newname.append(c)
162 newname.append(c)
163 i += 1
163 i += 1
164 return ''.join(newname)
164 return ''.join(newname)
165 except KeyError, inst:
165 except KeyError, inst:
166 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
166 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
167 inst.args[0])
167 inst.args[0])
168
168
169 def makefileobj(repo, pat, node=None, desc=None, total=None,
169 def makefileobj(repo, pat, node=None, desc=None, total=None,
170 seqno=None, revwidth=None, mode='wb', pathname=None):
170 seqno=None, revwidth=None, mode='wb', pathname=None):
171
171
172 writable = mode not in ('r', 'rb')
172 writable = mode not in ('r', 'rb')
173
173
174 if not pat or pat == '-':
174 if not pat or pat == '-':
175 fp = writable and repo.ui.fout or repo.ui.fin
175 fp = writable and repo.ui.fout or repo.ui.fin
176 if util.safehasattr(fp, 'fileno'):
176 if util.safehasattr(fp, 'fileno'):
177 return os.fdopen(os.dup(fp.fileno()), mode)
177 return os.fdopen(os.dup(fp.fileno()), mode)
178 else:
178 else:
179 # if this fp can't be duped properly, return
179 # if this fp can't be duped properly, return
180 # a dummy object that can be closed
180 # a dummy object that can be closed
181 class wrappedfileobj(object):
181 class wrappedfileobj(object):
182 noop = lambda x: None
182 noop = lambda x: None
183 def __init__(self, f):
183 def __init__(self, f):
184 self.f = f
184 self.f = f
185 def __getattr__(self, attr):
185 def __getattr__(self, attr):
186 if attr == 'close':
186 if attr == 'close':
187 return self.noop
187 return self.noop
188 else:
188 else:
189 return getattr(self.f, attr)
189 return getattr(self.f, attr)
190
190
191 return wrappedfileobj(fp)
191 return wrappedfileobj(fp)
192 if util.safehasattr(pat, 'write') and writable:
192 if util.safehasattr(pat, 'write') and writable:
193 return pat
193 return pat
194 if util.safehasattr(pat, 'read') and 'r' in mode:
194 if util.safehasattr(pat, 'read') and 'r' in mode:
195 return pat
195 return pat
196 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
196 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
197 pathname),
197 pathname),
198 mode)
198 mode)
199
199
200 def openrevlog(repo, cmd, file_, opts):
200 def openrevlog(repo, cmd, file_, opts):
201 """opens the changelog, manifest, a filelog or a given revlog"""
201 """opens the changelog, manifest, a filelog or a given revlog"""
202 cl = opts['changelog']
202 cl = opts['changelog']
203 mf = opts['manifest']
203 mf = opts['manifest']
204 msg = None
204 msg = None
205 if cl and mf:
205 if cl and mf:
206 msg = _('cannot specify --changelog and --manifest at the same time')
206 msg = _('cannot specify --changelog and --manifest at the same time')
207 elif cl or mf:
207 elif cl or mf:
208 if file_:
208 if file_:
209 msg = _('cannot specify filename with --changelog or --manifest')
209 msg = _('cannot specify filename with --changelog or --manifest')
210 elif not repo:
210 elif not repo:
211 msg = _('cannot specify --changelog or --manifest '
211 msg = _('cannot specify --changelog or --manifest '
212 'without a repository')
212 'without a repository')
213 if msg:
213 if msg:
214 raise util.Abort(msg)
214 raise util.Abort(msg)
215
215
216 r = None
216 r = None
217 if repo:
217 if repo:
218 if cl:
218 if cl:
219 r = repo.changelog
219 r = repo.changelog
220 elif mf:
220 elif mf:
221 r = repo.manifest
221 r = repo.manifest
222 elif file_:
222 elif file_:
223 filelog = repo.file(file_)
223 filelog = repo.file(file_)
224 if len(filelog):
224 if len(filelog):
225 r = filelog
225 r = filelog
226 if not r:
226 if not r:
227 if not file_:
227 if not file_:
228 raise error.CommandError(cmd, _('invalid arguments'))
228 raise error.CommandError(cmd, _('invalid arguments'))
229 if not os.path.isfile(file_):
229 if not os.path.isfile(file_):
230 raise util.Abort(_("revlog '%s' not found") % file_)
230 raise util.Abort(_("revlog '%s' not found") % file_)
231 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
231 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
232 file_[:-2] + ".i")
232 file_[:-2] + ".i")
233 return r
233 return r
234
234
235 def copy(ui, repo, pats, opts, rename=False):
235 def copy(ui, repo, pats, opts, rename=False):
236 # called with the repo lock held
236 # called with the repo lock held
237 #
237 #
238 # hgsep => pathname that uses "/" to separate directories
238 # hgsep => pathname that uses "/" to separate directories
239 # ossep => pathname that uses os.sep to separate directories
239 # ossep => pathname that uses os.sep to separate directories
240 cwd = repo.getcwd()
240 cwd = repo.getcwd()
241 targets = {}
241 targets = {}
242 after = opts.get("after")
242 after = opts.get("after")
243 dryrun = opts.get("dry_run")
243 dryrun = opts.get("dry_run")
244 wctx = repo[None]
244 wctx = repo[None]
245
245
246 def walkpat(pat):
246 def walkpat(pat):
247 srcs = []
247 srcs = []
248 badstates = after and '?' or '?r'
248 badstates = after and '?' or '?r'
249 m = scmutil.match(repo[None], [pat], opts, globbed=True)
249 m = scmutil.match(repo[None], [pat], opts, globbed=True)
250 for abs in repo.walk(m):
250 for abs in repo.walk(m):
251 state = repo.dirstate[abs]
251 state = repo.dirstate[abs]
252 rel = m.rel(abs)
252 rel = m.rel(abs)
253 exact = m.exact(abs)
253 exact = m.exact(abs)
254 if state in badstates:
254 if state in badstates:
255 if exact and state == '?':
255 if exact and state == '?':
256 ui.warn(_('%s: not copying - file is not managed\n') % rel)
256 ui.warn(_('%s: not copying - file is not managed\n') % rel)
257 if exact and state == 'r':
257 if exact and state == 'r':
258 ui.warn(_('%s: not copying - file has been marked for'
258 ui.warn(_('%s: not copying - file has been marked for'
259 ' remove\n') % rel)
259 ' remove\n') % rel)
260 continue
260 continue
261 # abs: hgsep
261 # abs: hgsep
262 # rel: ossep
262 # rel: ossep
263 srcs.append((abs, rel, exact))
263 srcs.append((abs, rel, exact))
264 return srcs
264 return srcs
265
265
266 # abssrc: hgsep
266 # abssrc: hgsep
267 # relsrc: ossep
267 # relsrc: ossep
268 # otarget: ossep
268 # otarget: ossep
269 def copyfile(abssrc, relsrc, otarget, exact):
269 def copyfile(abssrc, relsrc, otarget, exact):
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
271 if '/' in abstarget:
271 if '/' in abstarget:
272 # We cannot normalize abstarget itself, this would prevent
272 # We cannot normalize abstarget itself, this would prevent
273 # case only renames, like a => A.
273 # case only renames, like a => A.
274 abspath, absname = abstarget.rsplit('/', 1)
274 abspath, absname = abstarget.rsplit('/', 1)
275 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
275 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
276 reltarget = repo.pathto(abstarget, cwd)
276 reltarget = repo.pathto(abstarget, cwd)
277 target = repo.wjoin(abstarget)
277 target = repo.wjoin(abstarget)
278 src = repo.wjoin(abssrc)
278 src = repo.wjoin(abssrc)
279 state = repo.dirstate[abstarget]
279 state = repo.dirstate[abstarget]
280
280
281 scmutil.checkportable(ui, abstarget)
281 scmutil.checkportable(ui, abstarget)
282
282
283 # check for collisions
283 # check for collisions
284 prevsrc = targets.get(abstarget)
284 prevsrc = targets.get(abstarget)
285 if prevsrc is not None:
285 if prevsrc is not None:
286 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
286 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
287 (reltarget, repo.pathto(abssrc, cwd),
287 (reltarget, repo.pathto(abssrc, cwd),
288 repo.pathto(prevsrc, cwd)))
288 repo.pathto(prevsrc, cwd)))
289 return
289 return
290
290
291 # check for overwrites
291 # check for overwrites
292 exists = os.path.lexists(target)
292 exists = os.path.lexists(target)
293 samefile = False
293 samefile = False
294 if exists and abssrc != abstarget:
294 if exists and abssrc != abstarget:
295 if (repo.dirstate.normalize(abssrc) ==
295 if (repo.dirstate.normalize(abssrc) ==
296 repo.dirstate.normalize(abstarget)):
296 repo.dirstate.normalize(abstarget)):
297 if not rename:
297 if not rename:
298 ui.warn(_("%s: can't copy - same file\n") % reltarget)
298 ui.warn(_("%s: can't copy - same file\n") % reltarget)
299 return
299 return
300 exists = False
300 exists = False
301 samefile = True
301 samefile = True
302
302
303 if not after and exists or after and state in 'mn':
303 if not after and exists or after and state in 'mn':
304 if not opts['force']:
304 if not opts['force']:
305 ui.warn(_('%s: not overwriting - file exists\n') %
305 ui.warn(_('%s: not overwriting - file exists\n') %
306 reltarget)
306 reltarget)
307 return
307 return
308
308
309 if after:
309 if after:
310 if not exists:
310 if not exists:
311 if rename:
311 if rename:
312 ui.warn(_('%s: not recording move - %s does not exist\n') %
312 ui.warn(_('%s: not recording move - %s does not exist\n') %
313 (relsrc, reltarget))
313 (relsrc, reltarget))
314 else:
314 else:
315 ui.warn(_('%s: not recording copy - %s does not exist\n') %
315 ui.warn(_('%s: not recording copy - %s does not exist\n') %
316 (relsrc, reltarget))
316 (relsrc, reltarget))
317 return
317 return
318 elif not dryrun:
318 elif not dryrun:
319 try:
319 try:
320 if exists:
320 if exists:
321 os.unlink(target)
321 os.unlink(target)
322 targetdir = os.path.dirname(target) or '.'
322 targetdir = os.path.dirname(target) or '.'
323 if not os.path.isdir(targetdir):
323 if not os.path.isdir(targetdir):
324 os.makedirs(targetdir)
324 os.makedirs(targetdir)
325 if samefile:
325 if samefile:
326 tmp = target + "~hgrename"
326 tmp = target + "~hgrename"
327 os.rename(src, tmp)
327 os.rename(src, tmp)
328 os.rename(tmp, target)
328 os.rename(tmp, target)
329 else:
329 else:
330 util.copyfile(src, target)
330 util.copyfile(src, target)
331 srcexists = True
331 srcexists = True
332 except IOError, inst:
332 except IOError, inst:
333 if inst.errno == errno.ENOENT:
333 if inst.errno == errno.ENOENT:
334 ui.warn(_('%s: deleted in working copy\n') % relsrc)
334 ui.warn(_('%s: deleted in working copy\n') % relsrc)
335 srcexists = False
335 srcexists = False
336 else:
336 else:
337 ui.warn(_('%s: cannot copy - %s\n') %
337 ui.warn(_('%s: cannot copy - %s\n') %
338 (relsrc, inst.strerror))
338 (relsrc, inst.strerror))
339 return True # report a failure
339 return True # report a failure
340
340
341 if ui.verbose or not exact:
341 if ui.verbose or not exact:
342 if rename:
342 if rename:
343 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
343 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
344 else:
344 else:
345 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
345 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
346
346
347 targets[abstarget] = abssrc
347 targets[abstarget] = abssrc
348
348
349 # fix up dirstate
349 # fix up dirstate
350 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
350 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
351 dryrun=dryrun, cwd=cwd)
351 dryrun=dryrun, cwd=cwd)
352 if rename and not dryrun:
352 if rename and not dryrun:
353 if not after and srcexists and not samefile:
353 if not after and srcexists and not samefile:
354 util.unlinkpath(repo.wjoin(abssrc))
354 util.unlinkpath(repo.wjoin(abssrc))
355 wctx.forget([abssrc])
355 wctx.forget([abssrc])
356
356
357 # pat: ossep
357 # pat: ossep
358 # dest ossep
358 # dest ossep
359 # srcs: list of (hgsep, hgsep, ossep, bool)
359 # srcs: list of (hgsep, hgsep, ossep, bool)
360 # return: function that takes hgsep and returns ossep
360 # return: function that takes hgsep and returns ossep
361 def targetpathfn(pat, dest, srcs):
361 def targetpathfn(pat, dest, srcs):
362 if os.path.isdir(pat):
362 if os.path.isdir(pat):
363 abspfx = scmutil.canonpath(repo.root, cwd, pat)
363 abspfx = scmutil.canonpath(repo.root, cwd, pat)
364 abspfx = util.localpath(abspfx)
364 abspfx = util.localpath(abspfx)
365 if destdirexists:
365 if destdirexists:
366 striplen = len(os.path.split(abspfx)[0])
366 striplen = len(os.path.split(abspfx)[0])
367 else:
367 else:
368 striplen = len(abspfx)
368 striplen = len(abspfx)
369 if striplen:
369 if striplen:
370 striplen += len(os.sep)
370 striplen += len(os.sep)
371 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
371 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
372 elif destdirexists:
372 elif destdirexists:
373 res = lambda p: os.path.join(dest,
373 res = lambda p: os.path.join(dest,
374 os.path.basename(util.localpath(p)))
374 os.path.basename(util.localpath(p)))
375 else:
375 else:
376 res = lambda p: dest
376 res = lambda p: dest
377 return res
377 return res
378
378
379 # pat: ossep
379 # pat: ossep
380 # dest ossep
380 # dest ossep
381 # srcs: list of (hgsep, hgsep, ossep, bool)
381 # srcs: list of (hgsep, hgsep, ossep, bool)
382 # return: function that takes hgsep and returns ossep
382 # return: function that takes hgsep and returns ossep
383 def targetpathafterfn(pat, dest, srcs):
383 def targetpathafterfn(pat, dest, srcs):
384 if matchmod.patkind(pat):
384 if matchmod.patkind(pat):
385 # a mercurial pattern
385 # a mercurial pattern
386 res = lambda p: os.path.join(dest,
386 res = lambda p: os.path.join(dest,
387 os.path.basename(util.localpath(p)))
387 os.path.basename(util.localpath(p)))
388 else:
388 else:
389 abspfx = scmutil.canonpath(repo.root, cwd, pat)
389 abspfx = scmutil.canonpath(repo.root, cwd, pat)
390 if len(abspfx) < len(srcs[0][0]):
390 if len(abspfx) < len(srcs[0][0]):
391 # A directory. Either the target path contains the last
391 # A directory. Either the target path contains the last
392 # component of the source path or it does not.
392 # component of the source path or it does not.
393 def evalpath(striplen):
393 def evalpath(striplen):
394 score = 0
394 score = 0
395 for s in srcs:
395 for s in srcs:
396 t = os.path.join(dest, util.localpath(s[0])[striplen:])
396 t = os.path.join(dest, util.localpath(s[0])[striplen:])
397 if os.path.lexists(t):
397 if os.path.lexists(t):
398 score += 1
398 score += 1
399 return score
399 return score
400
400
401 abspfx = util.localpath(abspfx)
401 abspfx = util.localpath(abspfx)
402 striplen = len(abspfx)
402 striplen = len(abspfx)
403 if striplen:
403 if striplen:
404 striplen += len(os.sep)
404 striplen += len(os.sep)
405 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
405 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
406 score = evalpath(striplen)
406 score = evalpath(striplen)
407 striplen1 = len(os.path.split(abspfx)[0])
407 striplen1 = len(os.path.split(abspfx)[0])
408 if striplen1:
408 if striplen1:
409 striplen1 += len(os.sep)
409 striplen1 += len(os.sep)
410 if evalpath(striplen1) > score:
410 if evalpath(striplen1) > score:
411 striplen = striplen1
411 striplen = striplen1
412 res = lambda p: os.path.join(dest,
412 res = lambda p: os.path.join(dest,
413 util.localpath(p)[striplen:])
413 util.localpath(p)[striplen:])
414 else:
414 else:
415 # a file
415 # a file
416 if destdirexists:
416 if destdirexists:
417 res = lambda p: os.path.join(dest,
417 res = lambda p: os.path.join(dest,
418 os.path.basename(util.localpath(p)))
418 os.path.basename(util.localpath(p)))
419 else:
419 else:
420 res = lambda p: dest
420 res = lambda p: dest
421 return res
421 return res
422
422
423
423
424 pats = scmutil.expandpats(pats)
424 pats = scmutil.expandpats(pats)
425 if not pats:
425 if not pats:
426 raise util.Abort(_('no source or destination specified'))
426 raise util.Abort(_('no source or destination specified'))
427 if len(pats) == 1:
427 if len(pats) == 1:
428 raise util.Abort(_('no destination specified'))
428 raise util.Abort(_('no destination specified'))
429 dest = pats.pop()
429 dest = pats.pop()
430 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
430 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
431 if not destdirexists:
431 if not destdirexists:
432 if len(pats) > 1 or matchmod.patkind(pats[0]):
432 if len(pats) > 1 or matchmod.patkind(pats[0]):
433 raise util.Abort(_('with multiple sources, destination must be an '
433 raise util.Abort(_('with multiple sources, destination must be an '
434 'existing directory'))
434 'existing directory'))
435 if util.endswithsep(dest):
435 if util.endswithsep(dest):
436 raise util.Abort(_('destination %s is not a directory') % dest)
436 raise util.Abort(_('destination %s is not a directory') % dest)
437
437
438 tfn = targetpathfn
438 tfn = targetpathfn
439 if after:
439 if after:
440 tfn = targetpathafterfn
440 tfn = targetpathafterfn
441 copylist = []
441 copylist = []
442 for pat in pats:
442 for pat in pats:
443 srcs = walkpat(pat)
443 srcs = walkpat(pat)
444 if not srcs:
444 if not srcs:
445 continue
445 continue
446 copylist.append((tfn(pat, dest, srcs), srcs))
446 copylist.append((tfn(pat, dest, srcs), srcs))
447 if not copylist:
447 if not copylist:
448 raise util.Abort(_('no files to copy'))
448 raise util.Abort(_('no files to copy'))
449
449
450 errors = 0
450 errors = 0
451 for targetpath, srcs in copylist:
451 for targetpath, srcs in copylist:
452 for abssrc, relsrc, exact in srcs:
452 for abssrc, relsrc, exact in srcs:
453 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
453 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
454 errors += 1
454 errors += 1
455
455
456 if errors:
456 if errors:
457 ui.warn(_('(consider using --after)\n'))
457 ui.warn(_('(consider using --after)\n'))
458
458
459 return errors != 0
459 return errors != 0
460
460
461 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
461 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
462 runargs=None, appendpid=False):
462 runargs=None, appendpid=False):
463 '''Run a command as a service.'''
463 '''Run a command as a service.'''
464
464
465 if opts['daemon'] and not opts['daemon_pipefds']:
465 if opts['daemon'] and not opts['daemon_pipefds']:
466 # Signal child process startup with file removal
466 # Signal child process startup with file removal
467 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
467 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
468 os.close(lockfd)
468 os.close(lockfd)
469 try:
469 try:
470 if not runargs:
470 if not runargs:
471 runargs = util.hgcmd() + sys.argv[1:]
471 runargs = util.hgcmd() + sys.argv[1:]
472 runargs.append('--daemon-pipefds=%s' % lockpath)
472 runargs.append('--daemon-pipefds=%s' % lockpath)
473 # Don't pass --cwd to the child process, because we've already
473 # Don't pass --cwd to the child process, because we've already
474 # changed directory.
474 # changed directory.
475 for i in xrange(1, len(runargs)):
475 for i in xrange(1, len(runargs)):
476 if runargs[i].startswith('--cwd='):
476 if runargs[i].startswith('--cwd='):
477 del runargs[i]
477 del runargs[i]
478 break
478 break
479 elif runargs[i].startswith('--cwd'):
479 elif runargs[i].startswith('--cwd'):
480 del runargs[i:i + 2]
480 del runargs[i:i + 2]
481 break
481 break
482 def condfn():
482 def condfn():
483 return not os.path.exists(lockpath)
483 return not os.path.exists(lockpath)
484 pid = util.rundetached(runargs, condfn)
484 pid = util.rundetached(runargs, condfn)
485 if pid < 0:
485 if pid < 0:
486 raise util.Abort(_('child process failed to start'))
486 raise util.Abort(_('child process failed to start'))
487 finally:
487 finally:
488 try:
488 try:
489 os.unlink(lockpath)
489 os.unlink(lockpath)
490 except OSError, e:
490 except OSError, e:
491 if e.errno != errno.ENOENT:
491 if e.errno != errno.ENOENT:
492 raise
492 raise
493 if parentfn:
493 if parentfn:
494 return parentfn(pid)
494 return parentfn(pid)
495 else:
495 else:
496 return
496 return
497
497
498 if initfn:
498 if initfn:
499 initfn()
499 initfn()
500
500
501 if opts['pid_file']:
501 if opts['pid_file']:
502 mode = appendpid and 'a' or 'w'
502 mode = appendpid and 'a' or 'w'
503 fp = open(opts['pid_file'], mode)
503 fp = open(opts['pid_file'], mode)
504 fp.write(str(os.getpid()) + '\n')
504 fp.write(str(os.getpid()) + '\n')
505 fp.close()
505 fp.close()
506
506
507 if opts['daemon_pipefds']:
507 if opts['daemon_pipefds']:
508 lockpath = opts['daemon_pipefds']
508 lockpath = opts['daemon_pipefds']
509 try:
509 try:
510 os.setsid()
510 os.setsid()
511 except AttributeError:
511 except AttributeError:
512 pass
512 pass
513 os.unlink(lockpath)
513 os.unlink(lockpath)
514 util.hidewindow()
514 util.hidewindow()
515 sys.stdout.flush()
515 sys.stdout.flush()
516 sys.stderr.flush()
516 sys.stderr.flush()
517
517
518 nullfd = os.open(util.nulldev, os.O_RDWR)
518 nullfd = os.open(util.nulldev, os.O_RDWR)
519 logfilefd = nullfd
519 logfilefd = nullfd
520 if logfile:
520 if logfile:
521 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
521 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
522 os.dup2(nullfd, 0)
522 os.dup2(nullfd, 0)
523 os.dup2(logfilefd, 1)
523 os.dup2(logfilefd, 1)
524 os.dup2(logfilefd, 2)
524 os.dup2(logfilefd, 2)
525 if nullfd not in (0, 1, 2):
525 if nullfd not in (0, 1, 2):
526 os.close(nullfd)
526 os.close(nullfd)
527 if logfile and logfilefd not in (0, 1, 2):
527 if logfile and logfilefd not in (0, 1, 2):
528 os.close(logfilefd)
528 os.close(logfilefd)
529
529
530 if runfn:
530 if runfn:
531 return runfn()
531 return runfn()
532
532
533 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
533 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
534 opts=None):
534 opts=None):
535 '''export changesets as hg patches.'''
535 '''export changesets as hg patches.'''
536
536
537 total = len(revs)
537 total = len(revs)
538 revwidth = max([len(str(rev)) for rev in revs])
538 revwidth = max([len(str(rev)) for rev in revs])
539
539
540 def single(rev, seqno, fp):
540 def single(rev, seqno, fp):
541 ctx = repo[rev]
541 ctx = repo[rev]
542 node = ctx.node()
542 node = ctx.node()
543 parents = [p.node() for p in ctx.parents() if p]
543 parents = [p.node() for p in ctx.parents() if p]
544 branch = ctx.branch()
544 branch = ctx.branch()
545 if switch_parent:
545 if switch_parent:
546 parents.reverse()
546 parents.reverse()
547 prev = (parents and parents[0]) or nullid
547 prev = (parents and parents[0]) or nullid
548
548
549 shouldclose = False
549 shouldclose = False
550 if not fp:
550 if not fp:
551 desc_lines = ctx.description().rstrip().split('\n')
551 desc_lines = ctx.description().rstrip().split('\n')
552 desc = desc_lines[0] #Commit always has a first line.
552 desc = desc_lines[0] #Commit always has a first line.
553 fp = makefileobj(repo, template, node, desc=desc, total=total,
553 fp = makefileobj(repo, template, node, desc=desc, total=total,
554 seqno=seqno, revwidth=revwidth, mode='ab')
554 seqno=seqno, revwidth=revwidth, mode='ab')
555 if fp != template:
555 if fp != template:
556 shouldclose = True
556 shouldclose = True
557 if fp != sys.stdout and util.safehasattr(fp, 'name'):
557 if fp != sys.stdout and util.safehasattr(fp, 'name'):
558 repo.ui.note("%s\n" % fp.name)
558 repo.ui.note("%s\n" % fp.name)
559
559
560 fp.write("# HG changeset patch\n")
560 fp.write("# HG changeset patch\n")
561 fp.write("# User %s\n" % ctx.user())
561 fp.write("# User %s\n" % ctx.user())
562 fp.write("# Date %d %d\n" % ctx.date())
562 fp.write("# Date %d %d\n" % ctx.date())
563 if branch and branch != 'default':
563 if branch and branch != 'default':
564 fp.write("# Branch %s\n" % branch)
564 fp.write("# Branch %s\n" % branch)
565 fp.write("# Node ID %s\n" % hex(node))
565 fp.write("# Node ID %s\n" % hex(node))
566 fp.write("# Parent %s\n" % hex(prev))
566 fp.write("# Parent %s\n" % hex(prev))
567 if len(parents) > 1:
567 if len(parents) > 1:
568 fp.write("# Parent %s\n" % hex(parents[1]))
568 fp.write("# Parent %s\n" % hex(parents[1]))
569 fp.write(ctx.description().rstrip())
569 fp.write(ctx.description().rstrip())
570 fp.write("\n\n")
570 fp.write("\n\n")
571
571
572 for chunk in patch.diff(repo, prev, node, opts=opts):
572 for chunk in patch.diff(repo, prev, node, opts=opts):
573 fp.write(chunk)
573 fp.write(chunk)
574
574
575 if shouldclose:
575 if shouldclose:
576 fp.close()
576 fp.close()
577
577
578 for seqno, rev in enumerate(revs):
578 for seqno, rev in enumerate(revs):
579 single(rev, seqno + 1, fp)
579 single(rev, seqno + 1, fp)
580
580
581 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
581 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
582 changes=None, stat=False, fp=None, prefix='',
582 changes=None, stat=False, fp=None, prefix='',
583 listsubrepos=False):
583 listsubrepos=False):
584 '''show diff or diffstat.'''
584 '''show diff or diffstat.'''
585 if fp is None:
585 if fp is None:
586 write = ui.write
586 write = ui.write
587 else:
587 else:
588 def write(s, **kw):
588 def write(s, **kw):
589 fp.write(s)
589 fp.write(s)
590
590
591 if stat:
591 if stat:
592 diffopts = diffopts.copy(context=0)
592 diffopts = diffopts.copy(context=0)
593 width = 80
593 width = 80
594 if not ui.plain():
594 if not ui.plain():
595 width = ui.termwidth()
595 width = ui.termwidth()
596 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
596 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
597 prefix=prefix)
597 prefix=prefix)
598 for chunk, label in patch.diffstatui(util.iterlines(chunks),
598 for chunk, label in patch.diffstatui(util.iterlines(chunks),
599 width=width,
599 width=width,
600 git=diffopts.git):
600 git=diffopts.git):
601 write(chunk, label=label)
601 write(chunk, label=label)
602 else:
602 else:
603 for chunk, label in patch.diffui(repo, node1, node2, match,
603 for chunk, label in patch.diffui(repo, node1, node2, match,
604 changes, diffopts, prefix=prefix):
604 changes, diffopts, prefix=prefix):
605 write(chunk, label=label)
605 write(chunk, label=label)
606
606
607 if listsubrepos:
607 if listsubrepos:
608 ctx1 = repo[node1]
608 ctx1 = repo[node1]
609 ctx2 = repo[node2]
609 ctx2 = repo[node2]
610 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
610 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
611 tempnode2 = node2
611 tempnode2 = node2
612 try:
612 try:
613 if node2 is not None:
613 if node2 is not None:
614 tempnode2 = ctx2.substate[subpath][1]
614 tempnode2 = ctx2.substate[subpath][1]
615 except KeyError:
615 except KeyError:
616 # A subrepo that existed in node1 was deleted between node1 and
616 # A subrepo that existed in node1 was deleted between node1 and
617 # node2 (inclusive). Thus, ctx2's substate won't contain that
617 # node2 (inclusive). Thus, ctx2's substate won't contain that
618 # subpath. The best we can do is to ignore it.
618 # subpath. The best we can do is to ignore it.
619 tempnode2 = None
619 tempnode2 = None
620 submatch = matchmod.narrowmatcher(subpath, match)
620 submatch = matchmod.narrowmatcher(subpath, match)
621 sub.diff(diffopts, tempnode2, submatch, changes=changes,
621 sub.diff(diffopts, tempnode2, submatch, changes=changes,
622 stat=stat, fp=fp, prefix=prefix)
622 stat=stat, fp=fp, prefix=prefix)
623
623
624 class changeset_printer(object):
624 class changeset_printer(object):
625 '''show changeset information when templating not requested.'''
625 '''show changeset information when templating not requested.'''
626
626
627 def __init__(self, ui, repo, patch, diffopts, buffered):
627 def __init__(self, ui, repo, patch, diffopts, buffered):
628 self.ui = ui
628 self.ui = ui
629 self.repo = repo
629 self.repo = repo
630 self.buffered = buffered
630 self.buffered = buffered
631 self.patch = patch
631 self.patch = patch
632 self.diffopts = diffopts
632 self.diffopts = diffopts
633 self.header = {}
633 self.header = {}
634 self.hunk = {}
634 self.hunk = {}
635 self.lastheader = None
635 self.lastheader = None
636 self.footer = None
636 self.footer = None
637
637
638 def flush(self, rev):
638 def flush(self, rev):
639 if rev in self.header:
639 if rev in self.header:
640 h = self.header[rev]
640 h = self.header[rev]
641 if h != self.lastheader:
641 if h != self.lastheader:
642 self.lastheader = h
642 self.lastheader = h
643 self.ui.write(h)
643 self.ui.write(h)
644 del self.header[rev]
644 del self.header[rev]
645 if rev in self.hunk:
645 if rev in self.hunk:
646 self.ui.write(self.hunk[rev])
646 self.ui.write(self.hunk[rev])
647 del self.hunk[rev]
647 del self.hunk[rev]
648 return 1
648 return 1
649 return 0
649 return 0
650
650
651 def close(self):
651 def close(self):
652 if self.footer:
652 if self.footer:
653 self.ui.write(self.footer)
653 self.ui.write(self.footer)
654
654
655 def show(self, ctx, copies=None, matchfn=None, **props):
655 def show(self, ctx, copies=None, matchfn=None, **props):
656 if self.buffered:
656 if self.buffered:
657 self.ui.pushbuffer()
657 self.ui.pushbuffer()
658 self._show(ctx, copies, matchfn, props)
658 self._show(ctx, copies, matchfn, props)
659 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
659 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
660 else:
660 else:
661 self._show(ctx, copies, matchfn, props)
661 self._show(ctx, copies, matchfn, props)
662
662
663 def _show(self, ctx, copies, matchfn, props):
663 def _show(self, ctx, copies, matchfn, props):
664 '''show a single changeset or file revision'''
664 '''show a single changeset or file revision'''
665 changenode = ctx.node()
665 changenode = ctx.node()
666 rev = ctx.rev()
666 rev = ctx.rev()
667
667
668 if self.ui.quiet:
668 if self.ui.quiet:
669 self.ui.write("%d:%s\n" % (rev, short(changenode)),
669 self.ui.write("%d:%s\n" % (rev, short(changenode)),
670 label='log.node')
670 label='log.node')
671 return
671 return
672
672
673 log = self.repo.changelog
673 log = self.repo.changelog
674 date = util.datestr(ctx.date())
674 date = util.datestr(ctx.date())
675
675
676 hexfunc = self.ui.debugflag and hex or short
676 hexfunc = self.ui.debugflag and hex or short
677
677
678 parents = [(p, hexfunc(log.node(p)))
678 parents = [(p, hexfunc(log.node(p)))
679 for p in self._meaningful_parentrevs(log, rev)]
679 for p in self._meaningful_parentrevs(log, rev)]
680
680
681 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
681 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
682 label='log.changeset')
682 label='log.changeset')
683
683
684 branch = ctx.branch()
684 branch = ctx.branch()
685 # don't show the default branch name
685 # don't show the default branch name
686 if branch != 'default':
686 if branch != 'default':
687 self.ui.write(_("branch: %s\n") % branch,
687 self.ui.write(_("branch: %s\n") % branch,
688 label='log.branch')
688 label='log.branch')
689 for bookmark in self.repo.nodebookmarks(changenode):
689 for bookmark in self.repo.nodebookmarks(changenode):
690 self.ui.write(_("bookmark: %s\n") % bookmark,
690 self.ui.write(_("bookmark: %s\n") % bookmark,
691 label='log.bookmark')
691 label='log.bookmark')
692 for tag in self.repo.nodetags(changenode):
692 for tag in self.repo.nodetags(changenode):
693 self.ui.write(_("tag: %s\n") % tag,
693 self.ui.write(_("tag: %s\n") % tag,
694 label='log.tag')
694 label='log.tag')
695 if self.ui.debugflag and ctx.phase():
695 if self.ui.debugflag and ctx.phase():
696 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
696 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
697 label='log.phase')
697 label='log.phase')
698 for parent in parents:
698 for parent in parents:
699 self.ui.write(_("parent: %d:%s\n") % parent,
699 self.ui.write(_("parent: %d:%s\n") % parent,
700 label='log.parent')
700 label='log.parent')
701
701
702 if self.ui.debugflag:
702 if self.ui.debugflag:
703 mnode = ctx.manifestnode()
703 mnode = ctx.manifestnode()
704 self.ui.write(_("manifest: %d:%s\n") %
704 self.ui.write(_("manifest: %d:%s\n") %
705 (self.repo.manifest.rev(mnode), hex(mnode)),
705 (self.repo.manifest.rev(mnode), hex(mnode)),
706 label='ui.debug log.manifest')
706 label='ui.debug log.manifest')
707 self.ui.write(_("user: %s\n") % ctx.user(),
707 self.ui.write(_("user: %s\n") % ctx.user(),
708 label='log.user')
708 label='log.user')
709 self.ui.write(_("date: %s\n") % date,
709 self.ui.write(_("date: %s\n") % date,
710 label='log.date')
710 label='log.date')
711
711
712 if self.ui.debugflag:
712 if self.ui.debugflag:
713 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
713 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
714 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
714 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
715 files):
715 files):
716 if value:
716 if value:
717 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
717 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
718 label='ui.debug log.files')
718 label='ui.debug log.files')
719 elif ctx.files() and self.ui.verbose:
719 elif ctx.files() and self.ui.verbose:
720 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
720 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
721 label='ui.note log.files')
721 label='ui.note log.files')
722 if copies and self.ui.verbose:
722 if copies and self.ui.verbose:
723 copies = ['%s (%s)' % c for c in copies]
723 copies = ['%s (%s)' % c for c in copies]
724 self.ui.write(_("copies: %s\n") % ' '.join(copies),
724 self.ui.write(_("copies: %s\n") % ' '.join(copies),
725 label='ui.note log.copies')
725 label='ui.note log.copies')
726
726
727 extra = ctx.extra()
727 extra = ctx.extra()
728 if extra and self.ui.debugflag:
728 if extra and self.ui.debugflag:
729 for key, value in sorted(extra.items()):
729 for key, value in sorted(extra.items()):
730 self.ui.write(_("extra: %s=%s\n")
730 self.ui.write(_("extra: %s=%s\n")
731 % (key, value.encode('string_escape')),
731 % (key, value.encode('string_escape')),
732 label='ui.debug log.extra')
732 label='ui.debug log.extra')
733
733
734 description = ctx.description().strip()
734 description = ctx.description().strip()
735 if description:
735 if description:
736 if self.ui.verbose:
736 if self.ui.verbose:
737 self.ui.write(_("description:\n"),
737 self.ui.write(_("description:\n"),
738 label='ui.note log.description')
738 label='ui.note log.description')
739 self.ui.write(description,
739 self.ui.write(description,
740 label='ui.note log.description')
740 label='ui.note log.description')
741 self.ui.write("\n\n")
741 self.ui.write("\n\n")
742 else:
742 else:
743 self.ui.write(_("summary: %s\n") %
743 self.ui.write(_("summary: %s\n") %
744 description.splitlines()[0],
744 description.splitlines()[0],
745 label='log.summary')
745 label='log.summary')
746 self.ui.write("\n")
746 self.ui.write("\n")
747
747
748 self.showpatch(changenode, matchfn)
748 self.showpatch(changenode, matchfn)
749
749
750 def showpatch(self, node, matchfn):
750 def showpatch(self, node, matchfn):
751 if not matchfn:
751 if not matchfn:
752 matchfn = self.patch
752 matchfn = self.patch
753 if matchfn:
753 if matchfn:
754 stat = self.diffopts.get('stat')
754 stat = self.diffopts.get('stat')
755 diff = self.diffopts.get('patch')
755 diff = self.diffopts.get('patch')
756 diffopts = patch.diffopts(self.ui, self.diffopts)
756 diffopts = patch.diffopts(self.ui, self.diffopts)
757 prev = self.repo.changelog.parents(node)[0]
757 prev = self.repo.changelog.parents(node)[0]
758 if stat:
758 if stat:
759 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
759 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
760 match=matchfn, stat=True)
760 match=matchfn, stat=True)
761 if diff:
761 if diff:
762 if stat:
762 if stat:
763 self.ui.write("\n")
763 self.ui.write("\n")
764 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
764 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
765 match=matchfn, stat=False)
765 match=matchfn, stat=False)
766 self.ui.write("\n")
766 self.ui.write("\n")
767
767
768 def _meaningful_parentrevs(self, log, rev):
768 def _meaningful_parentrevs(self, log, rev):
769 """Return list of meaningful (or all if debug) parentrevs for rev.
769 """Return list of meaningful (or all if debug) parentrevs for rev.
770
770
771 For merges (two non-nullrev revisions) both parents are meaningful.
771 For merges (two non-nullrev revisions) both parents are meaningful.
772 Otherwise the first parent revision is considered meaningful if it
772 Otherwise the first parent revision is considered meaningful if it
773 is not the preceding revision.
773 is not the preceding revision.
774 """
774 """
775 parents = log.parentrevs(rev)
775 parents = log.parentrevs(rev)
776 if not self.ui.debugflag and parents[1] == nullrev:
776 if not self.ui.debugflag and parents[1] == nullrev:
777 if parents[0] >= rev - 1:
777 if parents[0] >= rev - 1:
778 parents = []
778 parents = []
779 else:
779 else:
780 parents = [parents[0]]
780 parents = [parents[0]]
781 return parents
781 return parents
782
782
783
783
784 class changeset_templater(changeset_printer):
784 class changeset_templater(changeset_printer):
785 '''format changeset information.'''
785 '''format changeset information.'''
786
786
787 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
787 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
788 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
788 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
789 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
789 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
790 defaulttempl = {
790 defaulttempl = {
791 'parent': '{rev}:{node|formatnode} ',
791 'parent': '{rev}:{node|formatnode} ',
792 'manifest': '{rev}:{node|formatnode}',
792 'manifest': '{rev}:{node|formatnode}',
793 'file_copy': '{name} ({source})',
793 'file_copy': '{name} ({source})',
794 'extra': '{key}={value|stringescape}'
794 'extra': '{key}={value|stringescape}'
795 }
795 }
796 # filecopy is preserved for compatibility reasons
796 # filecopy is preserved for compatibility reasons
797 defaulttempl['filecopy'] = defaulttempl['file_copy']
797 defaulttempl['filecopy'] = defaulttempl['file_copy']
798 self.t = templater.templater(mapfile, {'formatnode': formatnode},
798 self.t = templater.templater(mapfile, {'formatnode': formatnode},
799 cache=defaulttempl)
799 cache=defaulttempl)
800 self.cache = {}
800 self.cache = {}
801
801
802 def use_template(self, t):
802 def use_template(self, t):
803 '''set template string to use'''
803 '''set template string to use'''
804 self.t.cache['changeset'] = t
804 self.t.cache['changeset'] = t
805
805
806 def _meaningful_parentrevs(self, ctx):
806 def _meaningful_parentrevs(self, ctx):
807 """Return list of meaningful (or all if debug) parentrevs for rev.
807 """Return list of meaningful (or all if debug) parentrevs for rev.
808 """
808 """
809 parents = ctx.parents()
809 parents = ctx.parents()
810 if len(parents) > 1:
810 if len(parents) > 1:
811 return parents
811 return parents
812 if self.ui.debugflag:
812 if self.ui.debugflag:
813 return [parents[0], self.repo['null']]
813 return [parents[0], self.repo['null']]
814 if parents[0].rev() >= ctx.rev() - 1:
814 if parents[0].rev() >= ctx.rev() - 1:
815 return []
815 return []
816 return parents
816 return parents
817
817
818 def _show(self, ctx, copies, matchfn, props):
818 def _show(self, ctx, copies, matchfn, props):
819 '''show a single changeset or file revision'''
819 '''show a single changeset or file revision'''
820
820
821 showlist = templatekw.showlist
821 showlist = templatekw.showlist
822
822
823 # showparents() behaviour depends on ui trace level which
823 # showparents() behaviour depends on ui trace level which
824 # causes unexpected behaviours at templating level and makes
824 # causes unexpected behaviours at templating level and makes
825 # it harder to extract it in a standalone function. Its
825 # it harder to extract it in a standalone function. Its
826 # behaviour cannot be changed so leave it here for now.
826 # behaviour cannot be changed so leave it here for now.
827 def showparents(**args):
827 def showparents(**args):
828 ctx = args['ctx']
828 ctx = args['ctx']
829 parents = [[('rev', p.rev()), ('node', p.hex())]
829 parents = [[('rev', p.rev()), ('node', p.hex())]
830 for p in self._meaningful_parentrevs(ctx)]
830 for p in self._meaningful_parentrevs(ctx)]
831 return showlist('parent', parents, **args)
831 return showlist('parent', parents, **args)
832
832
833 props = props.copy()
833 props = props.copy()
834 props.update(templatekw.keywords)
834 props.update(templatekw.keywords)
835 props['parents'] = showparents
835 props['parents'] = showparents
836 props['templ'] = self.t
836 props['templ'] = self.t
837 props['ctx'] = ctx
837 props['ctx'] = ctx
838 props['repo'] = self.repo
838 props['repo'] = self.repo
839 props['revcache'] = {'copies': copies}
839 props['revcache'] = {'copies': copies}
840 props['cache'] = self.cache
840 props['cache'] = self.cache
841
841
842 # find correct templates for current mode
842 # find correct templates for current mode
843
843
844 tmplmodes = [
844 tmplmodes = [
845 (True, None),
845 (True, None),
846 (self.ui.verbose, 'verbose'),
846 (self.ui.verbose, 'verbose'),
847 (self.ui.quiet, 'quiet'),
847 (self.ui.quiet, 'quiet'),
848 (self.ui.debugflag, 'debug'),
848 (self.ui.debugflag, 'debug'),
849 ]
849 ]
850
850
851 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
851 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
852 for mode, postfix in tmplmodes:
852 for mode, postfix in tmplmodes:
853 for type in types:
853 for type in types:
854 cur = postfix and ('%s_%s' % (type, postfix)) or type
854 cur = postfix and ('%s_%s' % (type, postfix)) or type
855 if mode and cur in self.t:
855 if mode and cur in self.t:
856 types[type] = cur
856 types[type] = cur
857
857
858 try:
858 try:
859
859
860 # write header
860 # write header
861 if types['header']:
861 if types['header']:
862 h = templater.stringify(self.t(types['header'], **props))
862 h = templater.stringify(self.t(types['header'], **props))
863 if self.buffered:
863 if self.buffered:
864 self.header[ctx.rev()] = h
864 self.header[ctx.rev()] = h
865 else:
865 else:
866 if self.lastheader != h:
866 if self.lastheader != h:
867 self.lastheader = h
867 self.lastheader = h
868 self.ui.write(h)
868 self.ui.write(h)
869
869
870 # write changeset metadata, then patch if requested
870 # write changeset metadata, then patch if requested
871 key = types['changeset']
871 key = types['changeset']
872 self.ui.write(templater.stringify(self.t(key, **props)))
872 self.ui.write(templater.stringify(self.t(key, **props)))
873 self.showpatch(ctx.node(), matchfn)
873 self.showpatch(ctx.node(), matchfn)
874
874
875 if types['footer']:
875 if types['footer']:
876 if not self.footer:
876 if not self.footer:
877 self.footer = templater.stringify(self.t(types['footer'],
877 self.footer = templater.stringify(self.t(types['footer'],
878 **props))
878 **props))
879
879
880 except KeyError, inst:
880 except KeyError, inst:
881 msg = _("%s: no key named '%s'")
881 msg = _("%s: no key named '%s'")
882 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
882 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
883 except SyntaxError, inst:
883 except SyntaxError, inst:
884 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
884 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
885
885
886 def show_changeset(ui, repo, opts, buffered=False):
886 def show_changeset(ui, repo, opts, buffered=False):
887 """show one changeset using template or regular display.
887 """show one changeset using template or regular display.
888
888
889 Display format will be the first non-empty hit of:
889 Display format will be the first non-empty hit of:
890 1. option 'template'
890 1. option 'template'
891 2. option 'style'
891 2. option 'style'
892 3. [ui] setting 'logtemplate'
892 3. [ui] setting 'logtemplate'
893 4. [ui] setting 'style'
893 4. [ui] setting 'style'
894 If all of these values are either the unset or the empty string,
894 If all of these values are either the unset or the empty string,
895 regular display via changeset_printer() is done.
895 regular display via changeset_printer() is done.
896 """
896 """
897 # options
897 # options
898 patch = False
898 patch = False
899 if opts.get('patch') or opts.get('stat'):
899 if opts.get('patch') or opts.get('stat'):
900 patch = scmutil.matchall(repo)
900 patch = scmutil.matchall(repo)
901
901
902 tmpl = opts.get('template')
902 tmpl = opts.get('template')
903 style = None
903 style = None
904 if tmpl:
904 if tmpl:
905 tmpl = templater.parsestring(tmpl, quoted=False)
905 tmpl = templater.parsestring(tmpl, quoted=False)
906 else:
906 else:
907 style = opts.get('style')
907 style = opts.get('style')
908
908
909 # ui settings
909 # ui settings
910 if not (tmpl or style):
910 if not (tmpl or style):
911 tmpl = ui.config('ui', 'logtemplate')
911 tmpl = ui.config('ui', 'logtemplate')
912 if tmpl:
912 if tmpl:
913 try:
913 try:
914 tmpl = templater.parsestring(tmpl)
914 tmpl = templater.parsestring(tmpl)
915 except SyntaxError:
915 except SyntaxError:
916 tmpl = templater.parsestring(tmpl, quoted=False)
916 tmpl = templater.parsestring(tmpl, quoted=False)
917 else:
917 else:
918 style = util.expandpath(ui.config('ui', 'style', ''))
918 style = util.expandpath(ui.config('ui', 'style', ''))
919
919
920 if not (tmpl or style):
920 if not (tmpl or style):
921 return changeset_printer(ui, repo, patch, opts, buffered)
921 return changeset_printer(ui, repo, patch, opts, buffered)
922
922
923 mapfile = None
923 mapfile = None
924 if style and not tmpl:
924 if style and not tmpl:
925 mapfile = style
925 mapfile = style
926 if not os.path.split(mapfile)[0]:
926 if not os.path.split(mapfile)[0]:
927 mapname = (templater.templatepath('map-cmdline.' + mapfile)
927 mapname = (templater.templatepath('map-cmdline.' + mapfile)
928 or templater.templatepath(mapfile))
928 or templater.templatepath(mapfile))
929 if mapname:
929 if mapname:
930 mapfile = mapname
930 mapfile = mapname
931
931
932 try:
932 try:
933 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
933 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
934 except SyntaxError, inst:
934 except SyntaxError, inst:
935 raise util.Abort(inst.args[0])
935 raise util.Abort(inst.args[0])
936 if tmpl:
936 if tmpl:
937 t.use_template(tmpl)
937 t.use_template(tmpl)
938 return t
938 return t
939
939
940 def finddate(ui, repo, date):
940 def finddate(ui, repo, date):
941 """Find the tipmost changeset that matches the given date spec"""
941 """Find the tipmost changeset that matches the given date spec"""
942
942
943 df = util.matchdate(date)
943 df = util.matchdate(date)
944 m = scmutil.matchall(repo)
944 m = scmutil.matchall(repo)
945 results = {}
945 results = {}
946
946
947 def prep(ctx, fns):
947 def prep(ctx, fns):
948 d = ctx.date()
948 d = ctx.date()
949 if df(d[0]):
949 if df(d[0]):
950 results[ctx.rev()] = d
950 results[ctx.rev()] = d
951
951
952 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
952 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
953 rev = ctx.rev()
953 rev = ctx.rev()
954 if rev in results:
954 if rev in results:
955 ui.status(_("found revision %s from %s\n") %
955 ui.status(_("found revision %s from %s\n") %
956 (rev, util.datestr(results[rev])))
956 (rev, util.datestr(results[rev])))
957 return str(rev)
957 return str(rev)
958
958
959 raise util.Abort(_("revision matching date not found"))
959 raise util.Abort(_("revision matching date not found"))
960
960
961 def increasingwindows(start, end, windowsize=8, sizelimit=512):
961 def increasingwindows(start, end, windowsize=8, sizelimit=512):
962 if start < end:
962 if start < end:
963 while start < end:
963 while start < end:
964 yield start, min(windowsize, end - start)
964 yield start, min(windowsize, end - start)
965 start += windowsize
965 start += windowsize
966 if windowsize < sizelimit:
966 if windowsize < sizelimit:
967 windowsize *= 2
967 windowsize *= 2
968 else:
968 else:
969 while start > end:
969 while start > end:
970 yield start, min(windowsize, start - end - 1)
970 yield start, min(windowsize, start - end - 1)
971 start -= windowsize
971 start -= windowsize
972 if windowsize < sizelimit:
972 if windowsize < sizelimit:
973 windowsize *= 2
973 windowsize *= 2
974
974
975 def walkchangerevs(repo, match, opts, prepare):
975 def walkchangerevs(repo, match, opts, prepare):
976 '''Iterate over files and the revs in which they changed.
976 '''Iterate over files and the revs in which they changed.
977
977
978 Callers most commonly need to iterate backwards over the history
978 Callers most commonly need to iterate backwards over the history
979 in which they are interested. Doing so has awful (quadratic-looking)
979 in which they are interested. Doing so has awful (quadratic-looking)
980 performance, so we use iterators in a "windowed" way.
980 performance, so we use iterators in a "windowed" way.
981
981
982 We walk a window of revisions in the desired order. Within the
982 We walk a window of revisions in the desired order. Within the
983 window, we first walk forwards to gather data, then in the desired
983 window, we first walk forwards to gather data, then in the desired
984 order (usually backwards) to display it.
984 order (usually backwards) to display it.
985
985
986 This function returns an iterator yielding contexts. Before
986 This function returns an iterator yielding contexts. Before
987 yielding each context, the iterator will first call the prepare
987 yielding each context, the iterator will first call the prepare
988 function on each context in the window in forward order.'''
988 function on each context in the window in forward order.'''
989
989
990 follow = opts.get('follow') or opts.get('follow_first')
990 follow = opts.get('follow') or opts.get('follow_first')
991
991
992 if not len(repo):
992 if not len(repo):
993 return []
993 return []
994
994
995 if follow:
995 if follow:
996 defrange = '%s:0' % repo['.'].rev()
996 defrange = '%s:0' % repo['.'].rev()
997 else:
997 else:
998 defrange = '-1:0'
998 defrange = '-1:0'
999 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
999 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
1000 if not revs:
1000 if not revs:
1001 return []
1001 return []
1002 wanted = set()
1002 wanted = set()
1003 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1003 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1004 fncache = {}
1004 fncache = {}
1005 change = repo.changectx
1005 change = repo.changectx
1006
1006
1007 # First step is to fill wanted, the set of revisions that we want to yield.
1007 # First step is to fill wanted, the set of revisions that we want to yield.
1008 # When it does not induce extra cost, we also fill fncache for revisions in
1008 # When it does not induce extra cost, we also fill fncache for revisions in
1009 # wanted: a cache of filenames that were changed (ctx.files()) and that
1009 # wanted: a cache of filenames that were changed (ctx.files()) and that
1010 # match the file filtering conditions.
1010 # match the file filtering conditions.
1011
1011
1012 if not slowpath and not match.files():
1012 if not slowpath and not match.files():
1013 # No files, no patterns. Display all revs.
1013 # No files, no patterns. Display all revs.
1014 wanted = set(revs)
1014 wanted = set(revs)
1015 copies = []
1015 copies = []
1016
1016
1017 if not slowpath and match.files():
1017 if not slowpath and match.files():
1018 # We only have to read through the filelog to find wanted revisions
1018 # We only have to read through the filelog to find wanted revisions
1019
1019
1020 minrev, maxrev = min(revs), max(revs)
1020 minrev, maxrev = min(revs), max(revs)
1021 def filerevgen(filelog, last):
1021 def filerevgen(filelog, last):
1022 """
1022 """
1023 Only files, no patterns. Check the history of each file.
1023 Only files, no patterns. Check the history of each file.
1024
1024
1025 Examines filelog entries within minrev, maxrev linkrev range
1025 Examines filelog entries within minrev, maxrev linkrev range
1026 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1026 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1027 tuples in backwards order
1027 tuples in backwards order
1028 """
1028 """
1029 cl_count = len(repo)
1029 cl_count = len(repo)
1030 revs = []
1030 revs = []
1031 for j in xrange(0, last + 1):
1031 for j in xrange(0, last + 1):
1032 linkrev = filelog.linkrev(j)
1032 linkrev = filelog.linkrev(j)
1033 if linkrev < minrev:
1033 if linkrev < minrev:
1034 continue
1034 continue
1035 # only yield rev for which we have the changelog, it can
1035 # only yield rev for which we have the changelog, it can
1036 # happen while doing "hg log" during a pull or commit
1036 # happen while doing "hg log" during a pull or commit
1037 if linkrev >= cl_count:
1037 if linkrev >= cl_count:
1038 break
1038 break
1039
1039
1040 parentlinkrevs = []
1040 parentlinkrevs = []
1041 for p in filelog.parentrevs(j):
1041 for p in filelog.parentrevs(j):
1042 if p != nullrev:
1042 if p != nullrev:
1043 parentlinkrevs.append(filelog.linkrev(p))
1043 parentlinkrevs.append(filelog.linkrev(p))
1044 n = filelog.node(j)
1044 n = filelog.node(j)
1045 revs.append((linkrev, parentlinkrevs,
1045 revs.append((linkrev, parentlinkrevs,
1046 follow and filelog.renamed(n)))
1046 follow and filelog.renamed(n)))
1047
1047
1048 return reversed(revs)
1048 return reversed(revs)
1049 def iterfiles():
1049 def iterfiles():
1050 pctx = repo['.']
1050 pctx = repo['.']
1051 for filename in match.files():
1051 for filename in match.files():
1052 if follow:
1052 if follow:
1053 if filename not in pctx:
1053 if filename not in pctx:
1054 raise util.Abort(_('cannot follow file not in parent '
1054 raise util.Abort(_('cannot follow file not in parent '
1055 'revision: "%s"') % filename)
1055 'revision: "%s"') % filename)
1056 yield filename, pctx[filename].filenode()
1056 yield filename, pctx[filename].filenode()
1057 else:
1057 else:
1058 yield filename, None
1058 yield filename, None
1059 for filename_node in copies:
1059 for filename_node in copies:
1060 yield filename_node
1060 yield filename_node
1061 for file_, node in iterfiles():
1061 for file_, node in iterfiles():
1062 filelog = repo.file(file_)
1062 filelog = repo.file(file_)
1063 if not len(filelog):
1063 if not len(filelog):
1064 if node is None:
1064 if node is None:
1065 # A zero count may be a directory or deleted file, so
1065 # A zero count may be a directory or deleted file, so
1066 # try to find matching entries on the slow path.
1066 # try to find matching entries on the slow path.
1067 if follow:
1067 if follow:
1068 raise util.Abort(
1068 raise util.Abort(
1069 _('cannot follow nonexistent file: "%s"') % file_)
1069 _('cannot follow nonexistent file: "%s"') % file_)
1070 slowpath = True
1070 slowpath = True
1071 break
1071 break
1072 else:
1072 else:
1073 continue
1073 continue
1074
1074
1075 if node is None:
1075 if node is None:
1076 last = len(filelog) - 1
1076 last = len(filelog) - 1
1077 else:
1077 else:
1078 last = filelog.rev(node)
1078 last = filelog.rev(node)
1079
1079
1080
1080
1081 # keep track of all ancestors of the file
1081 # keep track of all ancestors of the file
1082 ancestors = set([filelog.linkrev(last)])
1082 ancestors = set([filelog.linkrev(last)])
1083
1083
1084 # iterate from latest to oldest revision
1084 # iterate from latest to oldest revision
1085 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1085 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1086 if not follow:
1086 if not follow:
1087 if rev > maxrev:
1087 if rev > maxrev:
1088 continue
1088 continue
1089 else:
1089 else:
1090 # Note that last might not be the first interesting
1090 # Note that last might not be the first interesting
1091 # rev to us:
1091 # rev to us:
1092 # if the file has been changed after maxrev, we'll
1092 # if the file has been changed after maxrev, we'll
1093 # have linkrev(last) > maxrev, and we still need
1093 # have linkrev(last) > maxrev, and we still need
1094 # to explore the file graph
1094 # to explore the file graph
1095 if rev not in ancestors:
1095 if rev not in ancestors:
1096 continue
1096 continue
1097 # XXX insert 1327 fix here
1097 # XXX insert 1327 fix here
1098 if flparentlinkrevs:
1098 if flparentlinkrevs:
1099 ancestors.update(flparentlinkrevs)
1099 ancestors.update(flparentlinkrevs)
1100
1100
1101 fncache.setdefault(rev, []).append(file_)
1101 fncache.setdefault(rev, []).append(file_)
1102 wanted.add(rev)
1102 wanted.add(rev)
1103 if copied:
1103 if copied:
1104 copies.append(copied)
1104 copies.append(copied)
1105 if slowpath:
1105 if slowpath:
1106 # We have to read the changelog to match filenames against
1106 # We have to read the changelog to match filenames against
1107 # changed files
1107 # changed files
1108
1108
1109 if follow:
1109 if follow:
1110 raise util.Abort(_('can only follow copies/renames for explicit '
1110 raise util.Abort(_('can only follow copies/renames for explicit '
1111 'filenames'))
1111 'filenames'))
1112
1112
1113 # The slow path checks files modified in every changeset.
1113 # The slow path checks files modified in every changeset.
1114 for i in sorted(revs):
1114 for i in sorted(revs):
1115 ctx = change(i)
1115 ctx = change(i)
1116 matches = filter(match, ctx.files())
1116 matches = filter(match, ctx.files())
1117 if matches:
1117 if matches:
1118 fncache[i] = matches
1118 fncache[i] = matches
1119 wanted.add(i)
1119 wanted.add(i)
1120
1120
1121 class followfilter(object):
1121 class followfilter(object):
1122 def __init__(self, onlyfirst=False):
1122 def __init__(self, onlyfirst=False):
1123 self.startrev = nullrev
1123 self.startrev = nullrev
1124 self.roots = set()
1124 self.roots = set()
1125 self.onlyfirst = onlyfirst
1125 self.onlyfirst = onlyfirst
1126
1126
1127 def match(self, rev):
1127 def match(self, rev):
1128 def realparents(rev):
1128 def realparents(rev):
1129 if self.onlyfirst:
1129 if self.onlyfirst:
1130 return repo.changelog.parentrevs(rev)[0:1]
1130 return repo.changelog.parentrevs(rev)[0:1]
1131 else:
1131 else:
1132 return filter(lambda x: x != nullrev,
1132 return filter(lambda x: x != nullrev,
1133 repo.changelog.parentrevs(rev))
1133 repo.changelog.parentrevs(rev))
1134
1134
1135 if self.startrev == nullrev:
1135 if self.startrev == nullrev:
1136 self.startrev = rev
1136 self.startrev = rev
1137 return True
1137 return True
1138
1138
1139 if rev > self.startrev:
1139 if rev > self.startrev:
1140 # forward: all descendants
1140 # forward: all descendants
1141 if not self.roots:
1141 if not self.roots:
1142 self.roots.add(self.startrev)
1142 self.roots.add(self.startrev)
1143 for parent in realparents(rev):
1143 for parent in realparents(rev):
1144 if parent in self.roots:
1144 if parent in self.roots:
1145 self.roots.add(rev)
1145 self.roots.add(rev)
1146 return True
1146 return True
1147 else:
1147 else:
1148 # backwards: all parents
1148 # backwards: all parents
1149 if not self.roots:
1149 if not self.roots:
1150 self.roots.update(realparents(self.startrev))
1150 self.roots.update(realparents(self.startrev))
1151 if rev in self.roots:
1151 if rev in self.roots:
1152 self.roots.remove(rev)
1152 self.roots.remove(rev)
1153 self.roots.update(realparents(rev))
1153 self.roots.update(realparents(rev))
1154 return True
1154 return True
1155
1155
1156 return False
1156 return False
1157
1157
1158 # it might be worthwhile to do this in the iterator if the rev range
1158 # it might be worthwhile to do this in the iterator if the rev range
1159 # is descending and the prune args are all within that range
1159 # is descending and the prune args are all within that range
1160 for rev in opts.get('prune', ()):
1160 for rev in opts.get('prune', ()):
1161 rev = repo[rev].rev()
1161 rev = repo[rev].rev()
1162 ff = followfilter()
1162 ff = followfilter()
1163 stop = min(revs[0], revs[-1])
1163 stop = min(revs[0], revs[-1])
1164 for x in xrange(rev, stop - 1, -1):
1164 for x in xrange(rev, stop - 1, -1):
1165 if ff.match(x):
1165 if ff.match(x):
1166 wanted.discard(x)
1166 wanted.discard(x)
1167
1167
1168 # Now that wanted is correctly initialized, we can iterate over the
1168 # Now that wanted is correctly initialized, we can iterate over the
1169 # revision range, yielding only revisions in wanted.
1169 # revision range, yielding only revisions in wanted.
1170 def iterate():
1170 def iterate():
1171 if follow and not match.files():
1171 if follow and not match.files():
1172 ff = followfilter(onlyfirst=opts.get('follow_first'))
1172 ff = followfilter(onlyfirst=opts.get('follow_first'))
1173 def want(rev):
1173 def want(rev):
1174 return ff.match(rev) and rev in wanted
1174 return ff.match(rev) and rev in wanted
1175 else:
1175 else:
1176 def want(rev):
1176 def want(rev):
1177 return rev in wanted
1177 return rev in wanted
1178
1178
1179 for i, window in increasingwindows(0, len(revs)):
1179 for i, window in increasingwindows(0, len(revs)):
1180 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1180 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1181 for rev in sorted(nrevs):
1181 for rev in sorted(nrevs):
1182 fns = fncache.get(rev)
1182 fns = fncache.get(rev)
1183 ctx = change(rev)
1183 ctx = change(rev)
1184 if not fns:
1184 if not fns:
1185 def fns_generator():
1185 def fns_generator():
1186 for f in ctx.files():
1186 for f in ctx.files():
1187 if match(f):
1187 if match(f):
1188 yield f
1188 yield f
1189 fns = fns_generator()
1189 fns = fns_generator()
1190 prepare(ctx, fns)
1190 prepare(ctx, fns)
1191 for rev in nrevs:
1191 for rev in nrevs:
1192 yield change(rev)
1192 yield change(rev)
1193 return iterate()
1193 return iterate()
1194
1194
1195 def _makegraphfilematcher(repo, pats, followfirst):
1195 def _makegraphfilematcher(repo, pats, followfirst):
1196 # When displaying a revision with --patch --follow FILE, we have
1196 # When displaying a revision with --patch --follow FILE, we have
1197 # to know which file of the revision must be diffed. With
1197 # to know which file of the revision must be diffed. With
1198 # --follow, we want the names of the ancestors of FILE in the
1198 # --follow, we want the names of the ancestors of FILE in the
1199 # revision, stored in "fcache". "fcache" is populated by
1199 # revision, stored in "fcache". "fcache" is populated by
1200 # reproducing the graph traversal already done by --follow revset
1200 # reproducing the graph traversal already done by --follow revset
1201 # and relating linkrevs to file names (which is not "correct" but
1201 # and relating linkrevs to file names (which is not "correct" but
1202 # good enough).
1202 # good enough).
1203 fcache = {}
1203 fcache = {}
1204 fcacheready = [False]
1204 fcacheready = [False]
1205 pctx = repo['.']
1205 pctx = repo['.']
1206 wctx = repo[None]
1206 wctx = repo[None]
1207
1207
1208 def populate():
1208 def populate():
1209 for fn in pats:
1209 for fn in pats:
1210 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1210 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1211 for c in i:
1211 for c in i:
1212 fcache.setdefault(c.linkrev(), set()).add(c.path())
1212 fcache.setdefault(c.linkrev(), set()).add(c.path())
1213
1213
1214 def filematcher(rev):
1214 def filematcher(rev):
1215 if not fcacheready[0]:
1215 if not fcacheready[0]:
1216 # Lazy initialization
1216 # Lazy initialization
1217 fcacheready[0] = True
1217 fcacheready[0] = True
1218 populate()
1218 populate()
1219 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1219 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1220
1220
1221 return filematcher
1221 return filematcher
1222
1222
1223 def _makegraphlogrevset(repo, pats, opts, revs):
1223 def _makegraphlogrevset(repo, pats, opts, revs):
1224 """Return (expr, filematcher) where expr is a revset string built
1224 """Return (expr, filematcher) where expr is a revset string built
1225 from log options and file patterns or None. If --stat or --patch
1225 from log options and file patterns or None. If --stat or --patch
1226 are not passed filematcher is None. Otherwise it is a callable
1226 are not passed filematcher is None. Otherwise it is a callable
1227 taking a revision number and returning a match objects filtering
1227 taking a revision number and returning a match objects filtering
1228 the files to be detailed when displaying the revision.
1228 the files to be detailed when displaying the revision.
1229 """
1229 """
1230 opt2revset = {
1230 opt2revset = {
1231 'no_merges': ('not merge()', None),
1231 'no_merges': ('not merge()', None),
1232 'only_merges': ('merge()', None),
1232 'only_merges': ('merge()', None),
1233 '_ancestors': ('ancestors(%(val)s)', None),
1233 '_ancestors': ('ancestors(%(val)s)', None),
1234 '_fancestors': ('_firstancestors(%(val)s)', None),
1234 '_fancestors': ('_firstancestors(%(val)s)', None),
1235 '_descendants': ('descendants(%(val)s)', None),
1235 '_descendants': ('descendants(%(val)s)', None),
1236 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1236 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1237 '_matchfiles': ('_matchfiles(%(val)s)', None),
1237 '_matchfiles': ('_matchfiles(%(val)s)', None),
1238 'date': ('date(%(val)r)', None),
1238 'date': ('date(%(val)r)', None),
1239 'branch': ('branch(%(val)r)', ' or '),
1239 'branch': ('branch(%(val)r)', ' or '),
1240 '_patslog': ('filelog(%(val)r)', ' or '),
1240 '_patslog': ('filelog(%(val)r)', ' or '),
1241 '_patsfollow': ('follow(%(val)r)', ' or '),
1241 '_patsfollow': ('follow(%(val)r)', ' or '),
1242 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1242 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1243 'keyword': ('keyword(%(val)r)', ' or '),
1243 'keyword': ('keyword(%(val)r)', ' or '),
1244 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1244 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1245 'user': ('user(%(val)r)', ' or '),
1245 'user': ('user(%(val)r)', ' or '),
1246 }
1246 }
1247
1247
1248 opts = dict(opts)
1248 opts = dict(opts)
1249 # follow or not follow?
1249 # follow or not follow?
1250 follow = opts.get('follow') or opts.get('follow_first')
1250 follow = opts.get('follow') or opts.get('follow_first')
1251 followfirst = opts.get('follow_first') and 1 or 0
1251 followfirst = opts.get('follow_first') and 1 or 0
1252 # --follow with FILE behaviour depends on revs...
1252 # --follow with FILE behaviour depends on revs...
1253 startrev = revs[0]
1253 startrev = revs[0]
1254 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1254 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1255
1255
1256 # branch and only_branch are really aliases and must be handled at
1256 # branch and only_branch are really aliases and must be handled at
1257 # the same time
1257 # the same time
1258 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1258 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1259 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1259 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1260 # pats/include/exclude are passed to match.match() directly in
1260 # pats/include/exclude are passed to match.match() directly in
1261 # _matchfile() revset but walkchangerevs() builds its matcher with
1261 # _matchfile() revset but walkchangerevs() builds its matcher with
1262 # scmutil.match(). The difference is input pats are globbed on
1262 # scmutil.match(). The difference is input pats are globbed on
1263 # platforms without shell expansion (windows).
1263 # platforms without shell expansion (windows).
1264 pctx = repo[None]
1264 pctx = repo[None]
1265 match, pats = scmutil.matchandpats(pctx, pats, opts)
1265 match, pats = scmutil.matchandpats(pctx, pats, opts)
1266 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1266 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1267 if not slowpath:
1267 if not slowpath:
1268 for f in match.files():
1268 for f in match.files():
1269 if follow and f not in pctx:
1269 if follow and f not in pctx:
1270 raise util.Abort(_('cannot follow file not in parent '
1270 raise util.Abort(_('cannot follow file not in parent '
1271 'revision: "%s"') % f)
1271 'revision: "%s"') % f)
1272 filelog = repo.file(f)
1272 filelog = repo.file(f)
1273 if not len(filelog):
1273 if not len(filelog):
1274 # A zero count may be a directory or deleted file, so
1274 # A zero count may be a directory or deleted file, so
1275 # try to find matching entries on the slow path.
1275 # try to find matching entries on the slow path.
1276 if follow:
1276 if follow:
1277 raise util.Abort(
1277 raise util.Abort(
1278 _('cannot follow nonexistent file: "%s"') % f)
1278 _('cannot follow nonexistent file: "%s"') % f)
1279 slowpath = True
1279 slowpath = True
1280 if slowpath:
1280 if slowpath:
1281 # See walkchangerevs() slow path.
1281 # See walkchangerevs() slow path.
1282 #
1282 #
1283 if follow:
1283 if follow:
1284 raise util.Abort(_('can only follow copies/renames for explicit '
1284 raise util.Abort(_('can only follow copies/renames for explicit '
1285 'filenames'))
1285 'filenames'))
1286 # pats/include/exclude cannot be represented as separate
1286 # pats/include/exclude cannot be represented as separate
1287 # revset expressions as their filtering logic applies at file
1287 # revset expressions as their filtering logic applies at file
1288 # level. For instance "-I a -X a" matches a revision touching
1288 # level. For instance "-I a -X a" matches a revision touching
1289 # "a" and "b" while "file(a) and not file(b)" does
1289 # "a" and "b" while "file(a) and not file(b)" does
1290 # not. Besides, filesets are evaluated against the working
1290 # not. Besides, filesets are evaluated against the working
1291 # directory.
1291 # directory.
1292 matchargs = ['r:', 'd:relpath']
1292 matchargs = ['r:', 'd:relpath']
1293 for p in pats:
1293 for p in pats:
1294 matchargs.append('p:' + p)
1294 matchargs.append('p:' + p)
1295 for p in opts.get('include', []):
1295 for p in opts.get('include', []):
1296 matchargs.append('i:' + p)
1296 matchargs.append('i:' + p)
1297 for p in opts.get('exclude', []):
1297 for p in opts.get('exclude', []):
1298 matchargs.append('x:' + p)
1298 matchargs.append('x:' + p)
1299 matchargs = ','.join(('%r' % p) for p in matchargs)
1299 matchargs = ','.join(('%r' % p) for p in matchargs)
1300 opts['_matchfiles'] = matchargs
1300 opts['_matchfiles'] = matchargs
1301 else:
1301 else:
1302 if follow:
1302 if follow:
1303 fpats = ('_patsfollow', '_patsfollowfirst')
1303 fpats = ('_patsfollow', '_patsfollowfirst')
1304 fnopats = (('_ancestors', '_fancestors'),
1304 fnopats = (('_ancestors', '_fancestors'),
1305 ('_descendants', '_fdescendants'))
1305 ('_descendants', '_fdescendants'))
1306 if pats:
1306 if pats:
1307 # follow() revset inteprets its file argument as a
1307 # follow() revset inteprets its file argument as a
1308 # manifest entry, so use match.files(), not pats.
1308 # manifest entry, so use match.files(), not pats.
1309 opts[fpats[followfirst]] = list(match.files())
1309 opts[fpats[followfirst]] = list(match.files())
1310 else:
1310 else:
1311 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1311 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1312 else:
1312 else:
1313 opts['_patslog'] = list(pats)
1313 opts['_patslog'] = list(pats)
1314
1314
1315 filematcher = None
1315 filematcher = None
1316 if opts.get('patch') or opts.get('stat'):
1316 if opts.get('patch') or opts.get('stat'):
1317 if follow:
1317 if follow:
1318 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1318 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1319 else:
1319 else:
1320 filematcher = lambda rev: match
1320 filematcher = lambda rev: match
1321
1321
1322 expr = []
1322 expr = []
1323 for op, val in opts.iteritems():
1323 for op, val in opts.iteritems():
1324 if not val:
1324 if not val:
1325 continue
1325 continue
1326 if op not in opt2revset:
1326 if op not in opt2revset:
1327 continue
1327 continue
1328 revop, andor = opt2revset[op]
1328 revop, andor = opt2revset[op]
1329 if '%(val)' not in revop:
1329 if '%(val)' not in revop:
1330 expr.append(revop)
1330 expr.append(revop)
1331 else:
1331 else:
1332 if not isinstance(val, list):
1332 if not isinstance(val, list):
1333 e = revop % {'val': val}
1333 e = revop % {'val': val}
1334 else:
1334 else:
1335 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1335 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1336 expr.append(e)
1336 expr.append(e)
1337
1337
1338 if expr:
1338 if expr:
1339 expr = '(' + ' and '.join(expr) + ')'
1339 expr = '(' + ' and '.join(expr) + ')'
1340 else:
1340 else:
1341 expr = None
1341 expr = None
1342 return expr, filematcher
1342 return expr, filematcher
1343
1343
1344 def getgraphlogrevs(repo, pats, opts):
1344 def getgraphlogrevs(repo, pats, opts):
1345 """Return (revs, expr, filematcher) where revs is an iterable of
1345 """Return (revs, expr, filematcher) where revs is an iterable of
1346 revision numbers, expr is a revset string built from log options
1346 revision numbers, expr is a revset string built from log options
1347 and file patterns or None, and used to filter 'revs'. If --stat or
1347 and file patterns or None, and used to filter 'revs'. If --stat or
1348 --patch are not passed filematcher is None. Otherwise it is a
1348 --patch are not passed filematcher is None. Otherwise it is a
1349 callable taking a revision number and returning a match objects
1349 callable taking a revision number and returning a match objects
1350 filtering the files to be detailed when displaying the revision.
1350 filtering the files to be detailed when displaying the revision.
1351 """
1351 """
1352 def increasingrevs(repo, revs, matcher):
1352 def increasingrevs(repo, revs, matcher):
1353 # The sorted input rev sequence is chopped in sub-sequences
1353 # The sorted input rev sequence is chopped in sub-sequences
1354 # which are sorted in ascending order and passed to the
1354 # which are sorted in ascending order and passed to the
1355 # matcher. The filtered revs are sorted again as they were in
1355 # matcher. The filtered revs are sorted again as they were in
1356 # the original sub-sequence. This achieve several things:
1356 # the original sub-sequence. This achieve several things:
1357 #
1357 #
1358 # - getlogrevs() now returns a generator which behaviour is
1358 # - getlogrevs() now returns a generator which behaviour is
1359 # adapted to log need. First results come fast, last ones
1359 # adapted to log need. First results come fast, last ones
1360 # are batched for performances.
1360 # are batched for performances.
1361 #
1361 #
1362 # - revset matchers often operate faster on revision in
1362 # - revset matchers often operate faster on revision in
1363 # changelog order, because most filters deal with the
1363 # changelog order, because most filters deal with the
1364 # changelog.
1364 # changelog.
1365 #
1365 #
1366 # - revset matchers can reorder revisions. "A or B" typically
1366 # - revset matchers can reorder revisions. "A or B" typically
1367 # returns returns the revision matching A then the revision
1367 # returns returns the revision matching A then the revision
1368 # matching B. We want to hide this internal implementation
1368 # matching B. We want to hide this internal implementation
1369 # detail from the caller, and sorting the filtered revision
1369 # detail from the caller, and sorting the filtered revision
1370 # again achieves this.
1370 # again achieves this.
1371 for i, window in increasingwindows(0, len(revs), windowsize=1):
1371 for i, window in increasingwindows(0, len(revs), windowsize=1):
1372 orevs = revs[i:i + window]
1372 orevs = revs[i:i + window]
1373 nrevs = set(matcher(repo, sorted(orevs)))
1373 nrevs = set(matcher(repo, sorted(orevs)))
1374 for rev in orevs:
1374 for rev in orevs:
1375 if rev in nrevs:
1375 if rev in nrevs:
1376 yield rev
1376 yield rev
1377
1377
1378 if not len(repo):
1378 if not len(repo):
1379 return iter([]), None, None
1379 return iter([]), None, None
1380 # Default --rev value depends on --follow but --follow behaviour
1380 # Default --rev value depends on --follow but --follow behaviour
1381 # depends on revisions resolved from --rev...
1381 # depends on revisions resolved from --rev...
1382 follow = opts.get('follow') or opts.get('follow_first')
1382 follow = opts.get('follow') or opts.get('follow_first')
1383 if opts.get('rev'):
1383 if opts.get('rev'):
1384 revs = scmutil.revrange(repo, opts['rev'])
1384 revs = scmutil.revrange(repo, opts['rev'])
1385 else:
1385 else:
1386 if follow and len(repo) > 0:
1386 if follow and len(repo) > 0:
1387 revs = scmutil.revrange(repo, ['.:0'])
1387 revs = scmutil.revrange(repo, ['.:0'])
1388 else:
1388 else:
1389 revs = range(len(repo) - 1, -1, -1)
1389 revs = range(len(repo) - 1, -1, -1)
1390 if not revs:
1390 if not revs:
1391 return iter([]), None, None
1391 return iter([]), None, None
1392 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1392 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1393 if expr:
1393 if expr:
1394 matcher = revset.match(repo.ui, expr)
1394 matcher = revset.match(repo.ui, expr)
1395 revs = increasingrevs(repo, revs, matcher)
1395 revs = increasingrevs(repo, revs, matcher)
1396 if not opts.get('hidden'):
1396 if not opts.get('hidden'):
1397 # --hidden is still experimental and not worth a dedicated revset
1397 # --hidden is still experimental and not worth a dedicated revset
1398 # yet. Fortunately, filtering revision number is fast.
1398 # yet. Fortunately, filtering revision number is fast.
1399 revs = (r for r in revs if r not in repo.changelog.hiddenrevs)
1399 revs = (r for r in revs if r not in repo.changelog.hiddenrevs)
1400 else:
1400 else:
1401 revs = iter(revs)
1401 revs = iter(revs)
1402 return revs, expr, filematcher
1402 return revs, expr, filematcher
1403
1403
1404 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1404 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1405 filematcher=None):
1405 filematcher=None):
1406 seen, state = [], graphmod.asciistate()
1406 seen, state = [], graphmod.asciistate()
1407 for rev, type, ctx, parents in dag:
1407 for rev, type, ctx, parents in dag:
1408 char = 'o'
1408 char = 'o'
1409 if ctx.node() in showparents:
1409 if ctx.node() in showparents:
1410 char = '@'
1410 char = '@'
1411 elif ctx.obsolete():
1411 elif ctx.obsolete():
1412 char = 'x'
1412 char = 'x'
1413 copies = None
1413 copies = None
1414 if getrenamed and ctx.rev():
1414 if getrenamed and ctx.rev():
1415 copies = []
1415 copies = []
1416 for fn in ctx.files():
1416 for fn in ctx.files():
1417 rename = getrenamed(fn, ctx.rev())
1417 rename = getrenamed(fn, ctx.rev())
1418 if rename:
1418 if rename:
1419 copies.append((fn, rename[0]))
1419 copies.append((fn, rename[0]))
1420 revmatchfn = None
1420 revmatchfn = None
1421 if filematcher is not None:
1421 if filematcher is not None:
1422 revmatchfn = filematcher(ctx.rev())
1422 revmatchfn = filematcher(ctx.rev())
1423 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1423 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1424 lines = displayer.hunk.pop(rev).split('\n')
1424 lines = displayer.hunk.pop(rev).split('\n')
1425 if not lines[-1]:
1425 if not lines[-1]:
1426 del lines[-1]
1426 del lines[-1]
1427 displayer.flush(rev)
1427 displayer.flush(rev)
1428 edges = edgefn(type, char, lines, seen, rev, parents)
1428 edges = edgefn(type, char, lines, seen, rev, parents)
1429 for type, char, lines, coldata in edges:
1429 for type, char, lines, coldata in edges:
1430 graphmod.ascii(ui, state, type, char, lines, coldata)
1430 graphmod.ascii(ui, state, type, char, lines, coldata)
1431 displayer.close()
1431 displayer.close()
1432
1432
1433 def graphlog(ui, repo, *pats, **opts):
1433 def graphlog(ui, repo, *pats, **opts):
1434 # Parameters are identical to log command ones
1434 # Parameters are identical to log command ones
1435 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1435 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1436 revs = sorted(revs, reverse=1)
1436 revs = sorted(revs, reverse=1)
1437 limit = loglimit(opts)
1437 limit = loglimit(opts)
1438 if limit is not None:
1438 if limit is not None:
1439 revs = revs[:limit]
1439 revs = revs[:limit]
1440 revdag = graphmod.dagwalker(repo, revs)
1440 revdag = graphmod.dagwalker(repo, revs)
1441
1441
1442 getrenamed = None
1442 getrenamed = None
1443 if opts.get('copies'):
1443 if opts.get('copies'):
1444 endrev = None
1444 endrev = None
1445 if opts.get('rev'):
1445 if opts.get('rev'):
1446 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1446 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1447 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1447 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1448 displayer = show_changeset(ui, repo, opts, buffered=True)
1448 displayer = show_changeset(ui, repo, opts, buffered=True)
1449 showparents = [ctx.node() for ctx in repo[None].parents()]
1449 showparents = [ctx.node() for ctx in repo[None].parents()]
1450 displaygraph(ui, revdag, displayer, showparents,
1450 displaygraph(ui, revdag, displayer, showparents,
1451 graphmod.asciiedges, getrenamed, filematcher)
1451 graphmod.asciiedges, getrenamed, filematcher)
1452
1452
1453 def checkunsupportedgraphflags(pats, opts):
1454 for op in ["newest_first"]:
1455 if op in opts and opts[op]:
1456 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1457 % op.replace("_", "-"))
1458
1459 def graphrevs(repo, nodes, opts):
1460 limit = loglimit(opts)
1461 nodes.reverse()
1462 if limit is not None:
1463 nodes = nodes[:limit]
1464 return graphmod.nodes(repo, nodes)
1465
1453 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1466 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1454 join = lambda f: os.path.join(prefix, f)
1467 join = lambda f: os.path.join(prefix, f)
1455 bad = []
1468 bad = []
1456 oldbad = match.bad
1469 oldbad = match.bad
1457 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1470 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1458 names = []
1471 names = []
1459 wctx = repo[None]
1472 wctx = repo[None]
1460 cca = None
1473 cca = None
1461 abort, warn = scmutil.checkportabilityalert(ui)
1474 abort, warn = scmutil.checkportabilityalert(ui)
1462 if abort or warn:
1475 if abort or warn:
1463 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1476 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1464 for f in repo.walk(match):
1477 for f in repo.walk(match):
1465 exact = match.exact(f)
1478 exact = match.exact(f)
1466 if exact or not explicitonly and f not in repo.dirstate:
1479 if exact or not explicitonly and f not in repo.dirstate:
1467 if cca:
1480 if cca:
1468 cca(f)
1481 cca(f)
1469 names.append(f)
1482 names.append(f)
1470 if ui.verbose or not exact:
1483 if ui.verbose or not exact:
1471 ui.status(_('adding %s\n') % match.rel(join(f)))
1484 ui.status(_('adding %s\n') % match.rel(join(f)))
1472
1485
1473 for subpath in wctx.substate:
1486 for subpath in wctx.substate:
1474 sub = wctx.sub(subpath)
1487 sub = wctx.sub(subpath)
1475 try:
1488 try:
1476 submatch = matchmod.narrowmatcher(subpath, match)
1489 submatch = matchmod.narrowmatcher(subpath, match)
1477 if listsubrepos:
1490 if listsubrepos:
1478 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1491 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1479 False))
1492 False))
1480 else:
1493 else:
1481 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1494 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1482 True))
1495 True))
1483 except error.LookupError:
1496 except error.LookupError:
1484 ui.status(_("skipping missing subrepository: %s\n")
1497 ui.status(_("skipping missing subrepository: %s\n")
1485 % join(subpath))
1498 % join(subpath))
1486
1499
1487 if not dryrun:
1500 if not dryrun:
1488 rejected = wctx.add(names, prefix)
1501 rejected = wctx.add(names, prefix)
1489 bad.extend(f for f in rejected if f in match.files())
1502 bad.extend(f for f in rejected if f in match.files())
1490 return bad
1503 return bad
1491
1504
1492 def forget(ui, repo, match, prefix, explicitonly):
1505 def forget(ui, repo, match, prefix, explicitonly):
1493 join = lambda f: os.path.join(prefix, f)
1506 join = lambda f: os.path.join(prefix, f)
1494 bad = []
1507 bad = []
1495 oldbad = match.bad
1508 oldbad = match.bad
1496 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1509 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1497 wctx = repo[None]
1510 wctx = repo[None]
1498 forgot = []
1511 forgot = []
1499 s = repo.status(match=match, clean=True)
1512 s = repo.status(match=match, clean=True)
1500 forget = sorted(s[0] + s[1] + s[3] + s[6])
1513 forget = sorted(s[0] + s[1] + s[3] + s[6])
1501 if explicitonly:
1514 if explicitonly:
1502 forget = [f for f in forget if match.exact(f)]
1515 forget = [f for f in forget if match.exact(f)]
1503
1516
1504 for subpath in wctx.substate:
1517 for subpath in wctx.substate:
1505 sub = wctx.sub(subpath)
1518 sub = wctx.sub(subpath)
1506 try:
1519 try:
1507 submatch = matchmod.narrowmatcher(subpath, match)
1520 submatch = matchmod.narrowmatcher(subpath, match)
1508 subbad, subforgot = sub.forget(ui, submatch, prefix)
1521 subbad, subforgot = sub.forget(ui, submatch, prefix)
1509 bad.extend([subpath + '/' + f for f in subbad])
1522 bad.extend([subpath + '/' + f for f in subbad])
1510 forgot.extend([subpath + '/' + f for f in subforgot])
1523 forgot.extend([subpath + '/' + f for f in subforgot])
1511 except error.LookupError:
1524 except error.LookupError:
1512 ui.status(_("skipping missing subrepository: %s\n")
1525 ui.status(_("skipping missing subrepository: %s\n")
1513 % join(subpath))
1526 % join(subpath))
1514
1527
1515 if not explicitonly:
1528 if not explicitonly:
1516 for f in match.files():
1529 for f in match.files():
1517 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1530 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1518 if f not in forgot:
1531 if f not in forgot:
1519 if os.path.exists(match.rel(join(f))):
1532 if os.path.exists(match.rel(join(f))):
1520 ui.warn(_('not removing %s: '
1533 ui.warn(_('not removing %s: '
1521 'file is already untracked\n')
1534 'file is already untracked\n')
1522 % match.rel(join(f)))
1535 % match.rel(join(f)))
1523 bad.append(f)
1536 bad.append(f)
1524
1537
1525 for f in forget:
1538 for f in forget:
1526 if ui.verbose or not match.exact(f):
1539 if ui.verbose or not match.exact(f):
1527 ui.status(_('removing %s\n') % match.rel(join(f)))
1540 ui.status(_('removing %s\n') % match.rel(join(f)))
1528
1541
1529 rejected = wctx.forget(forget, prefix)
1542 rejected = wctx.forget(forget, prefix)
1530 bad.extend(f for f in rejected if f in match.files())
1543 bad.extend(f for f in rejected if f in match.files())
1531 forgot.extend(forget)
1544 forgot.extend(forget)
1532 return bad, forgot
1545 return bad, forgot
1533
1546
1534 def duplicatecopies(repo, rev, p1):
1547 def duplicatecopies(repo, rev, p1):
1535 "Reproduce copies found in the source revision in the dirstate for grafts"
1548 "Reproduce copies found in the source revision in the dirstate for grafts"
1536 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1549 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1537 repo.dirstate.copy(src, dst)
1550 repo.dirstate.copy(src, dst)
1538
1551
1539 def commit(ui, repo, commitfunc, pats, opts):
1552 def commit(ui, repo, commitfunc, pats, opts):
1540 '''commit the specified files or all outstanding changes'''
1553 '''commit the specified files or all outstanding changes'''
1541 date = opts.get('date')
1554 date = opts.get('date')
1542 if date:
1555 if date:
1543 opts['date'] = util.parsedate(date)
1556 opts['date'] = util.parsedate(date)
1544 message = logmessage(ui, opts)
1557 message = logmessage(ui, opts)
1545
1558
1546 # extract addremove carefully -- this function can be called from a command
1559 # extract addremove carefully -- this function can be called from a command
1547 # that doesn't support addremove
1560 # that doesn't support addremove
1548 if opts.get('addremove'):
1561 if opts.get('addremove'):
1549 scmutil.addremove(repo, pats, opts)
1562 scmutil.addremove(repo, pats, opts)
1550
1563
1551 return commitfunc(ui, repo, message,
1564 return commitfunc(ui, repo, message,
1552 scmutil.match(repo[None], pats, opts), opts)
1565 scmutil.match(repo[None], pats, opts), opts)
1553
1566
1554 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1567 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1555 ui.note(_('amending changeset %s\n') % old)
1568 ui.note(_('amending changeset %s\n') % old)
1556 base = old.p1()
1569 base = old.p1()
1557
1570
1558 wlock = repo.wlock()
1571 wlock = repo.wlock()
1559 try:
1572 try:
1560 # First, do a regular commit to record all changes in the working
1573 # First, do a regular commit to record all changes in the working
1561 # directory (if there are any)
1574 # directory (if there are any)
1562 ui.callhooks = False
1575 ui.callhooks = False
1563 try:
1576 try:
1564 node = commit(ui, repo, commitfunc, pats, opts)
1577 node = commit(ui, repo, commitfunc, pats, opts)
1565 finally:
1578 finally:
1566 ui.callhooks = True
1579 ui.callhooks = True
1567 ctx = repo[node]
1580 ctx = repo[node]
1568
1581
1569 # Participating changesets:
1582 # Participating changesets:
1570 #
1583 #
1571 # node/ctx o - new (intermediate) commit that contains changes from
1584 # node/ctx o - new (intermediate) commit that contains changes from
1572 # | working dir to go into amending commit (or a workingctx
1585 # | working dir to go into amending commit (or a workingctx
1573 # | if there were no changes)
1586 # | if there were no changes)
1574 # |
1587 # |
1575 # old o - changeset to amend
1588 # old o - changeset to amend
1576 # |
1589 # |
1577 # base o - parent of amending changeset
1590 # base o - parent of amending changeset
1578
1591
1579 # Update extra dict from amended commit (e.g. to preserve graft source)
1592 # Update extra dict from amended commit (e.g. to preserve graft source)
1580 extra.update(old.extra())
1593 extra.update(old.extra())
1581
1594
1582 # Also update it from the intermediate commit or from the wctx
1595 # Also update it from the intermediate commit or from the wctx
1583 extra.update(ctx.extra())
1596 extra.update(ctx.extra())
1584
1597
1585 files = set(old.files())
1598 files = set(old.files())
1586
1599
1587 # Second, we use either the commit we just did, or if there were no
1600 # Second, we use either the commit we just did, or if there were no
1588 # changes the parent of the working directory as the version of the
1601 # changes the parent of the working directory as the version of the
1589 # files in the final amend commit
1602 # files in the final amend commit
1590 if node:
1603 if node:
1591 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1604 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1592
1605
1593 user = ctx.user()
1606 user = ctx.user()
1594 date = ctx.date()
1607 date = ctx.date()
1595 message = ctx.description()
1608 message = ctx.description()
1596 # Recompute copies (avoid recording a -> b -> a)
1609 # Recompute copies (avoid recording a -> b -> a)
1597 copied = copies.pathcopies(base, ctx)
1610 copied = copies.pathcopies(base, ctx)
1598
1611
1599 # Prune files which were reverted by the updates: if old introduced
1612 # Prune files which were reverted by the updates: if old introduced
1600 # file X and our intermediate commit, node, renamed that file, then
1613 # file X and our intermediate commit, node, renamed that file, then
1601 # those two files are the same and we can discard X from our list
1614 # those two files are the same and we can discard X from our list
1602 # of files. Likewise if X was deleted, it's no longer relevant
1615 # of files. Likewise if X was deleted, it's no longer relevant
1603 files.update(ctx.files())
1616 files.update(ctx.files())
1604
1617
1605 def samefile(f):
1618 def samefile(f):
1606 if f in ctx.manifest():
1619 if f in ctx.manifest():
1607 a = ctx.filectx(f)
1620 a = ctx.filectx(f)
1608 if f in base.manifest():
1621 if f in base.manifest():
1609 b = base.filectx(f)
1622 b = base.filectx(f)
1610 return (not a.cmp(b)
1623 return (not a.cmp(b)
1611 and a.flags() == b.flags())
1624 and a.flags() == b.flags())
1612 else:
1625 else:
1613 return False
1626 return False
1614 else:
1627 else:
1615 return f not in base.manifest()
1628 return f not in base.manifest()
1616 files = [f for f in files if not samefile(f)]
1629 files = [f for f in files if not samefile(f)]
1617
1630
1618 def filectxfn(repo, ctx_, path):
1631 def filectxfn(repo, ctx_, path):
1619 try:
1632 try:
1620 fctx = ctx[path]
1633 fctx = ctx[path]
1621 flags = fctx.flags()
1634 flags = fctx.flags()
1622 mctx = context.memfilectx(fctx.path(), fctx.data(),
1635 mctx = context.memfilectx(fctx.path(), fctx.data(),
1623 islink='l' in flags,
1636 islink='l' in flags,
1624 isexec='x' in flags,
1637 isexec='x' in flags,
1625 copied=copied.get(path))
1638 copied=copied.get(path))
1626 return mctx
1639 return mctx
1627 except KeyError:
1640 except KeyError:
1628 raise IOError
1641 raise IOError
1629 else:
1642 else:
1630 ui.note(_('copying changeset %s to %s\n') % (old, base))
1643 ui.note(_('copying changeset %s to %s\n') % (old, base))
1631
1644
1632 # Use version of files as in the old cset
1645 # Use version of files as in the old cset
1633 def filectxfn(repo, ctx_, path):
1646 def filectxfn(repo, ctx_, path):
1634 try:
1647 try:
1635 return old.filectx(path)
1648 return old.filectx(path)
1636 except KeyError:
1649 except KeyError:
1637 raise IOError
1650 raise IOError
1638
1651
1639 # See if we got a message from -m or -l, if not, open the editor
1652 # See if we got a message from -m or -l, if not, open the editor
1640 # with the message of the changeset to amend
1653 # with the message of the changeset to amend
1641 user = opts.get('user') or old.user()
1654 user = opts.get('user') or old.user()
1642 date = opts.get('date') or old.date()
1655 date = opts.get('date') or old.date()
1643 message = logmessage(ui, opts)
1656 message = logmessage(ui, opts)
1644 if not message:
1657 if not message:
1645 cctx = context.workingctx(repo, old.description(), user, date,
1658 cctx = context.workingctx(repo, old.description(), user, date,
1646 extra,
1659 extra,
1647 repo.status(base.node(), old.node()))
1660 repo.status(base.node(), old.node()))
1648 message = commitforceeditor(repo, cctx, [])
1661 message = commitforceeditor(repo, cctx, [])
1649
1662
1650 new = context.memctx(repo,
1663 new = context.memctx(repo,
1651 parents=[base.node(), nullid],
1664 parents=[base.node(), nullid],
1652 text=message,
1665 text=message,
1653 files=files,
1666 files=files,
1654 filectxfn=filectxfn,
1667 filectxfn=filectxfn,
1655 user=user,
1668 user=user,
1656 date=date,
1669 date=date,
1657 extra=extra)
1670 extra=extra)
1658 newid = repo.commitctx(new)
1671 newid = repo.commitctx(new)
1659 if newid != old.node():
1672 if newid != old.node():
1660 # Reroute the working copy parent to the new changeset
1673 # Reroute the working copy parent to the new changeset
1661 repo.setparents(newid, nullid)
1674 repo.setparents(newid, nullid)
1662
1675
1663 # Move bookmarks from old parent to amend commit
1676 # Move bookmarks from old parent to amend commit
1664 bms = repo.nodebookmarks(old.node())
1677 bms = repo.nodebookmarks(old.node())
1665 if bms:
1678 if bms:
1666 for bm in bms:
1679 for bm in bms:
1667 repo._bookmarks[bm] = newid
1680 repo._bookmarks[bm] = newid
1668 bookmarks.write(repo)
1681 bookmarks.write(repo)
1669
1682
1670 # Strip the intermediate commit (if there was one) and the amended
1683 # Strip the intermediate commit (if there was one) and the amended
1671 # commit
1684 # commit
1672 lock = repo.lock()
1685 lock = repo.lock()
1673 try:
1686 try:
1674 if node:
1687 if node:
1675 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1688 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1676 ui.note(_('stripping amended changeset %s\n') % old)
1689 ui.note(_('stripping amended changeset %s\n') % old)
1677 repair.strip(ui, repo, old.node(), topic='amend-backup')
1690 repair.strip(ui, repo, old.node(), topic='amend-backup')
1678 finally:
1691 finally:
1679 lock.release()
1692 lock.release()
1680 finally:
1693 finally:
1681 wlock.release()
1694 wlock.release()
1682 return newid
1695 return newid
1683
1696
1684 def commiteditor(repo, ctx, subs):
1697 def commiteditor(repo, ctx, subs):
1685 if ctx.description():
1698 if ctx.description():
1686 return ctx.description()
1699 return ctx.description()
1687 return commitforceeditor(repo, ctx, subs)
1700 return commitforceeditor(repo, ctx, subs)
1688
1701
1689 def commitforceeditor(repo, ctx, subs):
1702 def commitforceeditor(repo, ctx, subs):
1690 edittext = []
1703 edittext = []
1691 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1704 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1692 if ctx.description():
1705 if ctx.description():
1693 edittext.append(ctx.description())
1706 edittext.append(ctx.description())
1694 edittext.append("")
1707 edittext.append("")
1695 edittext.append("") # Empty line between message and comments.
1708 edittext.append("") # Empty line between message and comments.
1696 edittext.append(_("HG: Enter commit message."
1709 edittext.append(_("HG: Enter commit message."
1697 " Lines beginning with 'HG:' are removed."))
1710 " Lines beginning with 'HG:' are removed."))
1698 edittext.append(_("HG: Leave message empty to abort commit."))
1711 edittext.append(_("HG: Leave message empty to abort commit."))
1699 edittext.append("HG: --")
1712 edittext.append("HG: --")
1700 edittext.append(_("HG: user: %s") % ctx.user())
1713 edittext.append(_("HG: user: %s") % ctx.user())
1701 if ctx.p2():
1714 if ctx.p2():
1702 edittext.append(_("HG: branch merge"))
1715 edittext.append(_("HG: branch merge"))
1703 if ctx.branch():
1716 if ctx.branch():
1704 edittext.append(_("HG: branch '%s'") % ctx.branch())
1717 edittext.append(_("HG: branch '%s'") % ctx.branch())
1705 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1718 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1706 edittext.extend([_("HG: added %s") % f for f in added])
1719 edittext.extend([_("HG: added %s") % f for f in added])
1707 edittext.extend([_("HG: changed %s") % f for f in modified])
1720 edittext.extend([_("HG: changed %s") % f for f in modified])
1708 edittext.extend([_("HG: removed %s") % f for f in removed])
1721 edittext.extend([_("HG: removed %s") % f for f in removed])
1709 if not added and not modified and not removed:
1722 if not added and not modified and not removed:
1710 edittext.append(_("HG: no files changed"))
1723 edittext.append(_("HG: no files changed"))
1711 edittext.append("")
1724 edittext.append("")
1712 # run editor in the repository root
1725 # run editor in the repository root
1713 olddir = os.getcwd()
1726 olddir = os.getcwd()
1714 os.chdir(repo.root)
1727 os.chdir(repo.root)
1715 text = repo.ui.edit("\n".join(edittext), ctx.user())
1728 text = repo.ui.edit("\n".join(edittext), ctx.user())
1716 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1729 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1717 os.chdir(olddir)
1730 os.chdir(olddir)
1718
1731
1719 if not text.strip():
1732 if not text.strip():
1720 raise util.Abort(_("empty commit message"))
1733 raise util.Abort(_("empty commit message"))
1721
1734
1722 return text
1735 return text
1723
1736
1724 def revert(ui, repo, ctx, parents, *pats, **opts):
1737 def revert(ui, repo, ctx, parents, *pats, **opts):
1725 parent, p2 = parents
1738 parent, p2 = parents
1726 node = ctx.node()
1739 node = ctx.node()
1727
1740
1728 mf = ctx.manifest()
1741 mf = ctx.manifest()
1729 if node == parent:
1742 if node == parent:
1730 pmf = mf
1743 pmf = mf
1731 else:
1744 else:
1732 pmf = None
1745 pmf = None
1733
1746
1734 # need all matching names in dirstate and manifest of target rev,
1747 # need all matching names in dirstate and manifest of target rev,
1735 # so have to walk both. do not print errors if files exist in one
1748 # so have to walk both. do not print errors if files exist in one
1736 # but not other.
1749 # but not other.
1737
1750
1738 names = {}
1751 names = {}
1739
1752
1740 wlock = repo.wlock()
1753 wlock = repo.wlock()
1741 try:
1754 try:
1742 # walk dirstate.
1755 # walk dirstate.
1743
1756
1744 m = scmutil.match(repo[None], pats, opts)
1757 m = scmutil.match(repo[None], pats, opts)
1745 m.bad = lambda x, y: False
1758 m.bad = lambda x, y: False
1746 for abs in repo.walk(m):
1759 for abs in repo.walk(m):
1747 names[abs] = m.rel(abs), m.exact(abs)
1760 names[abs] = m.rel(abs), m.exact(abs)
1748
1761
1749 # walk target manifest.
1762 # walk target manifest.
1750
1763
1751 def badfn(path, msg):
1764 def badfn(path, msg):
1752 if path in names:
1765 if path in names:
1753 return
1766 return
1754 if path in ctx.substate:
1767 if path in ctx.substate:
1755 return
1768 return
1756 path_ = path + '/'
1769 path_ = path + '/'
1757 for f in names:
1770 for f in names:
1758 if f.startswith(path_):
1771 if f.startswith(path_):
1759 return
1772 return
1760 ui.warn("%s: %s\n" % (m.rel(path), msg))
1773 ui.warn("%s: %s\n" % (m.rel(path), msg))
1761
1774
1762 m = scmutil.match(ctx, pats, opts)
1775 m = scmutil.match(ctx, pats, opts)
1763 m.bad = badfn
1776 m.bad = badfn
1764 for abs in ctx.walk(m):
1777 for abs in ctx.walk(m):
1765 if abs not in names:
1778 if abs not in names:
1766 names[abs] = m.rel(abs), m.exact(abs)
1779 names[abs] = m.rel(abs), m.exact(abs)
1767
1780
1768 # get the list of subrepos that must be reverted
1781 # get the list of subrepos that must be reverted
1769 targetsubs = [s for s in ctx.substate if m(s)]
1782 targetsubs = [s for s in ctx.substate if m(s)]
1770 m = scmutil.matchfiles(repo, names)
1783 m = scmutil.matchfiles(repo, names)
1771 changes = repo.status(match=m)[:4]
1784 changes = repo.status(match=m)[:4]
1772 modified, added, removed, deleted = map(set, changes)
1785 modified, added, removed, deleted = map(set, changes)
1773
1786
1774 # if f is a rename, also revert the source
1787 # if f is a rename, also revert the source
1775 cwd = repo.getcwd()
1788 cwd = repo.getcwd()
1776 for f in added:
1789 for f in added:
1777 src = repo.dirstate.copied(f)
1790 src = repo.dirstate.copied(f)
1778 if src and src not in names and repo.dirstate[src] == 'r':
1791 if src and src not in names and repo.dirstate[src] == 'r':
1779 removed.add(src)
1792 removed.add(src)
1780 names[src] = (repo.pathto(src, cwd), True)
1793 names[src] = (repo.pathto(src, cwd), True)
1781
1794
1782 def removeforget(abs):
1795 def removeforget(abs):
1783 if repo.dirstate[abs] == 'a':
1796 if repo.dirstate[abs] == 'a':
1784 return _('forgetting %s\n')
1797 return _('forgetting %s\n')
1785 return _('removing %s\n')
1798 return _('removing %s\n')
1786
1799
1787 revert = ([], _('reverting %s\n'))
1800 revert = ([], _('reverting %s\n'))
1788 add = ([], _('adding %s\n'))
1801 add = ([], _('adding %s\n'))
1789 remove = ([], removeforget)
1802 remove = ([], removeforget)
1790 undelete = ([], _('undeleting %s\n'))
1803 undelete = ([], _('undeleting %s\n'))
1791
1804
1792 disptable = (
1805 disptable = (
1793 # dispatch table:
1806 # dispatch table:
1794 # file state
1807 # file state
1795 # action if in target manifest
1808 # action if in target manifest
1796 # action if not in target manifest
1809 # action if not in target manifest
1797 # make backup if in target manifest
1810 # make backup if in target manifest
1798 # make backup if not in target manifest
1811 # make backup if not in target manifest
1799 (modified, revert, remove, True, True),
1812 (modified, revert, remove, True, True),
1800 (added, revert, remove, True, False),
1813 (added, revert, remove, True, False),
1801 (removed, undelete, None, False, False),
1814 (removed, undelete, None, False, False),
1802 (deleted, revert, remove, False, False),
1815 (deleted, revert, remove, False, False),
1803 )
1816 )
1804
1817
1805 for abs, (rel, exact) in sorted(names.items()):
1818 for abs, (rel, exact) in sorted(names.items()):
1806 mfentry = mf.get(abs)
1819 mfentry = mf.get(abs)
1807 target = repo.wjoin(abs)
1820 target = repo.wjoin(abs)
1808 def handle(xlist, dobackup):
1821 def handle(xlist, dobackup):
1809 xlist[0].append(abs)
1822 xlist[0].append(abs)
1810 if (dobackup and not opts.get('no_backup') and
1823 if (dobackup and not opts.get('no_backup') and
1811 os.path.lexists(target)):
1824 os.path.lexists(target)):
1812 bakname = "%s.orig" % rel
1825 bakname = "%s.orig" % rel
1813 ui.note(_('saving current version of %s as %s\n') %
1826 ui.note(_('saving current version of %s as %s\n') %
1814 (rel, bakname))
1827 (rel, bakname))
1815 if not opts.get('dry_run'):
1828 if not opts.get('dry_run'):
1816 util.rename(target, bakname)
1829 util.rename(target, bakname)
1817 if ui.verbose or not exact:
1830 if ui.verbose or not exact:
1818 msg = xlist[1]
1831 msg = xlist[1]
1819 if not isinstance(msg, basestring):
1832 if not isinstance(msg, basestring):
1820 msg = msg(abs)
1833 msg = msg(abs)
1821 ui.status(msg % rel)
1834 ui.status(msg % rel)
1822 for table, hitlist, misslist, backuphit, backupmiss in disptable:
1835 for table, hitlist, misslist, backuphit, backupmiss in disptable:
1823 if abs not in table:
1836 if abs not in table:
1824 continue
1837 continue
1825 # file has changed in dirstate
1838 # file has changed in dirstate
1826 if mfentry:
1839 if mfentry:
1827 handle(hitlist, backuphit)
1840 handle(hitlist, backuphit)
1828 elif misslist is not None:
1841 elif misslist is not None:
1829 handle(misslist, backupmiss)
1842 handle(misslist, backupmiss)
1830 break
1843 break
1831 else:
1844 else:
1832 if abs not in repo.dirstate:
1845 if abs not in repo.dirstate:
1833 if mfentry:
1846 if mfentry:
1834 handle(add, True)
1847 handle(add, True)
1835 elif exact:
1848 elif exact:
1836 ui.warn(_('file not managed: %s\n') % rel)
1849 ui.warn(_('file not managed: %s\n') % rel)
1837 continue
1850 continue
1838 # file has not changed in dirstate
1851 # file has not changed in dirstate
1839 if node == parent:
1852 if node == parent:
1840 if exact:
1853 if exact:
1841 ui.warn(_('no changes needed to %s\n') % rel)
1854 ui.warn(_('no changes needed to %s\n') % rel)
1842 continue
1855 continue
1843 if pmf is None:
1856 if pmf is None:
1844 # only need parent manifest in this unlikely case,
1857 # only need parent manifest in this unlikely case,
1845 # so do not read by default
1858 # so do not read by default
1846 pmf = repo[parent].manifest()
1859 pmf = repo[parent].manifest()
1847 if abs in pmf and mfentry:
1860 if abs in pmf and mfentry:
1848 # if version of file is same in parent and target
1861 # if version of file is same in parent and target
1849 # manifests, do nothing
1862 # manifests, do nothing
1850 if (pmf[abs] != mfentry or
1863 if (pmf[abs] != mfentry or
1851 pmf.flags(abs) != mf.flags(abs)):
1864 pmf.flags(abs) != mf.flags(abs)):
1852 handle(revert, False)
1865 handle(revert, False)
1853 else:
1866 else:
1854 handle(remove, False)
1867 handle(remove, False)
1855
1868
1856 if not opts.get('dry_run'):
1869 if not opts.get('dry_run'):
1857 def checkout(f):
1870 def checkout(f):
1858 fc = ctx[f]
1871 fc = ctx[f]
1859 repo.wwrite(f, fc.data(), fc.flags())
1872 repo.wwrite(f, fc.data(), fc.flags())
1860
1873
1861 audit_path = scmutil.pathauditor(repo.root)
1874 audit_path = scmutil.pathauditor(repo.root)
1862 for f in remove[0]:
1875 for f in remove[0]:
1863 if repo.dirstate[f] == 'a':
1876 if repo.dirstate[f] == 'a':
1864 repo.dirstate.drop(f)
1877 repo.dirstate.drop(f)
1865 continue
1878 continue
1866 audit_path(f)
1879 audit_path(f)
1867 try:
1880 try:
1868 util.unlinkpath(repo.wjoin(f))
1881 util.unlinkpath(repo.wjoin(f))
1869 except OSError:
1882 except OSError:
1870 pass
1883 pass
1871 repo.dirstate.remove(f)
1884 repo.dirstate.remove(f)
1872
1885
1873 normal = None
1886 normal = None
1874 if node == parent:
1887 if node == parent:
1875 # We're reverting to our parent. If possible, we'd like status
1888 # We're reverting to our parent. If possible, we'd like status
1876 # to report the file as clean. We have to use normallookup for
1889 # to report the file as clean. We have to use normallookup for
1877 # merges to avoid losing information about merged/dirty files.
1890 # merges to avoid losing information about merged/dirty files.
1878 if p2 != nullid:
1891 if p2 != nullid:
1879 normal = repo.dirstate.normallookup
1892 normal = repo.dirstate.normallookup
1880 else:
1893 else:
1881 normal = repo.dirstate.normal
1894 normal = repo.dirstate.normal
1882 for f in revert[0]:
1895 for f in revert[0]:
1883 checkout(f)
1896 checkout(f)
1884 if normal:
1897 if normal:
1885 normal(f)
1898 normal(f)
1886
1899
1887 for f in add[0]:
1900 for f in add[0]:
1888 checkout(f)
1901 checkout(f)
1889 repo.dirstate.add(f)
1902 repo.dirstate.add(f)
1890
1903
1891 normal = repo.dirstate.normallookup
1904 normal = repo.dirstate.normallookup
1892 if node == parent and p2 == nullid:
1905 if node == parent and p2 == nullid:
1893 normal = repo.dirstate.normal
1906 normal = repo.dirstate.normal
1894 for f in undelete[0]:
1907 for f in undelete[0]:
1895 checkout(f)
1908 checkout(f)
1896 normal(f)
1909 normal(f)
1897
1910
1898 if targetsubs:
1911 if targetsubs:
1899 # Revert the subrepos on the revert list
1912 # Revert the subrepos on the revert list
1900 for sub in targetsubs:
1913 for sub in targetsubs:
1901 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
1914 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
1902 finally:
1915 finally:
1903 wlock.release()
1916 wlock.release()
1904
1917
1905 def command(table):
1918 def command(table):
1906 '''returns a function object bound to table which can be used as
1919 '''returns a function object bound to table which can be used as
1907 a decorator for populating table as a command table'''
1920 a decorator for populating table as a command table'''
1908
1921
1909 def cmd(name, options, synopsis=None):
1922 def cmd(name, options, synopsis=None):
1910 def decorator(func):
1923 def decorator(func):
1911 if synopsis:
1924 if synopsis:
1912 table[name] = func, options[:], synopsis
1925 table[name] = func, options[:], synopsis
1913 else:
1926 else:
1914 table[name] = func, options[:]
1927 table[name] = func, options[:]
1915 return func
1928 return func
1916 return decorator
1929 return decorator
1917
1930
1918 return cmd
1931 return cmd
@@ -1,5825 +1,5848 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec
19 import random, setdiscovery, treediscovery, dagutil, pvec
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ] + templateopts
102 ] + templateopts
102
103
103 diffopts = [
104 diffopts = [
104 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
105 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ]
108 ]
108
109
109 diffwsopts = [
110 diffwsopts = [
110 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
111 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
112 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
113 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
114 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
115 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
116 ]
117 ]
117
118
118 diffopts2 = [
119 diffopts2 = [
119 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ] + diffwsopts + [
122 ] + diffwsopts + [
122 ('U', 'unified', '',
123 ('U', 'unified', '',
123 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ]
126 ]
126
127
127 mergetoolopts = [
128 mergetoolopts = [
128 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
129 ]
130 ]
130
131
131 similarityopts = [
132 similarityopts = [
132 ('s', 'similarity', '',
133 ('s', 'similarity', '',
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 ]
135 ]
135
136
136 subrepoopts = [
137 subrepoopts = [
137 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
138 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
139 ]
140 ]
140
141
141 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
142
143
143 @command('^add',
144 @command('^add',
144 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
145 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
146 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
147 """add the specified files on the next commit
148 """add the specified files on the next commit
148
149
149 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
150 repository.
151 repository.
151
152
152 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
153 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
154
155
155 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
156
157
157 .. container:: verbose
158 .. container:: verbose
158
159
159 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
160 automatically by :hg:`add`::
161 automatically by :hg:`add`::
161
162
162 $ ls
163 $ ls
163 foo.c
164 foo.c
164 $ hg status
165 $ hg status
165 ? foo.c
166 ? foo.c
166 $ hg add
167 $ hg add
167 adding foo.c
168 adding foo.c
168 $ hg status
169 $ hg status
169 A foo.c
170 A foo.c
170
171
171 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
172 """
173 """
173
174
174 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 return rejected and 1 or 0
178 return rejected and 1 or 0
178
179
179 @command('addremove',
180 @command('addremove',
180 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
181 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
182 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
183 """add all new files, delete all missing files
184 """add all new files, delete all missing files
184
185
185 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
186 repository.
187 repository.
187
188
188 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
189 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
190 commit.
191 commit.
191
192
192 Use the -s/--similarity option to detect renamed files. With a
193 Use the -s/--similarity option to detect renamed files. With a
193 parameter greater than 0, this compares every removed file with
194 parameter greater than 0, this compares every removed file with
194 every added file and records those similar enough as renames. This
195 every added file and records those similar enough as renames. This
195 option takes a percentage between 0 (disabled) and 100 (files must
196 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. Detecting renamed files this way
197 be identical) as its parameter. Detecting renamed files this way
197 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
198 used to check which files were identified as moved or renamed.
199 used to check which files were identified as moved or renamed.
199 If this option is not specified, only renames of identical files
200 If this option is not specified, only renames of identical files
200 are detected.
201 are detected.
201
202
202 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
203 """
204 """
204 try:
205 try:
205 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
206 except ValueError:
207 except ValueError:
207 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
208 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
209 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211
212
212 @command('^annotate|blame',
213 @command('^annotate|blame',
213 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 ('', 'follow', None,
215 ('', 'follow', None,
215 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
218 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
220 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
225 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
227 """show changeset information by line for each file
228 """show changeset information by line for each file
228
229
229 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
230 each line
231 each line
231
232
232 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
233 by whom.
234 by whom.
234
235
235 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
236 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
237 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
238 nor desirable.
239 nor desirable.
239
240
240 Returns 0 on success.
241 Returns 0 on success.
241 """
242 """
242 if opts.get('follow'):
243 if opts.get('follow'):
243 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
244 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
245 opts['file'] = True
246 opts['file'] = True
246
247
247 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249
250
250 if not pats:
251 if not pats:
251 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
252
253
253 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
254
255
255 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('date', ' ', getdate),
259 ('date', ' ', getdate),
259 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
260 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
261 ]
262 ]
262
263
263 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
264 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
265 opts['number'] = True
266 opts['number'] = True
266
267
267 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
268 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270
271
271 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273
274
274 def bad(x, y):
275 def bad(x, y):
275 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
276
277
277 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
279 m.bad = bad
280 m.bad = bad
280 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
281 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
283 fctx = ctx[abs]
284 fctx = ctx[abs]
284 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
285 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 continue
287 continue
287
288
288 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 diffopts=diffopts)
290 diffopts=diffopts)
290 pieces = []
291 pieces = []
291
292
292 for f, sep in funcmap:
293 for f, sep in funcmap:
293 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
294 if l:
295 if l:
295 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
297 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 for x, w in sized])
299 for x, w in sized])
299
300
300 if pieces:
301 if pieces:
301 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
302 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
303
304
304 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
305 ui.write('\n')
306 ui.write('\n')
306
307
307 @command('archive',
308 @command('archive',
308 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 _('PREFIX')),
311 _('PREFIX')),
311 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
314 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
315 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
316 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
317
318
318 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
319 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
320
321
321 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
322 extension (or override using -t/--type).
323 extension (or override using -t/--type).
323
324
324 .. container:: verbose
325 .. container:: verbose
325
326
326 Examples:
327 Examples:
327
328
328 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
329
330
330 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
331
332
332 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
333
334
334 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
335
336
336 Valid types are:
337 Valid types are:
337
338
338 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
339 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
340 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
342 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
343 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
344
345
345 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
346 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
347
348
348 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
349 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
350 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
351 removed.
352 removed.
352
353
353 Returns 0 on success.
354 Returns 0 on success.
354 '''
355 '''
355
356
356 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 if not ctx:
358 if not ctx:
358 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
359 node = ctx.node()
360 node = ctx.node()
360 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
361 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
362 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
363
364
364 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
366
367
367 if dest == '-':
368 if dest == '-':
368 if kind == 'files':
369 if kind == 'files':
369 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
371 if not prefix:
372 if not prefix:
372 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
373
374
374 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
376 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378
379
379 @command('backout',
380 @command('backout',
380 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 ('', 'parent', '',
382 ('', 'parent', '',
382 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
386 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
387 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
388
389
389 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
390 current working directory.
391 current working directory.
391
392
392 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
393 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
394 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
395
396
396 .. note::
397 .. note::
397 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
398 incorrect merge.
399 incorrect merge.
399
400
400 .. container:: verbose
401 .. container:: verbose
401
402
402 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
403 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
404 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
405 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
406
407
407 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
408 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
409 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
410 merged separately.
411 merged separately.
411
412
412 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413
414
414 Returns 0 on success.
415 Returns 0 on success.
415 '''
416 '''
416 if rev and node:
417 if rev and node:
417 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
418
419
419 if not rev:
420 if not rev:
420 rev = node
421 rev = node
421
422
422 if not rev:
423 if not rev:
423 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
424
425
425 date = opts.get('date')
426 date = opts.get('date')
426 if date:
427 if date:
427 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
428
429
429 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
430 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
431
432
432 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
433 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
434 if a != node:
435 if a != node:
435 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
436
437
437 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
438 if p1 == nullid:
439 if p1 == nullid:
439 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
440 if p2 != nullid:
441 if p2 != nullid:
441 if not opts.get('parent'):
442 if not opts.get('parent'):
442 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
443 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
444 if p not in (p1, p2):
445 if p not in (p1, p2):
445 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
446 (short(p), short(node)))
447 (short(p), short(node)))
447 parent = p
448 parent = p
448 else:
449 else:
449 if opts.get('parent'):
450 if opts.get('parent'):
450 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 parent = p1
452 parent = p1
452
453
453 # the backout should appear on the same branch
454 # the backout should appear on the same branch
454 wlock = repo.wlock()
455 wlock = repo.wlock()
455 try:
456 try:
456 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
457 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
458 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
459 revert_opts = opts.copy()
460 revert_opts = opts.copy()
460 revert_opts['date'] = None
461 revert_opts['date'] = None
461 revert_opts['all'] = True
462 revert_opts['all'] = True
462 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
463 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
464 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
465 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
466 try:
467 try:
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 return hg.update(repo, op1)
469 return hg.update(repo, op1)
469 finally:
470 finally:
470 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
471
472
472 commit_opts = opts.copy()
473 commit_opts = opts.copy()
473 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
474 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 # we don't translate commit messages
476 # we don't translate commit messages
476 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
478 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
479 def nice(node):
480 def nice(node):
480 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
483 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
484 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
485 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
486 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
487 try:
488 try:
488 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 finally:
491 finally:
491 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
492 finally:
493 finally:
493 wlock.release()
494 wlock.release()
494 return 0
495 return 0
495
496
496 @command('bisect',
497 @command('bisect',
497 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
498 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
504 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 noupdate=None):
508 noupdate=None):
508 """subdivision search of changesets
509 """subdivision search of changesets
509
510
510 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
511 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
512 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
513 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
514 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
515 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
516 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
517 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
518
519
519 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
520 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
521
522
522 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
523 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
524 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
525 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
526 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
527 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
528 is bad.
529 is bad.
529
530
530 .. container:: verbose
531 .. container:: verbose
531
532
532 Some examples:
533 Some examples:
533
534
534 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
535
536
536 hg bisect --bad 34
537 hg bisect --bad 34
537 hg bisect --good 12
538 hg bisect --good 12
538
539
539 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
540 bad::
541 bad::
541
542
542 hg bisect --good
543 hg bisect --good
543 hg bisect --bad
544 hg bisect --bad
544
545
545 - mark the current revision, or a known revision, to be skipped (eg. if
546 - mark the current revision, or a known revision, to be skipped (eg. if
546 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
547
548
548 hg bisect --skip
549 hg bisect --skip
549 hg bisect --skip 23
550 hg bisect --skip 23
550
551
551 - forget the current bisection::
552 - forget the current bisection::
552
553
553 hg bisect --reset
554 hg bisect --reset
554
555
555 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
556 revision::
557 revision::
557
558
558 hg bisect --reset
559 hg bisect --reset
559 hg bisect --bad 34
560 hg bisect --bad 34
560 hg bisect --good 12
561 hg bisect --good 12
561 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
562
563
563 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
564 bisection::
565 bisection::
565
566
566 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
567
568
568 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
569 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
570
571
571 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
572
573
573 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
574
575
575 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
576
577
577 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
578
579
579 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
580
581
581 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582
583
583 Returns 0 on success.
584 Returns 0 on success.
584 """
585 """
585 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
586 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
587 # one of the parent was not checked.
588 # one of the parent was not checked.
588 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
589 if len(parents) > 1:
590 if len(parents) > 1:
590 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
591 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
592 if num == 1:
593 if num == 1:
593 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
594 return None
595 return None
595
596
596 def print_result(nodes, good):
597 def print_result(nodes, good):
597 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 if len(nodes) == 1:
599 if len(nodes) == 1:
599 # narrowed it down to a single revision
600 # narrowed it down to a single revision
600 if good:
601 if good:
601 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
602 else:
603 else:
603 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
604 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
605 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
606 if extendnode is not None:
607 if extendnode is not None:
607 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
608 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
609 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
610 % extendnode)
611 % extendnode)
611 else:
612 else:
612 # multiple possible revisions
613 # multiple possible revisions
613 if good:
614 if good:
614 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
615 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
616 else:
617 else:
617 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
618 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
619 for n in nodes:
620 for n in nodes:
620 displayer.show(repo[n])
621 displayer.show(repo[n])
621 displayer.close()
622 displayer.close()
622
623
623 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
624 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
625 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
626 return
627 return
627 if not state['good']:
628 if not state['good']:
628 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 else:
630 else:
630 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 return True
632 return True
632
633
633 # backward compatibility
634 # backward compatibility
634 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
635 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
637 if cmd == "good":
638 if cmd == "good":
638 good = True
639 good = True
639 elif cmd == "bad":
640 elif cmd == "bad":
640 bad = True
641 bad = True
641 else:
642 else:
642 reset = True
643 reset = True
643 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
645
646
646 if reset:
647 if reset:
647 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
648 if os.path.exists(p):
649 if os.path.exists(p):
649 os.unlink(p)
650 os.unlink(p)
650 return
651 return
651
652
652 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
653
654
654 if command:
655 if command:
655 changesets = 1
656 changesets = 1
656 try:
657 try:
657 node = state['current'][0]
658 node = state['current'][0]
658 except LookupError:
659 except LookupError:
659 if noupdate:
660 if noupdate:
660 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
661 'start a new bisect to fix'))
662 'start a new bisect to fix'))
662 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
663 if p2 != nullid:
664 if p2 != nullid:
664 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
665 try:
666 try:
666 while changesets:
667 while changesets:
667 # update state
668 # update state
668 state['current'] = [node]
669 state['current'] = [node]
669 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
670 status = util.system(command,
671 status = util.system(command,
671 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
672 out=ui.fout)
673 out=ui.fout)
673 if status == 125:
674 if status == 125:
674 transition = "skip"
675 transition = "skip"
675 elif status == 0:
676 elif status == 0:
676 transition = "good"
677 transition = "good"
677 # status < 0 means process was killed
678 # status < 0 means process was killed
678 elif status == 127:
679 elif status == 127:
679 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
680 elif status < 0:
681 elif status < 0:
681 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
682 else:
683 else:
683 transition = "bad"
684 transition = "bad"
684 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
685 rev = None # clear for future iterations
686 rev = None # clear for future iterations
686 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
687 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 check_state(state, interactive=False)
689 check_state(state, interactive=False)
689 # bisect
690 # bisect
690 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 # update to next check
692 # update to next check
692 node = nodes[0]
693 node = nodes[0]
693 if not noupdate:
694 if not noupdate:
694 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
695 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
696 finally:
697 finally:
697 state['current'] = [node]
698 state['current'] = [node]
698 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
699 print_result(nodes, good)
700 print_result(nodes, good)
700 return
701 return
701
702
702 # update state
703 # update state
703
704
704 if rev:
705 if rev:
705 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 else:
707 else:
707 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
708
709
709 if good or bad or skip:
710 if good or bad or skip:
710 if good:
711 if good:
711 state['good'] += nodes
712 state['good'] += nodes
712 elif bad:
713 elif bad:
713 state['bad'] += nodes
714 state['bad'] += nodes
714 elif skip:
715 elif skip:
715 state['skip'] += nodes
716 state['skip'] += nodes
716 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
717
718
718 if not check_state(state):
719 if not check_state(state):
719 return
720 return
720
721
721 # actually bisect
722 # actually bisect
722 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 if extend:
724 if extend:
724 if not changesets:
725 if not changesets:
725 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
726 if extendnode is not None:
727 if extendnode is not None:
727 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
728 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
729 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
730 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
731 if noupdate:
732 if noupdate:
732 return
733 return
733 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
734 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
735 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
736
737
737 if changesets == 0:
738 if changesets == 0:
738 print_result(nodes, good)
739 print_result(nodes, good)
739 else:
740 else:
740 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
741 node = nodes[0]
742 node = nodes[0]
742 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
743 tests, size = 0, 2
744 tests, size = 0, 2
744 while size <= changesets:
745 while size <= changesets:
745 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
746 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
747 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
748 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
749 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
750 state['current'] = [node]
751 state['current'] = [node]
751 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
752 if not noupdate:
753 if not noupdate:
753 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
754 return hg.clean(repo, node)
755 return hg.clean(repo, node)
755
756
756 @command('bookmarks',
757 @command('bookmarks',
757 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
758 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 rename=None, inactive=False):
765 rename=None, inactive=False):
765 '''track a line of development with movable markers
766 '''track a line of development with movable markers
766
767
767 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
771
772
772 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
774 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
775 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
776
777
777 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
779 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
781
782
782 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
783 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
785 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
786 '''
787 '''
787 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
788 marks = repo._bookmarks
789 marks = repo._bookmarks
789 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
790
791
791 if delete:
792 if delete:
792 if mark is None:
793 if mark is None:
793 raise util.Abort(_("bookmark name required"))
794 raise util.Abort(_("bookmark name required"))
794 if mark not in marks:
795 if mark not in marks:
795 raise util.Abort(_("bookmark '%s' does not exist") % mark)
796 raise util.Abort(_("bookmark '%s' does not exist") % mark)
796 if mark == repo._bookmarkcurrent:
797 if mark == repo._bookmarkcurrent:
797 bookmarks.setcurrent(repo, None)
798 bookmarks.setcurrent(repo, None)
798 del marks[mark]
799 del marks[mark]
799 bookmarks.write(repo)
800 bookmarks.write(repo)
800 return
801 return
801
802
802 if rename:
803 if rename:
803 if rename not in marks:
804 if rename not in marks:
804 raise util.Abort(_("bookmark '%s' does not exist") % rename)
805 raise util.Abort(_("bookmark '%s' does not exist") % rename)
805 if mark in marks and not force:
806 if mark in marks and not force:
806 raise util.Abort(_("bookmark '%s' already exists "
807 raise util.Abort(_("bookmark '%s' already exists "
807 "(use -f to force)") % mark)
808 "(use -f to force)") % mark)
808 if mark is None:
809 if mark is None:
809 raise util.Abort(_("new bookmark name required"))
810 raise util.Abort(_("new bookmark name required"))
810 marks[mark] = marks[rename]
811 marks[mark] = marks[rename]
811 if repo._bookmarkcurrent == rename and not inactive:
812 if repo._bookmarkcurrent == rename and not inactive:
812 bookmarks.setcurrent(repo, mark)
813 bookmarks.setcurrent(repo, mark)
813 del marks[rename]
814 del marks[rename]
814 bookmarks.write(repo)
815 bookmarks.write(repo)
815 return
816 return
816
817
817 if mark is not None:
818 if mark is not None:
818 if "\n" in mark:
819 if "\n" in mark:
819 raise util.Abort(_("bookmark name cannot contain newlines"))
820 raise util.Abort(_("bookmark name cannot contain newlines"))
820 mark = mark.strip()
821 mark = mark.strip()
821 if not mark:
822 if not mark:
822 raise util.Abort(_("bookmark names cannot consist entirely of "
823 raise util.Abort(_("bookmark names cannot consist entirely of "
823 "whitespace"))
824 "whitespace"))
824 if inactive and mark == repo._bookmarkcurrent:
825 if inactive and mark == repo._bookmarkcurrent:
825 bookmarks.setcurrent(repo, None)
826 bookmarks.setcurrent(repo, None)
826 return
827 return
827 if mark in marks and not force:
828 if mark in marks and not force:
828 raise util.Abort(_("bookmark '%s' already exists "
829 raise util.Abort(_("bookmark '%s' already exists "
829 "(use -f to force)") % mark)
830 "(use -f to force)") % mark)
830 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
831 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
831 and not force):
832 and not force):
832 raise util.Abort(
833 raise util.Abort(
833 _("a bookmark cannot have the name of an existing branch"))
834 _("a bookmark cannot have the name of an existing branch"))
834 if rev:
835 if rev:
835 marks[mark] = repo.lookup(rev)
836 marks[mark] = repo.lookup(rev)
836 else:
837 else:
837 marks[mark] = cur
838 marks[mark] = cur
838 if not inactive and cur == marks[mark]:
839 if not inactive and cur == marks[mark]:
839 bookmarks.setcurrent(repo, mark)
840 bookmarks.setcurrent(repo, mark)
840 bookmarks.write(repo)
841 bookmarks.write(repo)
841 return
842 return
842
843
843 if mark is None:
844 if mark is None:
844 if rev:
845 if rev:
845 raise util.Abort(_("bookmark name required"))
846 raise util.Abort(_("bookmark name required"))
846 if len(marks) == 0:
847 if len(marks) == 0:
847 ui.status(_("no bookmarks set\n"))
848 ui.status(_("no bookmarks set\n"))
848 else:
849 else:
849 for bmark, n in sorted(marks.iteritems()):
850 for bmark, n in sorted(marks.iteritems()):
850 current = repo._bookmarkcurrent
851 current = repo._bookmarkcurrent
851 if bmark == current and n == cur:
852 if bmark == current and n == cur:
852 prefix, label = '*', 'bookmarks.current'
853 prefix, label = '*', 'bookmarks.current'
853 else:
854 else:
854 prefix, label = ' ', ''
855 prefix, label = ' ', ''
855
856
856 if ui.quiet:
857 if ui.quiet:
857 ui.write("%s\n" % bmark, label=label)
858 ui.write("%s\n" % bmark, label=label)
858 else:
859 else:
859 ui.write(" %s %-25s %d:%s\n" % (
860 ui.write(" %s %-25s %d:%s\n" % (
860 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
861 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
861 label=label)
862 label=label)
862 return
863 return
863
864
864 @command('branch',
865 @command('branch',
865 [('f', 'force', None,
866 [('f', 'force', None,
866 _('set branch name even if it shadows an existing branch')),
867 _('set branch name even if it shadows an existing branch')),
867 ('C', 'clean', None, _('reset branch name to parent branch name'))],
868 ('C', 'clean', None, _('reset branch name to parent branch name'))],
868 _('[-fC] [NAME]'))
869 _('[-fC] [NAME]'))
869 def branch(ui, repo, label=None, **opts):
870 def branch(ui, repo, label=None, **opts):
870 """set or show the current branch name
871 """set or show the current branch name
871
872
872 .. note::
873 .. note::
873 Branch names are permanent and global. Use :hg:`bookmark` to create a
874 Branch names are permanent and global. Use :hg:`bookmark` to create a
874 light-weight bookmark instead. See :hg:`help glossary` for more
875 light-weight bookmark instead. See :hg:`help glossary` for more
875 information about named branches and bookmarks.
876 information about named branches and bookmarks.
876
877
877 With no argument, show the current branch name. With one argument,
878 With no argument, show the current branch name. With one argument,
878 set the working directory branch name (the branch will not exist
879 set the working directory branch name (the branch will not exist
879 in the repository until the next commit). Standard practice
880 in the repository until the next commit). Standard practice
880 recommends that primary development take place on the 'default'
881 recommends that primary development take place on the 'default'
881 branch.
882 branch.
882
883
883 Unless -f/--force is specified, branch will not let you set a
884 Unless -f/--force is specified, branch will not let you set a
884 branch name that already exists, even if it's inactive.
885 branch name that already exists, even if it's inactive.
885
886
886 Use -C/--clean to reset the working directory branch to that of
887 Use -C/--clean to reset the working directory branch to that of
887 the parent of the working directory, negating a previous branch
888 the parent of the working directory, negating a previous branch
888 change.
889 change.
889
890
890 Use the command :hg:`update` to switch to an existing branch. Use
891 Use the command :hg:`update` to switch to an existing branch. Use
891 :hg:`commit --close-branch` to mark this branch as closed.
892 :hg:`commit --close-branch` to mark this branch as closed.
892
893
893 Returns 0 on success.
894 Returns 0 on success.
894 """
895 """
895 if not opts.get('clean') and not label:
896 if not opts.get('clean') and not label:
896 ui.write("%s\n" % repo.dirstate.branch())
897 ui.write("%s\n" % repo.dirstate.branch())
897 return
898 return
898
899
899 wlock = repo.wlock()
900 wlock = repo.wlock()
900 try:
901 try:
901 if opts.get('clean'):
902 if opts.get('clean'):
902 label = repo[None].p1().branch()
903 label = repo[None].p1().branch()
903 repo.dirstate.setbranch(label)
904 repo.dirstate.setbranch(label)
904 ui.status(_('reset working directory to branch %s\n') % label)
905 ui.status(_('reset working directory to branch %s\n') % label)
905 elif label:
906 elif label:
906 if not opts.get('force') and label in repo.branchmap():
907 if not opts.get('force') and label in repo.branchmap():
907 if label not in [p.branch() for p in repo.parents()]:
908 if label not in [p.branch() for p in repo.parents()]:
908 raise util.Abort(_('a branch of the same name already'
909 raise util.Abort(_('a branch of the same name already'
909 ' exists'),
910 ' exists'),
910 # i18n: "it" refers to an existing branch
911 # i18n: "it" refers to an existing branch
911 hint=_("use 'hg update' to switch to it"))
912 hint=_("use 'hg update' to switch to it"))
912 repo.dirstate.setbranch(label)
913 repo.dirstate.setbranch(label)
913 ui.status(_('marked working directory as branch %s\n') % label)
914 ui.status(_('marked working directory as branch %s\n') % label)
914 ui.status(_('(branches are permanent and global, '
915 ui.status(_('(branches are permanent and global, '
915 'did you want a bookmark?)\n'))
916 'did you want a bookmark?)\n'))
916 finally:
917 finally:
917 wlock.release()
918 wlock.release()
918
919
919 @command('branches',
920 @command('branches',
920 [('a', 'active', False, _('show only branches that have unmerged heads')),
921 [('a', 'active', False, _('show only branches that have unmerged heads')),
921 ('c', 'closed', False, _('show normal and closed branches'))],
922 ('c', 'closed', False, _('show normal and closed branches'))],
922 _('[-ac]'))
923 _('[-ac]'))
923 def branches(ui, repo, active=False, closed=False):
924 def branches(ui, repo, active=False, closed=False):
924 """list repository named branches
925 """list repository named branches
925
926
926 List the repository's named branches, indicating which ones are
927 List the repository's named branches, indicating which ones are
927 inactive. If -c/--closed is specified, also list branches which have
928 inactive. If -c/--closed is specified, also list branches which have
928 been marked closed (see :hg:`commit --close-branch`).
929 been marked closed (see :hg:`commit --close-branch`).
929
930
930 If -a/--active is specified, only show active branches. A branch
931 If -a/--active is specified, only show active branches. A branch
931 is considered active if it contains repository heads.
932 is considered active if it contains repository heads.
932
933
933 Use the command :hg:`update` to switch to an existing branch.
934 Use the command :hg:`update` to switch to an existing branch.
934
935
935 Returns 0.
936 Returns 0.
936 """
937 """
937
938
938 hexfunc = ui.debugflag and hex or short
939 hexfunc = ui.debugflag and hex or short
939
940
940 activebranches = set([repo[n].branch() for n in repo.heads()])
941 activebranches = set([repo[n].branch() for n in repo.heads()])
941 branches = []
942 branches = []
942 for tag, heads in repo.branchmap().iteritems():
943 for tag, heads in repo.branchmap().iteritems():
943 for h in reversed(heads):
944 for h in reversed(heads):
944 ctx = repo[h]
945 ctx = repo[h]
945 isopen = not ctx.closesbranch()
946 isopen = not ctx.closesbranch()
946 if isopen:
947 if isopen:
947 tip = ctx
948 tip = ctx
948 break
949 break
949 else:
950 else:
950 tip = repo[heads[-1]]
951 tip = repo[heads[-1]]
951 isactive = tag in activebranches and isopen
952 isactive = tag in activebranches and isopen
952 branches.append((tip, isactive, isopen))
953 branches.append((tip, isactive, isopen))
953 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
954 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
954 reverse=True)
955 reverse=True)
955
956
956 for ctx, isactive, isopen in branches:
957 for ctx, isactive, isopen in branches:
957 if (not active) or isactive:
958 if (not active) or isactive:
958 if isactive:
959 if isactive:
959 label = 'branches.active'
960 label = 'branches.active'
960 notice = ''
961 notice = ''
961 elif not isopen:
962 elif not isopen:
962 if not closed:
963 if not closed:
963 continue
964 continue
964 label = 'branches.closed'
965 label = 'branches.closed'
965 notice = _(' (closed)')
966 notice = _(' (closed)')
966 else:
967 else:
967 label = 'branches.inactive'
968 label = 'branches.inactive'
968 notice = _(' (inactive)')
969 notice = _(' (inactive)')
969 if ctx.branch() == repo.dirstate.branch():
970 if ctx.branch() == repo.dirstate.branch():
970 label = 'branches.current'
971 label = 'branches.current'
971 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
972 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
972 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
973 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
973 'log.changeset')
974 'log.changeset')
974 tag = ui.label(ctx.branch(), label)
975 tag = ui.label(ctx.branch(), label)
975 if ui.quiet:
976 if ui.quiet:
976 ui.write("%s\n" % tag)
977 ui.write("%s\n" % tag)
977 else:
978 else:
978 ui.write("%s %s%s\n" % (tag, rev, notice))
979 ui.write("%s %s%s\n" % (tag, rev, notice))
979
980
980 @command('bundle',
981 @command('bundle',
981 [('f', 'force', None, _('run even when the destination is unrelated')),
982 [('f', 'force', None, _('run even when the destination is unrelated')),
982 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
983 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
983 _('REV')),
984 _('REV')),
984 ('b', 'branch', [], _('a specific branch you would like to bundle'),
985 ('b', 'branch', [], _('a specific branch you would like to bundle'),
985 _('BRANCH')),
986 _('BRANCH')),
986 ('', 'base', [],
987 ('', 'base', [],
987 _('a base changeset assumed to be available at the destination'),
988 _('a base changeset assumed to be available at the destination'),
988 _('REV')),
989 _('REV')),
989 ('a', 'all', None, _('bundle all changesets in the repository')),
990 ('a', 'all', None, _('bundle all changesets in the repository')),
990 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
991 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
991 ] + remoteopts,
992 ] + remoteopts,
992 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
993 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
993 def bundle(ui, repo, fname, dest=None, **opts):
994 def bundle(ui, repo, fname, dest=None, **opts):
994 """create a changegroup file
995 """create a changegroup file
995
996
996 Generate a compressed changegroup file collecting changesets not
997 Generate a compressed changegroup file collecting changesets not
997 known to be in another repository.
998 known to be in another repository.
998
999
999 If you omit the destination repository, then hg assumes the
1000 If you omit the destination repository, then hg assumes the
1000 destination will have all the nodes you specify with --base
1001 destination will have all the nodes you specify with --base
1001 parameters. To create a bundle containing all changesets, use
1002 parameters. To create a bundle containing all changesets, use
1002 -a/--all (or --base null).
1003 -a/--all (or --base null).
1003
1004
1004 You can change compression method with the -t/--type option.
1005 You can change compression method with the -t/--type option.
1005 The available compression methods are: none, bzip2, and
1006 The available compression methods are: none, bzip2, and
1006 gzip (by default, bundles are compressed using bzip2).
1007 gzip (by default, bundles are compressed using bzip2).
1007
1008
1008 The bundle file can then be transferred using conventional means
1009 The bundle file can then be transferred using conventional means
1009 and applied to another repository with the unbundle or pull
1010 and applied to another repository with the unbundle or pull
1010 command. This is useful when direct push and pull are not
1011 command. This is useful when direct push and pull are not
1011 available or when exporting an entire repository is undesirable.
1012 available or when exporting an entire repository is undesirable.
1012
1013
1013 Applying bundles preserves all changeset contents including
1014 Applying bundles preserves all changeset contents including
1014 permissions, copy/rename information, and revision history.
1015 permissions, copy/rename information, and revision history.
1015
1016
1016 Returns 0 on success, 1 if no changes found.
1017 Returns 0 on success, 1 if no changes found.
1017 """
1018 """
1018 revs = None
1019 revs = None
1019 if 'rev' in opts:
1020 if 'rev' in opts:
1020 revs = scmutil.revrange(repo, opts['rev'])
1021 revs = scmutil.revrange(repo, opts['rev'])
1021
1022
1022 bundletype = opts.get('type', 'bzip2').lower()
1023 bundletype = opts.get('type', 'bzip2').lower()
1023 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1024 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1024 bundletype = btypes.get(bundletype)
1025 bundletype = btypes.get(bundletype)
1025 if bundletype not in changegroup.bundletypes:
1026 if bundletype not in changegroup.bundletypes:
1026 raise util.Abort(_('unknown bundle type specified with --type'))
1027 raise util.Abort(_('unknown bundle type specified with --type'))
1027
1028
1028 if opts.get('all'):
1029 if opts.get('all'):
1029 base = ['null']
1030 base = ['null']
1030 else:
1031 else:
1031 base = scmutil.revrange(repo, opts.get('base'))
1032 base = scmutil.revrange(repo, opts.get('base'))
1032 if base:
1033 if base:
1033 if dest:
1034 if dest:
1034 raise util.Abort(_("--base is incompatible with specifying "
1035 raise util.Abort(_("--base is incompatible with specifying "
1035 "a destination"))
1036 "a destination"))
1036 common = [repo.lookup(rev) for rev in base]
1037 common = [repo.lookup(rev) for rev in base]
1037 heads = revs and map(repo.lookup, revs) or revs
1038 heads = revs and map(repo.lookup, revs) or revs
1038 cg = repo.getbundle('bundle', heads=heads, common=common)
1039 cg = repo.getbundle('bundle', heads=heads, common=common)
1039 outgoing = None
1040 outgoing = None
1040 else:
1041 else:
1041 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1042 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1042 dest, branches = hg.parseurl(dest, opts.get('branch'))
1043 dest, branches = hg.parseurl(dest, opts.get('branch'))
1043 other = hg.peer(repo, opts, dest)
1044 other = hg.peer(repo, opts, dest)
1044 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1045 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1045 heads = revs and map(repo.lookup, revs) or revs
1046 heads = revs and map(repo.lookup, revs) or revs
1046 outgoing = discovery.findcommonoutgoing(repo, other,
1047 outgoing = discovery.findcommonoutgoing(repo, other,
1047 onlyheads=heads,
1048 onlyheads=heads,
1048 force=opts.get('force'),
1049 force=opts.get('force'),
1049 portable=True)
1050 portable=True)
1050 cg = repo.getlocalbundle('bundle', outgoing)
1051 cg = repo.getlocalbundle('bundle', outgoing)
1051 if not cg:
1052 if not cg:
1052 scmutil.nochangesfound(ui, outgoing and outgoing.excluded)
1053 scmutil.nochangesfound(ui, outgoing and outgoing.excluded)
1053 return 1
1054 return 1
1054
1055
1055 changegroup.writebundle(cg, fname, bundletype)
1056 changegroup.writebundle(cg, fname, bundletype)
1056
1057
1057 @command('cat',
1058 @command('cat',
1058 [('o', 'output', '',
1059 [('o', 'output', '',
1059 _('print output to file with formatted name'), _('FORMAT')),
1060 _('print output to file with formatted name'), _('FORMAT')),
1060 ('r', 'rev', '', _('print the given revision'), _('REV')),
1061 ('r', 'rev', '', _('print the given revision'), _('REV')),
1061 ('', 'decode', None, _('apply any matching decode filter')),
1062 ('', 'decode', None, _('apply any matching decode filter')),
1062 ] + walkopts,
1063 ] + walkopts,
1063 _('[OPTION]... FILE...'))
1064 _('[OPTION]... FILE...'))
1064 def cat(ui, repo, file1, *pats, **opts):
1065 def cat(ui, repo, file1, *pats, **opts):
1065 """output the current or given revision of files
1066 """output the current or given revision of files
1066
1067
1067 Print the specified files as they were at the given revision. If
1068 Print the specified files as they were at the given revision. If
1068 no revision is given, the parent of the working directory is used,
1069 no revision is given, the parent of the working directory is used,
1069 or tip if no revision is checked out.
1070 or tip if no revision is checked out.
1070
1071
1071 Output may be to a file, in which case the name of the file is
1072 Output may be to a file, in which case the name of the file is
1072 given using a format string. The formatting rules are the same as
1073 given using a format string. The formatting rules are the same as
1073 for the export command, with the following additions:
1074 for the export command, with the following additions:
1074
1075
1075 :``%s``: basename of file being printed
1076 :``%s``: basename of file being printed
1076 :``%d``: dirname of file being printed, or '.' if in repository root
1077 :``%d``: dirname of file being printed, or '.' if in repository root
1077 :``%p``: root-relative path name of file being printed
1078 :``%p``: root-relative path name of file being printed
1078
1079
1079 Returns 0 on success.
1080 Returns 0 on success.
1080 """
1081 """
1081 ctx = scmutil.revsingle(repo, opts.get('rev'))
1082 ctx = scmutil.revsingle(repo, opts.get('rev'))
1082 err = 1
1083 err = 1
1083 m = scmutil.match(ctx, (file1,) + pats, opts)
1084 m = scmutil.match(ctx, (file1,) + pats, opts)
1084 for abs in ctx.walk(m):
1085 for abs in ctx.walk(m):
1085 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1086 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1086 pathname=abs)
1087 pathname=abs)
1087 data = ctx[abs].data()
1088 data = ctx[abs].data()
1088 if opts.get('decode'):
1089 if opts.get('decode'):
1089 data = repo.wwritedata(abs, data)
1090 data = repo.wwritedata(abs, data)
1090 fp.write(data)
1091 fp.write(data)
1091 fp.close()
1092 fp.close()
1092 err = 0
1093 err = 0
1093 return err
1094 return err
1094
1095
1095 @command('^clone',
1096 @command('^clone',
1096 [('U', 'noupdate', None,
1097 [('U', 'noupdate', None,
1097 _('the clone will include an empty working copy (only a repository)')),
1098 _('the clone will include an empty working copy (only a repository)')),
1098 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1099 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1099 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1100 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1100 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1101 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1101 ('', 'pull', None, _('use pull protocol to copy metadata')),
1102 ('', 'pull', None, _('use pull protocol to copy metadata')),
1102 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1103 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1103 ] + remoteopts,
1104 ] + remoteopts,
1104 _('[OPTION]... SOURCE [DEST]'))
1105 _('[OPTION]... SOURCE [DEST]'))
1105 def clone(ui, source, dest=None, **opts):
1106 def clone(ui, source, dest=None, **opts):
1106 """make a copy of an existing repository
1107 """make a copy of an existing repository
1107
1108
1108 Create a copy of an existing repository in a new directory.
1109 Create a copy of an existing repository in a new directory.
1109
1110
1110 If no destination directory name is specified, it defaults to the
1111 If no destination directory name is specified, it defaults to the
1111 basename of the source.
1112 basename of the source.
1112
1113
1113 The location of the source is added to the new repository's
1114 The location of the source is added to the new repository's
1114 ``.hg/hgrc`` file, as the default to be used for future pulls.
1115 ``.hg/hgrc`` file, as the default to be used for future pulls.
1115
1116
1116 Only local paths and ``ssh://`` URLs are supported as
1117 Only local paths and ``ssh://`` URLs are supported as
1117 destinations. For ``ssh://`` destinations, no working directory or
1118 destinations. For ``ssh://`` destinations, no working directory or
1118 ``.hg/hgrc`` will be created on the remote side.
1119 ``.hg/hgrc`` will be created on the remote side.
1119
1120
1120 To pull only a subset of changesets, specify one or more revisions
1121 To pull only a subset of changesets, specify one or more revisions
1121 identifiers with -r/--rev or branches with -b/--branch. The
1122 identifiers with -r/--rev or branches with -b/--branch. The
1122 resulting clone will contain only the specified changesets and
1123 resulting clone will contain only the specified changesets and
1123 their ancestors. These options (or 'clone src#rev dest') imply
1124 their ancestors. These options (or 'clone src#rev dest') imply
1124 --pull, even for local source repositories. Note that specifying a
1125 --pull, even for local source repositories. Note that specifying a
1125 tag will include the tagged changeset but not the changeset
1126 tag will include the tagged changeset but not the changeset
1126 containing the tag.
1127 containing the tag.
1127
1128
1128 To check out a particular version, use -u/--update, or
1129 To check out a particular version, use -u/--update, or
1129 -U/--noupdate to create a clone with no working directory.
1130 -U/--noupdate to create a clone with no working directory.
1130
1131
1131 .. container:: verbose
1132 .. container:: verbose
1132
1133
1133 For efficiency, hardlinks are used for cloning whenever the
1134 For efficiency, hardlinks are used for cloning whenever the
1134 source and destination are on the same filesystem (note this
1135 source and destination are on the same filesystem (note this
1135 applies only to the repository data, not to the working
1136 applies only to the repository data, not to the working
1136 directory). Some filesystems, such as AFS, implement hardlinking
1137 directory). Some filesystems, such as AFS, implement hardlinking
1137 incorrectly, but do not report errors. In these cases, use the
1138 incorrectly, but do not report errors. In these cases, use the
1138 --pull option to avoid hardlinking.
1139 --pull option to avoid hardlinking.
1139
1140
1140 In some cases, you can clone repositories and the working
1141 In some cases, you can clone repositories and the working
1141 directory using full hardlinks with ::
1142 directory using full hardlinks with ::
1142
1143
1143 $ cp -al REPO REPOCLONE
1144 $ cp -al REPO REPOCLONE
1144
1145
1145 This is the fastest way to clone, but it is not always safe. The
1146 This is the fastest way to clone, but it is not always safe. The
1146 operation is not atomic (making sure REPO is not modified during
1147 operation is not atomic (making sure REPO is not modified during
1147 the operation is up to you) and you have to make sure your
1148 the operation is up to you) and you have to make sure your
1148 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1149 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1149 so). Also, this is not compatible with certain extensions that
1150 so). Also, this is not compatible with certain extensions that
1150 place their metadata under the .hg directory, such as mq.
1151 place their metadata under the .hg directory, such as mq.
1151
1152
1152 Mercurial will update the working directory to the first applicable
1153 Mercurial will update the working directory to the first applicable
1153 revision from this list:
1154 revision from this list:
1154
1155
1155 a) null if -U or the source repository has no changesets
1156 a) null if -U or the source repository has no changesets
1156 b) if -u . and the source repository is local, the first parent of
1157 b) if -u . and the source repository is local, the first parent of
1157 the source repository's working directory
1158 the source repository's working directory
1158 c) the changeset specified with -u (if a branch name, this means the
1159 c) the changeset specified with -u (if a branch name, this means the
1159 latest head of that branch)
1160 latest head of that branch)
1160 d) the changeset specified with -r
1161 d) the changeset specified with -r
1161 e) the tipmost head specified with -b
1162 e) the tipmost head specified with -b
1162 f) the tipmost head specified with the url#branch source syntax
1163 f) the tipmost head specified with the url#branch source syntax
1163 g) the tipmost head of the default branch
1164 g) the tipmost head of the default branch
1164 h) tip
1165 h) tip
1165
1166
1166 Examples:
1167 Examples:
1167
1168
1168 - clone a remote repository to a new directory named hg/::
1169 - clone a remote repository to a new directory named hg/::
1169
1170
1170 hg clone http://selenic.com/hg
1171 hg clone http://selenic.com/hg
1171
1172
1172 - create a lightweight local clone::
1173 - create a lightweight local clone::
1173
1174
1174 hg clone project/ project-feature/
1175 hg clone project/ project-feature/
1175
1176
1176 - clone from an absolute path on an ssh server (note double-slash)::
1177 - clone from an absolute path on an ssh server (note double-slash)::
1177
1178
1178 hg clone ssh://user@server//home/projects/alpha/
1179 hg clone ssh://user@server//home/projects/alpha/
1179
1180
1180 - do a high-speed clone over a LAN while checking out a
1181 - do a high-speed clone over a LAN while checking out a
1181 specified version::
1182 specified version::
1182
1183
1183 hg clone --uncompressed http://server/repo -u 1.5
1184 hg clone --uncompressed http://server/repo -u 1.5
1184
1185
1185 - create a repository without changesets after a particular revision::
1186 - create a repository without changesets after a particular revision::
1186
1187
1187 hg clone -r 04e544 experimental/ good/
1188 hg clone -r 04e544 experimental/ good/
1188
1189
1189 - clone (and track) a particular named branch::
1190 - clone (and track) a particular named branch::
1190
1191
1191 hg clone http://selenic.com/hg#stable
1192 hg clone http://selenic.com/hg#stable
1192
1193
1193 See :hg:`help urls` for details on specifying URLs.
1194 See :hg:`help urls` for details on specifying URLs.
1194
1195
1195 Returns 0 on success.
1196 Returns 0 on success.
1196 """
1197 """
1197 if opts.get('noupdate') and opts.get('updaterev'):
1198 if opts.get('noupdate') and opts.get('updaterev'):
1198 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1199 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1199
1200
1200 r = hg.clone(ui, opts, source, dest,
1201 r = hg.clone(ui, opts, source, dest,
1201 pull=opts.get('pull'),
1202 pull=opts.get('pull'),
1202 stream=opts.get('uncompressed'),
1203 stream=opts.get('uncompressed'),
1203 rev=opts.get('rev'),
1204 rev=opts.get('rev'),
1204 update=opts.get('updaterev') or not opts.get('noupdate'),
1205 update=opts.get('updaterev') or not opts.get('noupdate'),
1205 branch=opts.get('branch'))
1206 branch=opts.get('branch'))
1206
1207
1207 return r is None
1208 return r is None
1208
1209
1209 @command('^commit|ci',
1210 @command('^commit|ci',
1210 [('A', 'addremove', None,
1211 [('A', 'addremove', None,
1211 _('mark new/missing files as added/removed before committing')),
1212 _('mark new/missing files as added/removed before committing')),
1212 ('', 'close-branch', None,
1213 ('', 'close-branch', None,
1213 _('mark a branch as closed, hiding it from the branch list')),
1214 _('mark a branch as closed, hiding it from the branch list')),
1214 ('', 'amend', None, _('amend the parent of the working dir')),
1215 ('', 'amend', None, _('amend the parent of the working dir')),
1215 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1216 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1216 _('[OPTION]... [FILE]...'))
1217 _('[OPTION]... [FILE]...'))
1217 def commit(ui, repo, *pats, **opts):
1218 def commit(ui, repo, *pats, **opts):
1218 """commit the specified files or all outstanding changes
1219 """commit the specified files or all outstanding changes
1219
1220
1220 Commit changes to the given files into the repository. Unlike a
1221 Commit changes to the given files into the repository. Unlike a
1221 centralized SCM, this operation is a local operation. See
1222 centralized SCM, this operation is a local operation. See
1222 :hg:`push` for a way to actively distribute your changes.
1223 :hg:`push` for a way to actively distribute your changes.
1223
1224
1224 If a list of files is omitted, all changes reported by :hg:`status`
1225 If a list of files is omitted, all changes reported by :hg:`status`
1225 will be committed.
1226 will be committed.
1226
1227
1227 If you are committing the result of a merge, do not provide any
1228 If you are committing the result of a merge, do not provide any
1228 filenames or -I/-X filters.
1229 filenames or -I/-X filters.
1229
1230
1230 If no commit message is specified, Mercurial starts your
1231 If no commit message is specified, Mercurial starts your
1231 configured editor where you can enter a message. In case your
1232 configured editor where you can enter a message. In case your
1232 commit fails, you will find a backup of your message in
1233 commit fails, you will find a backup of your message in
1233 ``.hg/last-message.txt``.
1234 ``.hg/last-message.txt``.
1234
1235
1235 The --amend flag can be used to amend the parent of the
1236 The --amend flag can be used to amend the parent of the
1236 working directory with a new commit that contains the changes
1237 working directory with a new commit that contains the changes
1237 in the parent in addition to those currently reported by :hg:`status`,
1238 in the parent in addition to those currently reported by :hg:`status`,
1238 if there are any. The old commit is stored in a backup bundle in
1239 if there are any. The old commit is stored in a backup bundle in
1239 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1240 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1240 on how to restore it).
1241 on how to restore it).
1241
1242
1242 Message, user and date are taken from the amended commit unless
1243 Message, user and date are taken from the amended commit unless
1243 specified. When a message isn't specified on the command line,
1244 specified. When a message isn't specified on the command line,
1244 the editor will open with the message of the amended commit.
1245 the editor will open with the message of the amended commit.
1245
1246
1246 It is not possible to amend public changesets (see :hg:`help phases`)
1247 It is not possible to amend public changesets (see :hg:`help phases`)
1247 or changesets that have children.
1248 or changesets that have children.
1248
1249
1249 See :hg:`help dates` for a list of formats valid for -d/--date.
1250 See :hg:`help dates` for a list of formats valid for -d/--date.
1250
1251
1251 Returns 0 on success, 1 if nothing changed.
1252 Returns 0 on success, 1 if nothing changed.
1252 """
1253 """
1253 if opts.get('subrepos'):
1254 if opts.get('subrepos'):
1254 # Let --subrepos on the command line overide config setting.
1255 # Let --subrepos on the command line overide config setting.
1255 ui.setconfig('ui', 'commitsubrepos', True)
1256 ui.setconfig('ui', 'commitsubrepos', True)
1256
1257
1257 extra = {}
1258 extra = {}
1258 if opts.get('close_branch'):
1259 if opts.get('close_branch'):
1259 if repo['.'].node() not in repo.branchheads():
1260 if repo['.'].node() not in repo.branchheads():
1260 # The topo heads set is included in the branch heads set of the
1261 # The topo heads set is included in the branch heads set of the
1261 # current branch, so it's sufficient to test branchheads
1262 # current branch, so it's sufficient to test branchheads
1262 raise util.Abort(_('can only close branch heads'))
1263 raise util.Abort(_('can only close branch heads'))
1263 extra['close'] = 1
1264 extra['close'] = 1
1264
1265
1265 branch = repo[None].branch()
1266 branch = repo[None].branch()
1266 bheads = repo.branchheads(branch)
1267 bheads = repo.branchheads(branch)
1267
1268
1268 if opts.get('amend'):
1269 if opts.get('amend'):
1269 if ui.configbool('ui', 'commitsubrepos'):
1270 if ui.configbool('ui', 'commitsubrepos'):
1270 raise util.Abort(_('cannot amend recursively'))
1271 raise util.Abort(_('cannot amend recursively'))
1271
1272
1272 old = repo['.']
1273 old = repo['.']
1273 if old.phase() == phases.public:
1274 if old.phase() == phases.public:
1274 raise util.Abort(_('cannot amend public changesets'))
1275 raise util.Abort(_('cannot amend public changesets'))
1275 if len(old.parents()) > 1:
1276 if len(old.parents()) > 1:
1276 raise util.Abort(_('cannot amend merge changesets'))
1277 raise util.Abort(_('cannot amend merge changesets'))
1277 if len(repo[None].parents()) > 1:
1278 if len(repo[None].parents()) > 1:
1278 raise util.Abort(_('cannot amend while merging'))
1279 raise util.Abort(_('cannot amend while merging'))
1279 if old.children():
1280 if old.children():
1280 raise util.Abort(_('cannot amend changeset with children'))
1281 raise util.Abort(_('cannot amend changeset with children'))
1281
1282
1282 e = cmdutil.commiteditor
1283 e = cmdutil.commiteditor
1283 if opts.get('force_editor'):
1284 if opts.get('force_editor'):
1284 e = cmdutil.commitforceeditor
1285 e = cmdutil.commitforceeditor
1285
1286
1286 def commitfunc(ui, repo, message, match, opts):
1287 def commitfunc(ui, repo, message, match, opts):
1287 editor = e
1288 editor = e
1288 # message contains text from -m or -l, if it's empty,
1289 # message contains text from -m or -l, if it's empty,
1289 # open the editor with the old message
1290 # open the editor with the old message
1290 if not message:
1291 if not message:
1291 message = old.description()
1292 message = old.description()
1292 editor = cmdutil.commitforceeditor
1293 editor = cmdutil.commitforceeditor
1293 return repo.commit(message,
1294 return repo.commit(message,
1294 opts.get('user') or old.user(),
1295 opts.get('user') or old.user(),
1295 opts.get('date') or old.date(),
1296 opts.get('date') or old.date(),
1296 match,
1297 match,
1297 editor=editor,
1298 editor=editor,
1298 extra=extra)
1299 extra=extra)
1299
1300
1300 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1301 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1301 if node == old.node():
1302 if node == old.node():
1302 ui.status(_("nothing changed\n"))
1303 ui.status(_("nothing changed\n"))
1303 return 1
1304 return 1
1304 else:
1305 else:
1305 e = cmdutil.commiteditor
1306 e = cmdutil.commiteditor
1306 if opts.get('force_editor'):
1307 if opts.get('force_editor'):
1307 e = cmdutil.commitforceeditor
1308 e = cmdutil.commitforceeditor
1308
1309
1309 def commitfunc(ui, repo, message, match, opts):
1310 def commitfunc(ui, repo, message, match, opts):
1310 return repo.commit(message, opts.get('user'), opts.get('date'),
1311 return repo.commit(message, opts.get('user'), opts.get('date'),
1311 match, editor=e, extra=extra)
1312 match, editor=e, extra=extra)
1312
1313
1313 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1314 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1314
1315
1315 if not node:
1316 if not node:
1316 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1317 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1317 if stat[3]:
1318 if stat[3]:
1318 ui.status(_("nothing changed (%d missing files, see "
1319 ui.status(_("nothing changed (%d missing files, see "
1319 "'hg status')\n") % len(stat[3]))
1320 "'hg status')\n") % len(stat[3]))
1320 else:
1321 else:
1321 ui.status(_("nothing changed\n"))
1322 ui.status(_("nothing changed\n"))
1322 return 1
1323 return 1
1323
1324
1324 ctx = repo[node]
1325 ctx = repo[node]
1325 parents = ctx.parents()
1326 parents = ctx.parents()
1326
1327
1327 if (not opts.get('amend') and bheads and node not in bheads and not
1328 if (not opts.get('amend') and bheads and node not in bheads and not
1328 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1329 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1329 ui.status(_('created new head\n'))
1330 ui.status(_('created new head\n'))
1330 # The message is not printed for initial roots. For the other
1331 # The message is not printed for initial roots. For the other
1331 # changesets, it is printed in the following situations:
1332 # changesets, it is printed in the following situations:
1332 #
1333 #
1333 # Par column: for the 2 parents with ...
1334 # Par column: for the 2 parents with ...
1334 # N: null or no parent
1335 # N: null or no parent
1335 # B: parent is on another named branch
1336 # B: parent is on another named branch
1336 # C: parent is a regular non head changeset
1337 # C: parent is a regular non head changeset
1337 # H: parent was a branch head of the current branch
1338 # H: parent was a branch head of the current branch
1338 # Msg column: whether we print "created new head" message
1339 # Msg column: whether we print "created new head" message
1339 # In the following, it is assumed that there already exists some
1340 # In the following, it is assumed that there already exists some
1340 # initial branch heads of the current branch, otherwise nothing is
1341 # initial branch heads of the current branch, otherwise nothing is
1341 # printed anyway.
1342 # printed anyway.
1342 #
1343 #
1343 # Par Msg Comment
1344 # Par Msg Comment
1344 # NN y additional topo root
1345 # NN y additional topo root
1345 #
1346 #
1346 # BN y additional branch root
1347 # BN y additional branch root
1347 # CN y additional topo head
1348 # CN y additional topo head
1348 # HN n usual case
1349 # HN n usual case
1349 #
1350 #
1350 # BB y weird additional branch root
1351 # BB y weird additional branch root
1351 # CB y branch merge
1352 # CB y branch merge
1352 # HB n merge with named branch
1353 # HB n merge with named branch
1353 #
1354 #
1354 # CC y additional head from merge
1355 # CC y additional head from merge
1355 # CH n merge with a head
1356 # CH n merge with a head
1356 #
1357 #
1357 # HH n head merge: head count decreases
1358 # HH n head merge: head count decreases
1358
1359
1359 if not opts.get('close_branch'):
1360 if not opts.get('close_branch'):
1360 for r in parents:
1361 for r in parents:
1361 if r.closesbranch() and r.branch() == branch:
1362 if r.closesbranch() and r.branch() == branch:
1362 ui.status(_('reopening closed branch head %d\n') % r)
1363 ui.status(_('reopening closed branch head %d\n') % r)
1363
1364
1364 if ui.debugflag:
1365 if ui.debugflag:
1365 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1366 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1366 elif ui.verbose:
1367 elif ui.verbose:
1367 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1368 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1368
1369
1369 @command('copy|cp',
1370 @command('copy|cp',
1370 [('A', 'after', None, _('record a copy that has already occurred')),
1371 [('A', 'after', None, _('record a copy that has already occurred')),
1371 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1372 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1372 ] + walkopts + dryrunopts,
1373 ] + walkopts + dryrunopts,
1373 _('[OPTION]... [SOURCE]... DEST'))
1374 _('[OPTION]... [SOURCE]... DEST'))
1374 def copy(ui, repo, *pats, **opts):
1375 def copy(ui, repo, *pats, **opts):
1375 """mark files as copied for the next commit
1376 """mark files as copied for the next commit
1376
1377
1377 Mark dest as having copies of source files. If dest is a
1378 Mark dest as having copies of source files. If dest is a
1378 directory, copies are put in that directory. If dest is a file,
1379 directory, copies are put in that directory. If dest is a file,
1379 the source must be a single file.
1380 the source must be a single file.
1380
1381
1381 By default, this command copies the contents of files as they
1382 By default, this command copies the contents of files as they
1382 exist in the working directory. If invoked with -A/--after, the
1383 exist in the working directory. If invoked with -A/--after, the
1383 operation is recorded, but no copying is performed.
1384 operation is recorded, but no copying is performed.
1384
1385
1385 This command takes effect with the next commit. To undo a copy
1386 This command takes effect with the next commit. To undo a copy
1386 before that, see :hg:`revert`.
1387 before that, see :hg:`revert`.
1387
1388
1388 Returns 0 on success, 1 if errors are encountered.
1389 Returns 0 on success, 1 if errors are encountered.
1389 """
1390 """
1390 wlock = repo.wlock(False)
1391 wlock = repo.wlock(False)
1391 try:
1392 try:
1392 return cmdutil.copy(ui, repo, pats, opts)
1393 return cmdutil.copy(ui, repo, pats, opts)
1393 finally:
1394 finally:
1394 wlock.release()
1395 wlock.release()
1395
1396
1396 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1397 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1397 def debugancestor(ui, repo, *args):
1398 def debugancestor(ui, repo, *args):
1398 """find the ancestor revision of two revisions in a given index"""
1399 """find the ancestor revision of two revisions in a given index"""
1399 if len(args) == 3:
1400 if len(args) == 3:
1400 index, rev1, rev2 = args
1401 index, rev1, rev2 = args
1401 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1402 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1402 lookup = r.lookup
1403 lookup = r.lookup
1403 elif len(args) == 2:
1404 elif len(args) == 2:
1404 if not repo:
1405 if not repo:
1405 raise util.Abort(_("there is no Mercurial repository here "
1406 raise util.Abort(_("there is no Mercurial repository here "
1406 "(.hg not found)"))
1407 "(.hg not found)"))
1407 rev1, rev2 = args
1408 rev1, rev2 = args
1408 r = repo.changelog
1409 r = repo.changelog
1409 lookup = repo.lookup
1410 lookup = repo.lookup
1410 else:
1411 else:
1411 raise util.Abort(_('either two or three arguments required'))
1412 raise util.Abort(_('either two or three arguments required'))
1412 a = r.ancestor(lookup(rev1), lookup(rev2))
1413 a = r.ancestor(lookup(rev1), lookup(rev2))
1413 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1414 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1414
1415
1415 @command('debugbuilddag',
1416 @command('debugbuilddag',
1416 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1417 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1417 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1418 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1418 ('n', 'new-file', None, _('add new file at each rev'))],
1419 ('n', 'new-file', None, _('add new file at each rev'))],
1419 _('[OPTION]... [TEXT]'))
1420 _('[OPTION]... [TEXT]'))
1420 def debugbuilddag(ui, repo, text=None,
1421 def debugbuilddag(ui, repo, text=None,
1421 mergeable_file=False,
1422 mergeable_file=False,
1422 overwritten_file=False,
1423 overwritten_file=False,
1423 new_file=False):
1424 new_file=False):
1424 """builds a repo with a given DAG from scratch in the current empty repo
1425 """builds a repo with a given DAG from scratch in the current empty repo
1425
1426
1426 The description of the DAG is read from stdin if not given on the
1427 The description of the DAG is read from stdin if not given on the
1427 command line.
1428 command line.
1428
1429
1429 Elements:
1430 Elements:
1430
1431
1431 - "+n" is a linear run of n nodes based on the current default parent
1432 - "+n" is a linear run of n nodes based on the current default parent
1432 - "." is a single node based on the current default parent
1433 - "." is a single node based on the current default parent
1433 - "$" resets the default parent to null (implied at the start);
1434 - "$" resets the default parent to null (implied at the start);
1434 otherwise the default parent is always the last node created
1435 otherwise the default parent is always the last node created
1435 - "<p" sets the default parent to the backref p
1436 - "<p" sets the default parent to the backref p
1436 - "*p" is a fork at parent p, which is a backref
1437 - "*p" is a fork at parent p, which is a backref
1437 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1438 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1438 - "/p2" is a merge of the preceding node and p2
1439 - "/p2" is a merge of the preceding node and p2
1439 - ":tag" defines a local tag for the preceding node
1440 - ":tag" defines a local tag for the preceding node
1440 - "@branch" sets the named branch for subsequent nodes
1441 - "@branch" sets the named branch for subsequent nodes
1441 - "#...\\n" is a comment up to the end of the line
1442 - "#...\\n" is a comment up to the end of the line
1442
1443
1443 Whitespace between the above elements is ignored.
1444 Whitespace between the above elements is ignored.
1444
1445
1445 A backref is either
1446 A backref is either
1446
1447
1447 - a number n, which references the node curr-n, where curr is the current
1448 - a number n, which references the node curr-n, where curr is the current
1448 node, or
1449 node, or
1449 - the name of a local tag you placed earlier using ":tag", or
1450 - the name of a local tag you placed earlier using ":tag", or
1450 - empty to denote the default parent.
1451 - empty to denote the default parent.
1451
1452
1452 All string valued-elements are either strictly alphanumeric, or must
1453 All string valued-elements are either strictly alphanumeric, or must
1453 be enclosed in double quotes ("..."), with "\\" as escape character.
1454 be enclosed in double quotes ("..."), with "\\" as escape character.
1454 """
1455 """
1455
1456
1456 if text is None:
1457 if text is None:
1457 ui.status(_("reading DAG from stdin\n"))
1458 ui.status(_("reading DAG from stdin\n"))
1458 text = ui.fin.read()
1459 text = ui.fin.read()
1459
1460
1460 cl = repo.changelog
1461 cl = repo.changelog
1461 if len(cl) > 0:
1462 if len(cl) > 0:
1462 raise util.Abort(_('repository is not empty'))
1463 raise util.Abort(_('repository is not empty'))
1463
1464
1464 # determine number of revs in DAG
1465 # determine number of revs in DAG
1465 total = 0
1466 total = 0
1466 for type, data in dagparser.parsedag(text):
1467 for type, data in dagparser.parsedag(text):
1467 if type == 'n':
1468 if type == 'n':
1468 total += 1
1469 total += 1
1469
1470
1470 if mergeable_file:
1471 if mergeable_file:
1471 linesperrev = 2
1472 linesperrev = 2
1472 # make a file with k lines per rev
1473 # make a file with k lines per rev
1473 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1474 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1474 initialmergedlines.append("")
1475 initialmergedlines.append("")
1475
1476
1476 tags = []
1477 tags = []
1477
1478
1478 lock = tr = None
1479 lock = tr = None
1479 try:
1480 try:
1480 lock = repo.lock()
1481 lock = repo.lock()
1481 tr = repo.transaction("builddag")
1482 tr = repo.transaction("builddag")
1482
1483
1483 at = -1
1484 at = -1
1484 atbranch = 'default'
1485 atbranch = 'default'
1485 nodeids = []
1486 nodeids = []
1486 id = 0
1487 id = 0
1487 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1488 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1488 for type, data in dagparser.parsedag(text):
1489 for type, data in dagparser.parsedag(text):
1489 if type == 'n':
1490 if type == 'n':
1490 ui.note('node %s\n' % str(data))
1491 ui.note('node %s\n' % str(data))
1491 id, ps = data
1492 id, ps = data
1492
1493
1493 files = []
1494 files = []
1494 fctxs = {}
1495 fctxs = {}
1495
1496
1496 p2 = None
1497 p2 = None
1497 if mergeable_file:
1498 if mergeable_file:
1498 fn = "mf"
1499 fn = "mf"
1499 p1 = repo[ps[0]]
1500 p1 = repo[ps[0]]
1500 if len(ps) > 1:
1501 if len(ps) > 1:
1501 p2 = repo[ps[1]]
1502 p2 = repo[ps[1]]
1502 pa = p1.ancestor(p2)
1503 pa = p1.ancestor(p2)
1503 base, local, other = [x[fn].data() for x in pa, p1, p2]
1504 base, local, other = [x[fn].data() for x in pa, p1, p2]
1504 m3 = simplemerge.Merge3Text(base, local, other)
1505 m3 = simplemerge.Merge3Text(base, local, other)
1505 ml = [l.strip() for l in m3.merge_lines()]
1506 ml = [l.strip() for l in m3.merge_lines()]
1506 ml.append("")
1507 ml.append("")
1507 elif at > 0:
1508 elif at > 0:
1508 ml = p1[fn].data().split("\n")
1509 ml = p1[fn].data().split("\n")
1509 else:
1510 else:
1510 ml = initialmergedlines
1511 ml = initialmergedlines
1511 ml[id * linesperrev] += " r%i" % id
1512 ml[id * linesperrev] += " r%i" % id
1512 mergedtext = "\n".join(ml)
1513 mergedtext = "\n".join(ml)
1513 files.append(fn)
1514 files.append(fn)
1514 fctxs[fn] = context.memfilectx(fn, mergedtext)
1515 fctxs[fn] = context.memfilectx(fn, mergedtext)
1515
1516
1516 if overwritten_file:
1517 if overwritten_file:
1517 fn = "of"
1518 fn = "of"
1518 files.append(fn)
1519 files.append(fn)
1519 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1520 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1520
1521
1521 if new_file:
1522 if new_file:
1522 fn = "nf%i" % id
1523 fn = "nf%i" % id
1523 files.append(fn)
1524 files.append(fn)
1524 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1525 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1525 if len(ps) > 1:
1526 if len(ps) > 1:
1526 if not p2:
1527 if not p2:
1527 p2 = repo[ps[1]]
1528 p2 = repo[ps[1]]
1528 for fn in p2:
1529 for fn in p2:
1529 if fn.startswith("nf"):
1530 if fn.startswith("nf"):
1530 files.append(fn)
1531 files.append(fn)
1531 fctxs[fn] = p2[fn]
1532 fctxs[fn] = p2[fn]
1532
1533
1533 def fctxfn(repo, cx, path):
1534 def fctxfn(repo, cx, path):
1534 return fctxs.get(path)
1535 return fctxs.get(path)
1535
1536
1536 if len(ps) == 0 or ps[0] < 0:
1537 if len(ps) == 0 or ps[0] < 0:
1537 pars = [None, None]
1538 pars = [None, None]
1538 elif len(ps) == 1:
1539 elif len(ps) == 1:
1539 pars = [nodeids[ps[0]], None]
1540 pars = [nodeids[ps[0]], None]
1540 else:
1541 else:
1541 pars = [nodeids[p] for p in ps]
1542 pars = [nodeids[p] for p in ps]
1542 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1543 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1543 date=(id, 0),
1544 date=(id, 0),
1544 user="debugbuilddag",
1545 user="debugbuilddag",
1545 extra={'branch': atbranch})
1546 extra={'branch': atbranch})
1546 nodeid = repo.commitctx(cx)
1547 nodeid = repo.commitctx(cx)
1547 nodeids.append(nodeid)
1548 nodeids.append(nodeid)
1548 at = id
1549 at = id
1549 elif type == 'l':
1550 elif type == 'l':
1550 id, name = data
1551 id, name = data
1551 ui.note('tag %s\n' % name)
1552 ui.note('tag %s\n' % name)
1552 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1553 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1553 elif type == 'a':
1554 elif type == 'a':
1554 ui.note('branch %s\n' % data)
1555 ui.note('branch %s\n' % data)
1555 atbranch = data
1556 atbranch = data
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 tr.close()
1558 tr.close()
1558
1559
1559 if tags:
1560 if tags:
1560 repo.opener.write("localtags", "".join(tags))
1561 repo.opener.write("localtags", "".join(tags))
1561 finally:
1562 finally:
1562 ui.progress(_('building'), None)
1563 ui.progress(_('building'), None)
1563 release(tr, lock)
1564 release(tr, lock)
1564
1565
1565 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1566 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1566 def debugbundle(ui, bundlepath, all=None, **opts):
1567 def debugbundle(ui, bundlepath, all=None, **opts):
1567 """lists the contents of a bundle"""
1568 """lists the contents of a bundle"""
1568 f = url.open(ui, bundlepath)
1569 f = url.open(ui, bundlepath)
1569 try:
1570 try:
1570 gen = changegroup.readbundle(f, bundlepath)
1571 gen = changegroup.readbundle(f, bundlepath)
1571 if all:
1572 if all:
1572 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1573 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1573
1574
1574 def showchunks(named):
1575 def showchunks(named):
1575 ui.write("\n%s\n" % named)
1576 ui.write("\n%s\n" % named)
1576 chain = None
1577 chain = None
1577 while True:
1578 while True:
1578 chunkdata = gen.deltachunk(chain)
1579 chunkdata = gen.deltachunk(chain)
1579 if not chunkdata:
1580 if not chunkdata:
1580 break
1581 break
1581 node = chunkdata['node']
1582 node = chunkdata['node']
1582 p1 = chunkdata['p1']
1583 p1 = chunkdata['p1']
1583 p2 = chunkdata['p2']
1584 p2 = chunkdata['p2']
1584 cs = chunkdata['cs']
1585 cs = chunkdata['cs']
1585 deltabase = chunkdata['deltabase']
1586 deltabase = chunkdata['deltabase']
1586 delta = chunkdata['delta']
1587 delta = chunkdata['delta']
1587 ui.write("%s %s %s %s %s %s\n" %
1588 ui.write("%s %s %s %s %s %s\n" %
1588 (hex(node), hex(p1), hex(p2),
1589 (hex(node), hex(p1), hex(p2),
1589 hex(cs), hex(deltabase), len(delta)))
1590 hex(cs), hex(deltabase), len(delta)))
1590 chain = node
1591 chain = node
1591
1592
1592 chunkdata = gen.changelogheader()
1593 chunkdata = gen.changelogheader()
1593 showchunks("changelog")
1594 showchunks("changelog")
1594 chunkdata = gen.manifestheader()
1595 chunkdata = gen.manifestheader()
1595 showchunks("manifest")
1596 showchunks("manifest")
1596 while True:
1597 while True:
1597 chunkdata = gen.filelogheader()
1598 chunkdata = gen.filelogheader()
1598 if not chunkdata:
1599 if not chunkdata:
1599 break
1600 break
1600 fname = chunkdata['filename']
1601 fname = chunkdata['filename']
1601 showchunks(fname)
1602 showchunks(fname)
1602 else:
1603 else:
1603 chunkdata = gen.changelogheader()
1604 chunkdata = gen.changelogheader()
1604 chain = None
1605 chain = None
1605 while True:
1606 while True:
1606 chunkdata = gen.deltachunk(chain)
1607 chunkdata = gen.deltachunk(chain)
1607 if not chunkdata:
1608 if not chunkdata:
1608 break
1609 break
1609 node = chunkdata['node']
1610 node = chunkdata['node']
1610 ui.write("%s\n" % hex(node))
1611 ui.write("%s\n" % hex(node))
1611 chain = node
1612 chain = node
1612 finally:
1613 finally:
1613 f.close()
1614 f.close()
1614
1615
1615 @command('debugcheckstate', [], '')
1616 @command('debugcheckstate', [], '')
1616 def debugcheckstate(ui, repo):
1617 def debugcheckstate(ui, repo):
1617 """validate the correctness of the current dirstate"""
1618 """validate the correctness of the current dirstate"""
1618 parent1, parent2 = repo.dirstate.parents()
1619 parent1, parent2 = repo.dirstate.parents()
1619 m1 = repo[parent1].manifest()
1620 m1 = repo[parent1].manifest()
1620 m2 = repo[parent2].manifest()
1621 m2 = repo[parent2].manifest()
1621 errors = 0
1622 errors = 0
1622 for f in repo.dirstate:
1623 for f in repo.dirstate:
1623 state = repo.dirstate[f]
1624 state = repo.dirstate[f]
1624 if state in "nr" and f not in m1:
1625 if state in "nr" and f not in m1:
1625 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1626 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1626 errors += 1
1627 errors += 1
1627 if state in "a" and f in m1:
1628 if state in "a" and f in m1:
1628 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1629 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1629 errors += 1
1630 errors += 1
1630 if state in "m" and f not in m1 and f not in m2:
1631 if state in "m" and f not in m1 and f not in m2:
1631 ui.warn(_("%s in state %s, but not in either manifest\n") %
1632 ui.warn(_("%s in state %s, but not in either manifest\n") %
1632 (f, state))
1633 (f, state))
1633 errors += 1
1634 errors += 1
1634 for f in m1:
1635 for f in m1:
1635 state = repo.dirstate[f]
1636 state = repo.dirstate[f]
1636 if state not in "nrm":
1637 if state not in "nrm":
1637 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1638 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1638 errors += 1
1639 errors += 1
1639 if errors:
1640 if errors:
1640 error = _(".hg/dirstate inconsistent with current parent's manifest")
1641 error = _(".hg/dirstate inconsistent with current parent's manifest")
1641 raise util.Abort(error)
1642 raise util.Abort(error)
1642
1643
1643 @command('debugcommands', [], _('[COMMAND]'))
1644 @command('debugcommands', [], _('[COMMAND]'))
1644 def debugcommands(ui, cmd='', *args):
1645 def debugcommands(ui, cmd='', *args):
1645 """list all available commands and options"""
1646 """list all available commands and options"""
1646 for cmd, vals in sorted(table.iteritems()):
1647 for cmd, vals in sorted(table.iteritems()):
1647 cmd = cmd.split('|')[0].strip('^')
1648 cmd = cmd.split('|')[0].strip('^')
1648 opts = ', '.join([i[1] for i in vals[1]])
1649 opts = ', '.join([i[1] for i in vals[1]])
1649 ui.write('%s: %s\n' % (cmd, opts))
1650 ui.write('%s: %s\n' % (cmd, opts))
1650
1651
1651 @command('debugcomplete',
1652 @command('debugcomplete',
1652 [('o', 'options', None, _('show the command options'))],
1653 [('o', 'options', None, _('show the command options'))],
1653 _('[-o] CMD'))
1654 _('[-o] CMD'))
1654 def debugcomplete(ui, cmd='', **opts):
1655 def debugcomplete(ui, cmd='', **opts):
1655 """returns the completion list associated with the given command"""
1656 """returns the completion list associated with the given command"""
1656
1657
1657 if opts.get('options'):
1658 if opts.get('options'):
1658 options = []
1659 options = []
1659 otables = [globalopts]
1660 otables = [globalopts]
1660 if cmd:
1661 if cmd:
1661 aliases, entry = cmdutil.findcmd(cmd, table, False)
1662 aliases, entry = cmdutil.findcmd(cmd, table, False)
1662 otables.append(entry[1])
1663 otables.append(entry[1])
1663 for t in otables:
1664 for t in otables:
1664 for o in t:
1665 for o in t:
1665 if "(DEPRECATED)" in o[3]:
1666 if "(DEPRECATED)" in o[3]:
1666 continue
1667 continue
1667 if o[0]:
1668 if o[0]:
1668 options.append('-%s' % o[0])
1669 options.append('-%s' % o[0])
1669 options.append('--%s' % o[1])
1670 options.append('--%s' % o[1])
1670 ui.write("%s\n" % "\n".join(options))
1671 ui.write("%s\n" % "\n".join(options))
1671 return
1672 return
1672
1673
1673 cmdlist = cmdutil.findpossible(cmd, table)
1674 cmdlist = cmdutil.findpossible(cmd, table)
1674 if ui.verbose:
1675 if ui.verbose:
1675 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1676 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1676 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1677 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1677
1678
1678 @command('debugdag',
1679 @command('debugdag',
1679 [('t', 'tags', None, _('use tags as labels')),
1680 [('t', 'tags', None, _('use tags as labels')),
1680 ('b', 'branches', None, _('annotate with branch names')),
1681 ('b', 'branches', None, _('annotate with branch names')),
1681 ('', 'dots', None, _('use dots for runs')),
1682 ('', 'dots', None, _('use dots for runs')),
1682 ('s', 'spaces', None, _('separate elements by spaces'))],
1683 ('s', 'spaces', None, _('separate elements by spaces'))],
1683 _('[OPTION]... [FILE [REV]...]'))
1684 _('[OPTION]... [FILE [REV]...]'))
1684 def debugdag(ui, repo, file_=None, *revs, **opts):
1685 def debugdag(ui, repo, file_=None, *revs, **opts):
1685 """format the changelog or an index DAG as a concise textual description
1686 """format the changelog or an index DAG as a concise textual description
1686
1687
1687 If you pass a revlog index, the revlog's DAG is emitted. If you list
1688 If you pass a revlog index, the revlog's DAG is emitted. If you list
1688 revision numbers, they get labelled in the output as rN.
1689 revision numbers, they get labelled in the output as rN.
1689
1690
1690 Otherwise, the changelog DAG of the current repo is emitted.
1691 Otherwise, the changelog DAG of the current repo is emitted.
1691 """
1692 """
1692 spaces = opts.get('spaces')
1693 spaces = opts.get('spaces')
1693 dots = opts.get('dots')
1694 dots = opts.get('dots')
1694 if file_:
1695 if file_:
1695 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1696 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1696 revs = set((int(r) for r in revs))
1697 revs = set((int(r) for r in revs))
1697 def events():
1698 def events():
1698 for r in rlog:
1699 for r in rlog:
1699 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1700 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1700 if p != -1)))
1701 if p != -1)))
1701 if r in revs:
1702 if r in revs:
1702 yield 'l', (r, "r%i" % r)
1703 yield 'l', (r, "r%i" % r)
1703 elif repo:
1704 elif repo:
1704 cl = repo.changelog
1705 cl = repo.changelog
1705 tags = opts.get('tags')
1706 tags = opts.get('tags')
1706 branches = opts.get('branches')
1707 branches = opts.get('branches')
1707 if tags:
1708 if tags:
1708 labels = {}
1709 labels = {}
1709 for l, n in repo.tags().items():
1710 for l, n in repo.tags().items():
1710 labels.setdefault(cl.rev(n), []).append(l)
1711 labels.setdefault(cl.rev(n), []).append(l)
1711 def events():
1712 def events():
1712 b = "default"
1713 b = "default"
1713 for r in cl:
1714 for r in cl:
1714 if branches:
1715 if branches:
1715 newb = cl.read(cl.node(r))[5]['branch']
1716 newb = cl.read(cl.node(r))[5]['branch']
1716 if newb != b:
1717 if newb != b:
1717 yield 'a', newb
1718 yield 'a', newb
1718 b = newb
1719 b = newb
1719 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1720 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1720 if p != -1)))
1721 if p != -1)))
1721 if tags:
1722 if tags:
1722 ls = labels.get(r)
1723 ls = labels.get(r)
1723 if ls:
1724 if ls:
1724 for l in ls:
1725 for l in ls:
1725 yield 'l', (r, l)
1726 yield 'l', (r, l)
1726 else:
1727 else:
1727 raise util.Abort(_('need repo for changelog dag'))
1728 raise util.Abort(_('need repo for changelog dag'))
1728
1729
1729 for line in dagparser.dagtextlines(events(),
1730 for line in dagparser.dagtextlines(events(),
1730 addspaces=spaces,
1731 addspaces=spaces,
1731 wraplabels=True,
1732 wraplabels=True,
1732 wrapannotations=True,
1733 wrapannotations=True,
1733 wrapnonlinear=dots,
1734 wrapnonlinear=dots,
1734 usedots=dots,
1735 usedots=dots,
1735 maxlinewidth=70):
1736 maxlinewidth=70):
1736 ui.write(line)
1737 ui.write(line)
1737 ui.write("\n")
1738 ui.write("\n")
1738
1739
1739 @command('debugdata',
1740 @command('debugdata',
1740 [('c', 'changelog', False, _('open changelog')),
1741 [('c', 'changelog', False, _('open changelog')),
1741 ('m', 'manifest', False, _('open manifest'))],
1742 ('m', 'manifest', False, _('open manifest'))],
1742 _('-c|-m|FILE REV'))
1743 _('-c|-m|FILE REV'))
1743 def debugdata(ui, repo, file_, rev = None, **opts):
1744 def debugdata(ui, repo, file_, rev = None, **opts):
1744 """dump the contents of a data file revision"""
1745 """dump the contents of a data file revision"""
1745 if opts.get('changelog') or opts.get('manifest'):
1746 if opts.get('changelog') or opts.get('manifest'):
1746 file_, rev = None, file_
1747 file_, rev = None, file_
1747 elif rev is None:
1748 elif rev is None:
1748 raise error.CommandError('debugdata', _('invalid arguments'))
1749 raise error.CommandError('debugdata', _('invalid arguments'))
1749 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1750 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1750 try:
1751 try:
1751 ui.write(r.revision(r.lookup(rev)))
1752 ui.write(r.revision(r.lookup(rev)))
1752 except KeyError:
1753 except KeyError:
1753 raise util.Abort(_('invalid revision identifier %s') % rev)
1754 raise util.Abort(_('invalid revision identifier %s') % rev)
1754
1755
1755 @command('debugdate',
1756 @command('debugdate',
1756 [('e', 'extended', None, _('try extended date formats'))],
1757 [('e', 'extended', None, _('try extended date formats'))],
1757 _('[-e] DATE [RANGE]'))
1758 _('[-e] DATE [RANGE]'))
1758 def debugdate(ui, date, range=None, **opts):
1759 def debugdate(ui, date, range=None, **opts):
1759 """parse and display a date"""
1760 """parse and display a date"""
1760 if opts["extended"]:
1761 if opts["extended"]:
1761 d = util.parsedate(date, util.extendeddateformats)
1762 d = util.parsedate(date, util.extendeddateformats)
1762 else:
1763 else:
1763 d = util.parsedate(date)
1764 d = util.parsedate(date)
1764 ui.write("internal: %s %s\n" % d)
1765 ui.write("internal: %s %s\n" % d)
1765 ui.write("standard: %s\n" % util.datestr(d))
1766 ui.write("standard: %s\n" % util.datestr(d))
1766 if range:
1767 if range:
1767 m = util.matchdate(range)
1768 m = util.matchdate(range)
1768 ui.write("match: %s\n" % m(d[0]))
1769 ui.write("match: %s\n" % m(d[0]))
1769
1770
1770 @command('debugdiscovery',
1771 @command('debugdiscovery',
1771 [('', 'old', None, _('use old-style discovery')),
1772 [('', 'old', None, _('use old-style discovery')),
1772 ('', 'nonheads', None,
1773 ('', 'nonheads', None,
1773 _('use old-style discovery with non-heads included')),
1774 _('use old-style discovery with non-heads included')),
1774 ] + remoteopts,
1775 ] + remoteopts,
1775 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1776 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1776 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1777 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1777 """runs the changeset discovery protocol in isolation"""
1778 """runs the changeset discovery protocol in isolation"""
1778 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1779 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1779 opts.get('branch'))
1780 opts.get('branch'))
1780 remote = hg.peer(repo, opts, remoteurl)
1781 remote = hg.peer(repo, opts, remoteurl)
1781 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1782 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1782
1783
1783 # make sure tests are repeatable
1784 # make sure tests are repeatable
1784 random.seed(12323)
1785 random.seed(12323)
1785
1786
1786 def doit(localheads, remoteheads):
1787 def doit(localheads, remoteheads):
1787 if opts.get('old'):
1788 if opts.get('old'):
1788 if localheads:
1789 if localheads:
1789 raise util.Abort('cannot use localheads with old style '
1790 raise util.Abort('cannot use localheads with old style '
1790 'discovery')
1791 'discovery')
1791 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1792 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1792 force=True)
1793 force=True)
1793 common = set(common)
1794 common = set(common)
1794 if not opts.get('nonheads'):
1795 if not opts.get('nonheads'):
1795 ui.write("unpruned common: %s\n" % " ".join([short(n)
1796 ui.write("unpruned common: %s\n" % " ".join([short(n)
1796 for n in common]))
1797 for n in common]))
1797 dag = dagutil.revlogdag(repo.changelog)
1798 dag = dagutil.revlogdag(repo.changelog)
1798 all = dag.ancestorset(dag.internalizeall(common))
1799 all = dag.ancestorset(dag.internalizeall(common))
1799 common = dag.externalizeall(dag.headsetofconnecteds(all))
1800 common = dag.externalizeall(dag.headsetofconnecteds(all))
1800 else:
1801 else:
1801 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1802 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1802 common = set(common)
1803 common = set(common)
1803 rheads = set(hds)
1804 rheads = set(hds)
1804 lheads = set(repo.heads())
1805 lheads = set(repo.heads())
1805 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1806 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1806 if lheads <= common:
1807 if lheads <= common:
1807 ui.write("local is subset\n")
1808 ui.write("local is subset\n")
1808 elif rheads <= common:
1809 elif rheads <= common:
1809 ui.write("remote is subset\n")
1810 ui.write("remote is subset\n")
1810
1811
1811 serverlogs = opts.get('serverlog')
1812 serverlogs = opts.get('serverlog')
1812 if serverlogs:
1813 if serverlogs:
1813 for filename in serverlogs:
1814 for filename in serverlogs:
1814 logfile = open(filename, 'r')
1815 logfile = open(filename, 'r')
1815 try:
1816 try:
1816 line = logfile.readline()
1817 line = logfile.readline()
1817 while line:
1818 while line:
1818 parts = line.strip().split(';')
1819 parts = line.strip().split(';')
1819 op = parts[1]
1820 op = parts[1]
1820 if op == 'cg':
1821 if op == 'cg':
1821 pass
1822 pass
1822 elif op == 'cgss':
1823 elif op == 'cgss':
1823 doit(parts[2].split(' '), parts[3].split(' '))
1824 doit(parts[2].split(' '), parts[3].split(' '))
1824 elif op == 'unb':
1825 elif op == 'unb':
1825 doit(parts[3].split(' '), parts[2].split(' '))
1826 doit(parts[3].split(' '), parts[2].split(' '))
1826 line = logfile.readline()
1827 line = logfile.readline()
1827 finally:
1828 finally:
1828 logfile.close()
1829 logfile.close()
1829
1830
1830 else:
1831 else:
1831 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1832 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1832 opts.get('remote_head'))
1833 opts.get('remote_head'))
1833 localrevs = opts.get('local_head')
1834 localrevs = opts.get('local_head')
1834 doit(localrevs, remoterevs)
1835 doit(localrevs, remoterevs)
1835
1836
1836 @command('debugfileset', [], ('REVSPEC'))
1837 @command('debugfileset', [], ('REVSPEC'))
1837 def debugfileset(ui, repo, expr):
1838 def debugfileset(ui, repo, expr):
1838 '''parse and apply a fileset specification'''
1839 '''parse and apply a fileset specification'''
1839 if ui.verbose:
1840 if ui.verbose:
1840 tree = fileset.parse(expr)[0]
1841 tree = fileset.parse(expr)[0]
1841 ui.note(tree, "\n")
1842 ui.note(tree, "\n")
1842
1843
1843 for f in fileset.getfileset(repo[None], expr):
1844 for f in fileset.getfileset(repo[None], expr):
1844 ui.write("%s\n" % f)
1845 ui.write("%s\n" % f)
1845
1846
1846 @command('debugfsinfo', [], _('[PATH]'))
1847 @command('debugfsinfo', [], _('[PATH]'))
1847 def debugfsinfo(ui, path = "."):
1848 def debugfsinfo(ui, path = "."):
1848 """show information detected about current filesystem"""
1849 """show information detected about current filesystem"""
1849 util.writefile('.debugfsinfo', '')
1850 util.writefile('.debugfsinfo', '')
1850 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1851 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1851 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1852 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1852 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1853 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1853 and 'yes' or 'no'))
1854 and 'yes' or 'no'))
1854 os.unlink('.debugfsinfo')
1855 os.unlink('.debugfsinfo')
1855
1856
1856 @command('debuggetbundle',
1857 @command('debuggetbundle',
1857 [('H', 'head', [], _('id of head node'), _('ID')),
1858 [('H', 'head', [], _('id of head node'), _('ID')),
1858 ('C', 'common', [], _('id of common node'), _('ID')),
1859 ('C', 'common', [], _('id of common node'), _('ID')),
1859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1860 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1860 _('REPO FILE [-H|-C ID]...'))
1861 _('REPO FILE [-H|-C ID]...'))
1861 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1862 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1862 """retrieves a bundle from a repo
1863 """retrieves a bundle from a repo
1863
1864
1864 Every ID must be a full-length hex node id string. Saves the bundle to the
1865 Every ID must be a full-length hex node id string. Saves the bundle to the
1865 given file.
1866 given file.
1866 """
1867 """
1867 repo = hg.peer(ui, opts, repopath)
1868 repo = hg.peer(ui, opts, repopath)
1868 if not repo.capable('getbundle'):
1869 if not repo.capable('getbundle'):
1869 raise util.Abort("getbundle() not supported by target repository")
1870 raise util.Abort("getbundle() not supported by target repository")
1870 args = {}
1871 args = {}
1871 if common:
1872 if common:
1872 args['common'] = [bin(s) for s in common]
1873 args['common'] = [bin(s) for s in common]
1873 if head:
1874 if head:
1874 args['heads'] = [bin(s) for s in head]
1875 args['heads'] = [bin(s) for s in head]
1875 bundle = repo.getbundle('debug', **args)
1876 bundle = repo.getbundle('debug', **args)
1876
1877
1877 bundletype = opts.get('type', 'bzip2').lower()
1878 bundletype = opts.get('type', 'bzip2').lower()
1878 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1879 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1879 bundletype = btypes.get(bundletype)
1880 bundletype = btypes.get(bundletype)
1880 if bundletype not in changegroup.bundletypes:
1881 if bundletype not in changegroup.bundletypes:
1881 raise util.Abort(_('unknown bundle type specified with --type'))
1882 raise util.Abort(_('unknown bundle type specified with --type'))
1882 changegroup.writebundle(bundle, bundlepath, bundletype)
1883 changegroup.writebundle(bundle, bundlepath, bundletype)
1883
1884
1884 @command('debugignore', [], '')
1885 @command('debugignore', [], '')
1885 def debugignore(ui, repo, *values, **opts):
1886 def debugignore(ui, repo, *values, **opts):
1886 """display the combined ignore pattern"""
1887 """display the combined ignore pattern"""
1887 ignore = repo.dirstate._ignore
1888 ignore = repo.dirstate._ignore
1888 includepat = getattr(ignore, 'includepat', None)
1889 includepat = getattr(ignore, 'includepat', None)
1889 if includepat is not None:
1890 if includepat is not None:
1890 ui.write("%s\n" % includepat)
1891 ui.write("%s\n" % includepat)
1891 else:
1892 else:
1892 raise util.Abort(_("no ignore patterns found"))
1893 raise util.Abort(_("no ignore patterns found"))
1893
1894
1894 @command('debugindex',
1895 @command('debugindex',
1895 [('c', 'changelog', False, _('open changelog')),
1896 [('c', 'changelog', False, _('open changelog')),
1896 ('m', 'manifest', False, _('open manifest')),
1897 ('m', 'manifest', False, _('open manifest')),
1897 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1898 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1898 _('[-f FORMAT] -c|-m|FILE'))
1899 _('[-f FORMAT] -c|-m|FILE'))
1899 def debugindex(ui, repo, file_ = None, **opts):
1900 def debugindex(ui, repo, file_ = None, **opts):
1900 """dump the contents of an index file"""
1901 """dump the contents of an index file"""
1901 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1902 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1902 format = opts.get('format', 0)
1903 format = opts.get('format', 0)
1903 if format not in (0, 1):
1904 if format not in (0, 1):
1904 raise util.Abort(_("unknown format %d") % format)
1905 raise util.Abort(_("unknown format %d") % format)
1905
1906
1906 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1907 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1907 if generaldelta:
1908 if generaldelta:
1908 basehdr = ' delta'
1909 basehdr = ' delta'
1909 else:
1910 else:
1910 basehdr = ' base'
1911 basehdr = ' base'
1911
1912
1912 if format == 0:
1913 if format == 0:
1913 ui.write(" rev offset length " + basehdr + " linkrev"
1914 ui.write(" rev offset length " + basehdr + " linkrev"
1914 " nodeid p1 p2\n")
1915 " nodeid p1 p2\n")
1915 elif format == 1:
1916 elif format == 1:
1916 ui.write(" rev flag offset length"
1917 ui.write(" rev flag offset length"
1917 " size " + basehdr + " link p1 p2"
1918 " size " + basehdr + " link p1 p2"
1918 " nodeid\n")
1919 " nodeid\n")
1919
1920
1920 for i in r:
1921 for i in r:
1921 node = r.node(i)
1922 node = r.node(i)
1922 if generaldelta:
1923 if generaldelta:
1923 base = r.deltaparent(i)
1924 base = r.deltaparent(i)
1924 else:
1925 else:
1925 base = r.chainbase(i)
1926 base = r.chainbase(i)
1926 if format == 0:
1927 if format == 0:
1927 try:
1928 try:
1928 pp = r.parents(node)
1929 pp = r.parents(node)
1929 except Exception:
1930 except Exception:
1930 pp = [nullid, nullid]
1931 pp = [nullid, nullid]
1931 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1932 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1932 i, r.start(i), r.length(i), base, r.linkrev(i),
1933 i, r.start(i), r.length(i), base, r.linkrev(i),
1933 short(node), short(pp[0]), short(pp[1])))
1934 short(node), short(pp[0]), short(pp[1])))
1934 elif format == 1:
1935 elif format == 1:
1935 pr = r.parentrevs(i)
1936 pr = r.parentrevs(i)
1936 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1937 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1937 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1938 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1938 base, r.linkrev(i), pr[0], pr[1], short(node)))
1939 base, r.linkrev(i), pr[0], pr[1], short(node)))
1939
1940
1940 @command('debugindexdot', [], _('FILE'))
1941 @command('debugindexdot', [], _('FILE'))
1941 def debugindexdot(ui, repo, file_):
1942 def debugindexdot(ui, repo, file_):
1942 """dump an index DAG as a graphviz dot file"""
1943 """dump an index DAG as a graphviz dot file"""
1943 r = None
1944 r = None
1944 if repo:
1945 if repo:
1945 filelog = repo.file(file_)
1946 filelog = repo.file(file_)
1946 if len(filelog):
1947 if len(filelog):
1947 r = filelog
1948 r = filelog
1948 if not r:
1949 if not r:
1949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1950 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1950 ui.write("digraph G {\n")
1951 ui.write("digraph G {\n")
1951 for i in r:
1952 for i in r:
1952 node = r.node(i)
1953 node = r.node(i)
1953 pp = r.parents(node)
1954 pp = r.parents(node)
1954 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1955 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1955 if pp[1] != nullid:
1956 if pp[1] != nullid:
1956 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1957 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1957 ui.write("}\n")
1958 ui.write("}\n")
1958
1959
1959 @command('debuginstall', [], '')
1960 @command('debuginstall', [], '')
1960 def debuginstall(ui):
1961 def debuginstall(ui):
1961 '''test Mercurial installation
1962 '''test Mercurial installation
1962
1963
1963 Returns 0 on success.
1964 Returns 0 on success.
1964 '''
1965 '''
1965
1966
1966 def writetemp(contents):
1967 def writetemp(contents):
1967 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1968 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1968 f = os.fdopen(fd, "wb")
1969 f = os.fdopen(fd, "wb")
1969 f.write(contents)
1970 f.write(contents)
1970 f.close()
1971 f.close()
1971 return name
1972 return name
1972
1973
1973 problems = 0
1974 problems = 0
1974
1975
1975 # encoding
1976 # encoding
1976 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1977 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1977 try:
1978 try:
1978 encoding.fromlocal("test")
1979 encoding.fromlocal("test")
1979 except util.Abort, inst:
1980 except util.Abort, inst:
1980 ui.write(" %s\n" % inst)
1981 ui.write(" %s\n" % inst)
1981 ui.write(_(" (check that your locale is properly set)\n"))
1982 ui.write(_(" (check that your locale is properly set)\n"))
1982 problems += 1
1983 problems += 1
1983
1984
1984 # compiled modules
1985 # compiled modules
1985 ui.status(_("checking installed modules (%s)...\n")
1986 ui.status(_("checking installed modules (%s)...\n")
1986 % os.path.dirname(__file__))
1987 % os.path.dirname(__file__))
1987 try:
1988 try:
1988 import bdiff, mpatch, base85, osutil
1989 import bdiff, mpatch, base85, osutil
1989 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1990 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1990 except Exception, inst:
1991 except Exception, inst:
1991 ui.write(" %s\n" % inst)
1992 ui.write(" %s\n" % inst)
1992 ui.write(_(" One or more extensions could not be found"))
1993 ui.write(_(" One or more extensions could not be found"))
1993 ui.write(_(" (check that you compiled the extensions)\n"))
1994 ui.write(_(" (check that you compiled the extensions)\n"))
1994 problems += 1
1995 problems += 1
1995
1996
1996 # templates
1997 # templates
1997 import templater
1998 import templater
1998 p = templater.templatepath()
1999 p = templater.templatepath()
1999 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2000 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2000 try:
2001 try:
2001 templater.templater(templater.templatepath("map-cmdline.default"))
2002 templater.templater(templater.templatepath("map-cmdline.default"))
2002 except Exception, inst:
2003 except Exception, inst:
2003 ui.write(" %s\n" % inst)
2004 ui.write(" %s\n" % inst)
2004 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2005 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2005 problems += 1
2006 problems += 1
2006
2007
2007 # editor
2008 # editor
2008 ui.status(_("checking commit editor...\n"))
2009 ui.status(_("checking commit editor...\n"))
2009 editor = ui.geteditor()
2010 editor = ui.geteditor()
2010 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2011 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2011 if not cmdpath:
2012 if not cmdpath:
2012 if editor == 'vi':
2013 if editor == 'vi':
2013 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2014 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2014 ui.write(_(" (specify a commit editor in your configuration"
2015 ui.write(_(" (specify a commit editor in your configuration"
2015 " file)\n"))
2016 " file)\n"))
2016 else:
2017 else:
2017 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2018 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2018 ui.write(_(" (specify a commit editor in your configuration"
2019 ui.write(_(" (specify a commit editor in your configuration"
2019 " file)\n"))
2020 " file)\n"))
2020 problems += 1
2021 problems += 1
2021
2022
2022 # check username
2023 # check username
2023 ui.status(_("checking username...\n"))
2024 ui.status(_("checking username...\n"))
2024 try:
2025 try:
2025 ui.username()
2026 ui.username()
2026 except util.Abort, e:
2027 except util.Abort, e:
2027 ui.write(" %s\n" % e)
2028 ui.write(" %s\n" % e)
2028 ui.write(_(" (specify a username in your configuration file)\n"))
2029 ui.write(_(" (specify a username in your configuration file)\n"))
2029 problems += 1
2030 problems += 1
2030
2031
2031 if not problems:
2032 if not problems:
2032 ui.status(_("no problems detected\n"))
2033 ui.status(_("no problems detected\n"))
2033 else:
2034 else:
2034 ui.write(_("%s problems detected,"
2035 ui.write(_("%s problems detected,"
2035 " please check your install!\n") % problems)
2036 " please check your install!\n") % problems)
2036
2037
2037 return problems
2038 return problems
2038
2039
2039 @command('debugknown', [], _('REPO ID...'))
2040 @command('debugknown', [], _('REPO ID...'))
2040 def debugknown(ui, repopath, *ids, **opts):
2041 def debugknown(ui, repopath, *ids, **opts):
2041 """test whether node ids are known to a repo
2042 """test whether node ids are known to a repo
2042
2043
2043 Every ID must be a full-length hex node id string. Returns a list of 0s
2044 Every ID must be a full-length hex node id string. Returns a list of 0s
2044 and 1s indicating unknown/known.
2045 and 1s indicating unknown/known.
2045 """
2046 """
2046 repo = hg.peer(ui, opts, repopath)
2047 repo = hg.peer(ui, opts, repopath)
2047 if not repo.capable('known'):
2048 if not repo.capable('known'):
2048 raise util.Abort("known() not supported by target repository")
2049 raise util.Abort("known() not supported by target repository")
2049 flags = repo.known([bin(s) for s in ids])
2050 flags = repo.known([bin(s) for s in ids])
2050 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2051 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2051
2052
2052 @command('debugobsolete', [] + commitopts2,
2053 @command('debugobsolete', [] + commitopts2,
2053 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2054 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2054 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2055 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2055 """create arbitrary obsolete marker"""
2056 """create arbitrary obsolete marker"""
2056 if precursor is not None:
2057 if precursor is not None:
2057 metadata = {}
2058 metadata = {}
2058 if 'date' in opts:
2059 if 'date' in opts:
2059 metadata['date'] = opts['date']
2060 metadata['date'] = opts['date']
2060 metadata['user'] = opts['user'] or ui.username()
2061 metadata['user'] = opts['user'] or ui.username()
2061 succs = tuple(bin(succ) for succ in successors)
2062 succs = tuple(bin(succ) for succ in successors)
2062 l = repo.lock()
2063 l = repo.lock()
2063 try:
2064 try:
2064 tr = repo.transaction('debugobsolete')
2065 tr = repo.transaction('debugobsolete')
2065 try:
2066 try:
2066 repo.obsstore.create(tr, bin(precursor), succs, 0, metadata)
2067 repo.obsstore.create(tr, bin(precursor), succs, 0, metadata)
2067 tr.close()
2068 tr.close()
2068 finally:
2069 finally:
2069 tr.release()
2070 tr.release()
2070 finally:
2071 finally:
2071 l.release()
2072 l.release()
2072 else:
2073 else:
2073 for m in obsolete.allmarkers(repo):
2074 for m in obsolete.allmarkers(repo):
2074 ui.write(hex(m.precnode()))
2075 ui.write(hex(m.precnode()))
2075 for repl in m.succnodes():
2076 for repl in m.succnodes():
2076 ui.write(' ')
2077 ui.write(' ')
2077 ui.write(hex(repl))
2078 ui.write(hex(repl))
2078 ui.write(' %X ' % m._data[2])
2079 ui.write(' %X ' % m._data[2])
2079 ui.write(m.metadata())
2080 ui.write(m.metadata())
2080 ui.write('\n')
2081 ui.write('\n')
2081
2082
2082 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2083 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2083 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2084 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2084 '''access the pushkey key/value protocol
2085 '''access the pushkey key/value protocol
2085
2086
2086 With two args, list the keys in the given namespace.
2087 With two args, list the keys in the given namespace.
2087
2088
2088 With five args, set a key to new if it currently is set to old.
2089 With five args, set a key to new if it currently is set to old.
2089 Reports success or failure.
2090 Reports success or failure.
2090 '''
2091 '''
2091
2092
2092 target = hg.peer(ui, {}, repopath)
2093 target = hg.peer(ui, {}, repopath)
2093 if keyinfo:
2094 if keyinfo:
2094 key, old, new = keyinfo
2095 key, old, new = keyinfo
2095 r = target.pushkey(namespace, key, old, new)
2096 r = target.pushkey(namespace, key, old, new)
2096 ui.status(str(r) + '\n')
2097 ui.status(str(r) + '\n')
2097 return not r
2098 return not r
2098 else:
2099 else:
2099 for k, v in target.listkeys(namespace).iteritems():
2100 for k, v in target.listkeys(namespace).iteritems():
2100 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2101 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2101 v.encode('string-escape')))
2102 v.encode('string-escape')))
2102
2103
2103 @command('debugpvec', [], _('A B'))
2104 @command('debugpvec', [], _('A B'))
2104 def debugpvec(ui, repo, a, b=None):
2105 def debugpvec(ui, repo, a, b=None):
2105 ca = scmutil.revsingle(repo, a)
2106 ca = scmutil.revsingle(repo, a)
2106 cb = scmutil.revsingle(repo, b)
2107 cb = scmutil.revsingle(repo, b)
2107 pa = pvec.ctxpvec(ca)
2108 pa = pvec.ctxpvec(ca)
2108 pb = pvec.ctxpvec(cb)
2109 pb = pvec.ctxpvec(cb)
2109 if pa == pb:
2110 if pa == pb:
2110 rel = "="
2111 rel = "="
2111 elif pa > pb:
2112 elif pa > pb:
2112 rel = ">"
2113 rel = ">"
2113 elif pa < pb:
2114 elif pa < pb:
2114 rel = "<"
2115 rel = "<"
2115 elif pa | pb:
2116 elif pa | pb:
2116 rel = "|"
2117 rel = "|"
2117 ui.write(_("a: %s\n") % pa)
2118 ui.write(_("a: %s\n") % pa)
2118 ui.write(_("b: %s\n") % pb)
2119 ui.write(_("b: %s\n") % pb)
2119 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2120 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2120 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2121 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2121 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2122 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2122 pa.distance(pb), rel))
2123 pa.distance(pb), rel))
2123
2124
2124 @command('debugrebuildstate',
2125 @command('debugrebuildstate',
2125 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2126 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2126 _('[-r REV] [REV]'))
2127 _('[-r REV] [REV]'))
2127 def debugrebuildstate(ui, repo, rev="tip"):
2128 def debugrebuildstate(ui, repo, rev="tip"):
2128 """rebuild the dirstate as it would look like for the given revision"""
2129 """rebuild the dirstate as it would look like for the given revision"""
2129 ctx = scmutil.revsingle(repo, rev)
2130 ctx = scmutil.revsingle(repo, rev)
2130 wlock = repo.wlock()
2131 wlock = repo.wlock()
2131 try:
2132 try:
2132 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2133 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2133 finally:
2134 finally:
2134 wlock.release()
2135 wlock.release()
2135
2136
2136 @command('debugrename',
2137 @command('debugrename',
2137 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2138 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2138 _('[-r REV] FILE'))
2139 _('[-r REV] FILE'))
2139 def debugrename(ui, repo, file1, *pats, **opts):
2140 def debugrename(ui, repo, file1, *pats, **opts):
2140 """dump rename information"""
2141 """dump rename information"""
2141
2142
2142 ctx = scmutil.revsingle(repo, opts.get('rev'))
2143 ctx = scmutil.revsingle(repo, opts.get('rev'))
2143 m = scmutil.match(ctx, (file1,) + pats, opts)
2144 m = scmutil.match(ctx, (file1,) + pats, opts)
2144 for abs in ctx.walk(m):
2145 for abs in ctx.walk(m):
2145 fctx = ctx[abs]
2146 fctx = ctx[abs]
2146 o = fctx.filelog().renamed(fctx.filenode())
2147 o = fctx.filelog().renamed(fctx.filenode())
2147 rel = m.rel(abs)
2148 rel = m.rel(abs)
2148 if o:
2149 if o:
2149 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2150 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2150 else:
2151 else:
2151 ui.write(_("%s not renamed\n") % rel)
2152 ui.write(_("%s not renamed\n") % rel)
2152
2153
2153 @command('debugrevlog',
2154 @command('debugrevlog',
2154 [('c', 'changelog', False, _('open changelog')),
2155 [('c', 'changelog', False, _('open changelog')),
2155 ('m', 'manifest', False, _('open manifest')),
2156 ('m', 'manifest', False, _('open manifest')),
2156 ('d', 'dump', False, _('dump index data'))],
2157 ('d', 'dump', False, _('dump index data'))],
2157 _('-c|-m|FILE'))
2158 _('-c|-m|FILE'))
2158 def debugrevlog(ui, repo, file_ = None, **opts):
2159 def debugrevlog(ui, repo, file_ = None, **opts):
2159 """show data and statistics about a revlog"""
2160 """show data and statistics about a revlog"""
2160 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2161 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2161
2162
2162 if opts.get("dump"):
2163 if opts.get("dump"):
2163 numrevs = len(r)
2164 numrevs = len(r)
2164 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2165 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2165 " rawsize totalsize compression heads\n")
2166 " rawsize totalsize compression heads\n")
2166 ts = 0
2167 ts = 0
2167 heads = set()
2168 heads = set()
2168 for rev in xrange(numrevs):
2169 for rev in xrange(numrevs):
2169 dbase = r.deltaparent(rev)
2170 dbase = r.deltaparent(rev)
2170 if dbase == -1:
2171 if dbase == -1:
2171 dbase = rev
2172 dbase = rev
2172 cbase = r.chainbase(rev)
2173 cbase = r.chainbase(rev)
2173 p1, p2 = r.parentrevs(rev)
2174 p1, p2 = r.parentrevs(rev)
2174 rs = r.rawsize(rev)
2175 rs = r.rawsize(rev)
2175 ts = ts + rs
2176 ts = ts + rs
2176 heads -= set(r.parentrevs(rev))
2177 heads -= set(r.parentrevs(rev))
2177 heads.add(rev)
2178 heads.add(rev)
2178 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2179 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2179 (rev, p1, p2, r.start(rev), r.end(rev),
2180 (rev, p1, p2, r.start(rev), r.end(rev),
2180 r.start(dbase), r.start(cbase),
2181 r.start(dbase), r.start(cbase),
2181 r.start(p1), r.start(p2),
2182 r.start(p1), r.start(p2),
2182 rs, ts, ts / r.end(rev), len(heads)))
2183 rs, ts, ts / r.end(rev), len(heads)))
2183 return 0
2184 return 0
2184
2185
2185 v = r.version
2186 v = r.version
2186 format = v & 0xFFFF
2187 format = v & 0xFFFF
2187 flags = []
2188 flags = []
2188 gdelta = False
2189 gdelta = False
2189 if v & revlog.REVLOGNGINLINEDATA:
2190 if v & revlog.REVLOGNGINLINEDATA:
2190 flags.append('inline')
2191 flags.append('inline')
2191 if v & revlog.REVLOGGENERALDELTA:
2192 if v & revlog.REVLOGGENERALDELTA:
2192 gdelta = True
2193 gdelta = True
2193 flags.append('generaldelta')
2194 flags.append('generaldelta')
2194 if not flags:
2195 if not flags:
2195 flags = ['(none)']
2196 flags = ['(none)']
2196
2197
2197 nummerges = 0
2198 nummerges = 0
2198 numfull = 0
2199 numfull = 0
2199 numprev = 0
2200 numprev = 0
2200 nump1 = 0
2201 nump1 = 0
2201 nump2 = 0
2202 nump2 = 0
2202 numother = 0
2203 numother = 0
2203 nump1prev = 0
2204 nump1prev = 0
2204 nump2prev = 0
2205 nump2prev = 0
2205 chainlengths = []
2206 chainlengths = []
2206
2207
2207 datasize = [None, 0, 0L]
2208 datasize = [None, 0, 0L]
2208 fullsize = [None, 0, 0L]
2209 fullsize = [None, 0, 0L]
2209 deltasize = [None, 0, 0L]
2210 deltasize = [None, 0, 0L]
2210
2211
2211 def addsize(size, l):
2212 def addsize(size, l):
2212 if l[0] is None or size < l[0]:
2213 if l[0] is None or size < l[0]:
2213 l[0] = size
2214 l[0] = size
2214 if size > l[1]:
2215 if size > l[1]:
2215 l[1] = size
2216 l[1] = size
2216 l[2] += size
2217 l[2] += size
2217
2218
2218 numrevs = len(r)
2219 numrevs = len(r)
2219 for rev in xrange(numrevs):
2220 for rev in xrange(numrevs):
2220 p1, p2 = r.parentrevs(rev)
2221 p1, p2 = r.parentrevs(rev)
2221 delta = r.deltaparent(rev)
2222 delta = r.deltaparent(rev)
2222 if format > 0:
2223 if format > 0:
2223 addsize(r.rawsize(rev), datasize)
2224 addsize(r.rawsize(rev), datasize)
2224 if p2 != nullrev:
2225 if p2 != nullrev:
2225 nummerges += 1
2226 nummerges += 1
2226 size = r.length(rev)
2227 size = r.length(rev)
2227 if delta == nullrev:
2228 if delta == nullrev:
2228 chainlengths.append(0)
2229 chainlengths.append(0)
2229 numfull += 1
2230 numfull += 1
2230 addsize(size, fullsize)
2231 addsize(size, fullsize)
2231 else:
2232 else:
2232 chainlengths.append(chainlengths[delta] + 1)
2233 chainlengths.append(chainlengths[delta] + 1)
2233 addsize(size, deltasize)
2234 addsize(size, deltasize)
2234 if delta == rev - 1:
2235 if delta == rev - 1:
2235 numprev += 1
2236 numprev += 1
2236 if delta == p1:
2237 if delta == p1:
2237 nump1prev += 1
2238 nump1prev += 1
2238 elif delta == p2:
2239 elif delta == p2:
2239 nump2prev += 1
2240 nump2prev += 1
2240 elif delta == p1:
2241 elif delta == p1:
2241 nump1 += 1
2242 nump1 += 1
2242 elif delta == p2:
2243 elif delta == p2:
2243 nump2 += 1
2244 nump2 += 1
2244 elif delta != nullrev:
2245 elif delta != nullrev:
2245 numother += 1
2246 numother += 1
2246
2247
2247 numdeltas = numrevs - numfull
2248 numdeltas = numrevs - numfull
2248 numoprev = numprev - nump1prev - nump2prev
2249 numoprev = numprev - nump1prev - nump2prev
2249 totalrawsize = datasize[2]
2250 totalrawsize = datasize[2]
2250 datasize[2] /= numrevs
2251 datasize[2] /= numrevs
2251 fulltotal = fullsize[2]
2252 fulltotal = fullsize[2]
2252 fullsize[2] /= numfull
2253 fullsize[2] /= numfull
2253 deltatotal = deltasize[2]
2254 deltatotal = deltasize[2]
2254 deltasize[2] /= numrevs - numfull
2255 deltasize[2] /= numrevs - numfull
2255 totalsize = fulltotal + deltatotal
2256 totalsize = fulltotal + deltatotal
2256 avgchainlen = sum(chainlengths) / numrevs
2257 avgchainlen = sum(chainlengths) / numrevs
2257 compratio = totalrawsize / totalsize
2258 compratio = totalrawsize / totalsize
2258
2259
2259 basedfmtstr = '%%%dd\n'
2260 basedfmtstr = '%%%dd\n'
2260 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2261 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2261
2262
2262 def dfmtstr(max):
2263 def dfmtstr(max):
2263 return basedfmtstr % len(str(max))
2264 return basedfmtstr % len(str(max))
2264 def pcfmtstr(max, padding=0):
2265 def pcfmtstr(max, padding=0):
2265 return basepcfmtstr % (len(str(max)), ' ' * padding)
2266 return basepcfmtstr % (len(str(max)), ' ' * padding)
2266
2267
2267 def pcfmt(value, total):
2268 def pcfmt(value, total):
2268 return (value, 100 * float(value) / total)
2269 return (value, 100 * float(value) / total)
2269
2270
2270 ui.write('format : %d\n' % format)
2271 ui.write('format : %d\n' % format)
2271 ui.write('flags : %s\n' % ', '.join(flags))
2272 ui.write('flags : %s\n' % ', '.join(flags))
2272
2273
2273 ui.write('\n')
2274 ui.write('\n')
2274 fmt = pcfmtstr(totalsize)
2275 fmt = pcfmtstr(totalsize)
2275 fmt2 = dfmtstr(totalsize)
2276 fmt2 = dfmtstr(totalsize)
2276 ui.write('revisions : ' + fmt2 % numrevs)
2277 ui.write('revisions : ' + fmt2 % numrevs)
2277 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2278 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2278 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2279 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2279 ui.write('revisions : ' + fmt2 % numrevs)
2280 ui.write('revisions : ' + fmt2 % numrevs)
2280 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2281 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2281 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2282 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2282 ui.write('revision size : ' + fmt2 % totalsize)
2283 ui.write('revision size : ' + fmt2 % totalsize)
2283 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2284 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2284 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2285 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2285
2286
2286 ui.write('\n')
2287 ui.write('\n')
2287 fmt = dfmtstr(max(avgchainlen, compratio))
2288 fmt = dfmtstr(max(avgchainlen, compratio))
2288 ui.write('avg chain length : ' + fmt % avgchainlen)
2289 ui.write('avg chain length : ' + fmt % avgchainlen)
2289 ui.write('compression ratio : ' + fmt % compratio)
2290 ui.write('compression ratio : ' + fmt % compratio)
2290
2291
2291 if format > 0:
2292 if format > 0:
2292 ui.write('\n')
2293 ui.write('\n')
2293 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2294 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2294 % tuple(datasize))
2295 % tuple(datasize))
2295 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2296 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2296 % tuple(fullsize))
2297 % tuple(fullsize))
2297 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2298 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2298 % tuple(deltasize))
2299 % tuple(deltasize))
2299
2300
2300 if numdeltas > 0:
2301 if numdeltas > 0:
2301 ui.write('\n')
2302 ui.write('\n')
2302 fmt = pcfmtstr(numdeltas)
2303 fmt = pcfmtstr(numdeltas)
2303 fmt2 = pcfmtstr(numdeltas, 4)
2304 fmt2 = pcfmtstr(numdeltas, 4)
2304 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2305 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2305 if numprev > 0:
2306 if numprev > 0:
2306 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2307 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2307 numprev))
2308 numprev))
2308 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2309 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2309 numprev))
2310 numprev))
2310 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2311 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2311 numprev))
2312 numprev))
2312 if gdelta:
2313 if gdelta:
2313 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2314 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2314 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2315 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2315 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2316 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2316 numdeltas))
2317 numdeltas))
2317
2318
2318 @command('debugrevspec', [], ('REVSPEC'))
2319 @command('debugrevspec', [], ('REVSPEC'))
2319 def debugrevspec(ui, repo, expr):
2320 def debugrevspec(ui, repo, expr):
2320 """parse and apply a revision specification
2321 """parse and apply a revision specification
2321
2322
2322 Use --verbose to print the parsed tree before and after aliases
2323 Use --verbose to print the parsed tree before and after aliases
2323 expansion.
2324 expansion.
2324 """
2325 """
2325 if ui.verbose:
2326 if ui.verbose:
2326 tree = revset.parse(expr)[0]
2327 tree = revset.parse(expr)[0]
2327 ui.note(revset.prettyformat(tree), "\n")
2328 ui.note(revset.prettyformat(tree), "\n")
2328 newtree = revset.findaliases(ui, tree)
2329 newtree = revset.findaliases(ui, tree)
2329 if newtree != tree:
2330 if newtree != tree:
2330 ui.note(revset.prettyformat(newtree), "\n")
2331 ui.note(revset.prettyformat(newtree), "\n")
2331 func = revset.match(ui, expr)
2332 func = revset.match(ui, expr)
2332 for c in func(repo, range(len(repo))):
2333 for c in func(repo, range(len(repo))):
2333 ui.write("%s\n" % c)
2334 ui.write("%s\n" % c)
2334
2335
2335 @command('debugsetparents', [], _('REV1 [REV2]'))
2336 @command('debugsetparents', [], _('REV1 [REV2]'))
2336 def debugsetparents(ui, repo, rev1, rev2=None):
2337 def debugsetparents(ui, repo, rev1, rev2=None):
2337 """manually set the parents of the current working directory
2338 """manually set the parents of the current working directory
2338
2339
2339 This is useful for writing repository conversion tools, but should
2340 This is useful for writing repository conversion tools, but should
2340 be used with care.
2341 be used with care.
2341
2342
2342 Returns 0 on success.
2343 Returns 0 on success.
2343 """
2344 """
2344
2345
2345 r1 = scmutil.revsingle(repo, rev1).node()
2346 r1 = scmutil.revsingle(repo, rev1).node()
2346 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2347 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2347
2348
2348 wlock = repo.wlock()
2349 wlock = repo.wlock()
2349 try:
2350 try:
2350 repo.setparents(r1, r2)
2351 repo.setparents(r1, r2)
2351 finally:
2352 finally:
2352 wlock.release()
2353 wlock.release()
2353
2354
2354 @command('debugstate',
2355 @command('debugstate',
2355 [('', 'nodates', None, _('do not display the saved mtime')),
2356 [('', 'nodates', None, _('do not display the saved mtime')),
2356 ('', 'datesort', None, _('sort by saved mtime'))],
2357 ('', 'datesort', None, _('sort by saved mtime'))],
2357 _('[OPTION]...'))
2358 _('[OPTION]...'))
2358 def debugstate(ui, repo, nodates=None, datesort=None):
2359 def debugstate(ui, repo, nodates=None, datesort=None):
2359 """show the contents of the current dirstate"""
2360 """show the contents of the current dirstate"""
2360 timestr = ""
2361 timestr = ""
2361 showdate = not nodates
2362 showdate = not nodates
2362 if datesort:
2363 if datesort:
2363 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2364 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2364 else:
2365 else:
2365 keyfunc = None # sort by filename
2366 keyfunc = None # sort by filename
2366 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2367 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2367 if showdate:
2368 if showdate:
2368 if ent[3] == -1:
2369 if ent[3] == -1:
2369 # Pad or slice to locale representation
2370 # Pad or slice to locale representation
2370 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2371 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2371 time.localtime(0)))
2372 time.localtime(0)))
2372 timestr = 'unset'
2373 timestr = 'unset'
2373 timestr = (timestr[:locale_len] +
2374 timestr = (timestr[:locale_len] +
2374 ' ' * (locale_len - len(timestr)))
2375 ' ' * (locale_len - len(timestr)))
2375 else:
2376 else:
2376 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2377 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2377 time.localtime(ent[3]))
2378 time.localtime(ent[3]))
2378 if ent[1] & 020000:
2379 if ent[1] & 020000:
2379 mode = 'lnk'
2380 mode = 'lnk'
2380 else:
2381 else:
2381 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2382 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2382 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2383 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2383 for f in repo.dirstate.copies():
2384 for f in repo.dirstate.copies():
2384 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2385 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2385
2386
2386 @command('debugsub',
2387 @command('debugsub',
2387 [('r', 'rev', '',
2388 [('r', 'rev', '',
2388 _('revision to check'), _('REV'))],
2389 _('revision to check'), _('REV'))],
2389 _('[-r REV] [REV]'))
2390 _('[-r REV] [REV]'))
2390 def debugsub(ui, repo, rev=None):
2391 def debugsub(ui, repo, rev=None):
2391 ctx = scmutil.revsingle(repo, rev, None)
2392 ctx = scmutil.revsingle(repo, rev, None)
2392 for k, v in sorted(ctx.substate.items()):
2393 for k, v in sorted(ctx.substate.items()):
2393 ui.write('path %s\n' % k)
2394 ui.write('path %s\n' % k)
2394 ui.write(' source %s\n' % v[0])
2395 ui.write(' source %s\n' % v[0])
2395 ui.write(' revision %s\n' % v[1])
2396 ui.write(' revision %s\n' % v[1])
2396
2397
2397 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2398 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2398 def debugwalk(ui, repo, *pats, **opts):
2399 def debugwalk(ui, repo, *pats, **opts):
2399 """show how files match on given patterns"""
2400 """show how files match on given patterns"""
2400 m = scmutil.match(repo[None], pats, opts)
2401 m = scmutil.match(repo[None], pats, opts)
2401 items = list(repo.walk(m))
2402 items = list(repo.walk(m))
2402 if not items:
2403 if not items:
2403 return
2404 return
2404 f = lambda fn: fn
2405 f = lambda fn: fn
2405 if ui.configbool('ui', 'slash') and os.sep != '/':
2406 if ui.configbool('ui', 'slash') and os.sep != '/':
2406 f = lambda fn: util.normpath(fn)
2407 f = lambda fn: util.normpath(fn)
2407 fmt = 'f %%-%ds %%-%ds %%s' % (
2408 fmt = 'f %%-%ds %%-%ds %%s' % (
2408 max([len(abs) for abs in items]),
2409 max([len(abs) for abs in items]),
2409 max([len(m.rel(abs)) for abs in items]))
2410 max([len(m.rel(abs)) for abs in items]))
2410 for abs in items:
2411 for abs in items:
2411 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2412 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2412 ui.write("%s\n" % line.rstrip())
2413 ui.write("%s\n" % line.rstrip())
2413
2414
2414 @command('debugwireargs',
2415 @command('debugwireargs',
2415 [('', 'three', '', 'three'),
2416 [('', 'three', '', 'three'),
2416 ('', 'four', '', 'four'),
2417 ('', 'four', '', 'four'),
2417 ('', 'five', '', 'five'),
2418 ('', 'five', '', 'five'),
2418 ] + remoteopts,
2419 ] + remoteopts,
2419 _('REPO [OPTIONS]... [ONE [TWO]]'))
2420 _('REPO [OPTIONS]... [ONE [TWO]]'))
2420 def debugwireargs(ui, repopath, *vals, **opts):
2421 def debugwireargs(ui, repopath, *vals, **opts):
2421 repo = hg.peer(ui, opts, repopath)
2422 repo = hg.peer(ui, opts, repopath)
2422 for opt in remoteopts:
2423 for opt in remoteopts:
2423 del opts[opt[1]]
2424 del opts[opt[1]]
2424 args = {}
2425 args = {}
2425 for k, v in opts.iteritems():
2426 for k, v in opts.iteritems():
2426 if v:
2427 if v:
2427 args[k] = v
2428 args[k] = v
2428 # run twice to check that we don't mess up the stream for the next command
2429 # run twice to check that we don't mess up the stream for the next command
2429 res1 = repo.debugwireargs(*vals, **args)
2430 res1 = repo.debugwireargs(*vals, **args)
2430 res2 = repo.debugwireargs(*vals, **args)
2431 res2 = repo.debugwireargs(*vals, **args)
2431 ui.write("%s\n" % res1)
2432 ui.write("%s\n" % res1)
2432 if res1 != res2:
2433 if res1 != res2:
2433 ui.warn("%s\n" % res2)
2434 ui.warn("%s\n" % res2)
2434
2435
2435 @command('^diff',
2436 @command('^diff',
2436 [('r', 'rev', [], _('revision'), _('REV')),
2437 [('r', 'rev', [], _('revision'), _('REV')),
2437 ('c', 'change', '', _('change made by revision'), _('REV'))
2438 ('c', 'change', '', _('change made by revision'), _('REV'))
2438 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2439 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2439 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2440 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2440 def diff(ui, repo, *pats, **opts):
2441 def diff(ui, repo, *pats, **opts):
2441 """diff repository (or selected files)
2442 """diff repository (or selected files)
2442
2443
2443 Show differences between revisions for the specified files.
2444 Show differences between revisions for the specified files.
2444
2445
2445 Differences between files are shown using the unified diff format.
2446 Differences between files are shown using the unified diff format.
2446
2447
2447 .. note::
2448 .. note::
2448 diff may generate unexpected results for merges, as it will
2449 diff may generate unexpected results for merges, as it will
2449 default to comparing against the working directory's first
2450 default to comparing against the working directory's first
2450 parent changeset if no revisions are specified.
2451 parent changeset if no revisions are specified.
2451
2452
2452 When two revision arguments are given, then changes are shown
2453 When two revision arguments are given, then changes are shown
2453 between those revisions. If only one revision is specified then
2454 between those revisions. If only one revision is specified then
2454 that revision is compared to the working directory, and, when no
2455 that revision is compared to the working directory, and, when no
2455 revisions are specified, the working directory files are compared
2456 revisions are specified, the working directory files are compared
2456 to its parent.
2457 to its parent.
2457
2458
2458 Alternatively you can specify -c/--change with a revision to see
2459 Alternatively you can specify -c/--change with a revision to see
2459 the changes in that changeset relative to its first parent.
2460 the changes in that changeset relative to its first parent.
2460
2461
2461 Without the -a/--text option, diff will avoid generating diffs of
2462 Without the -a/--text option, diff will avoid generating diffs of
2462 files it detects as binary. With -a, diff will generate a diff
2463 files it detects as binary. With -a, diff will generate a diff
2463 anyway, probably with undesirable results.
2464 anyway, probably with undesirable results.
2464
2465
2465 Use the -g/--git option to generate diffs in the git extended diff
2466 Use the -g/--git option to generate diffs in the git extended diff
2466 format. For more information, read :hg:`help diffs`.
2467 format. For more information, read :hg:`help diffs`.
2467
2468
2468 .. container:: verbose
2469 .. container:: verbose
2469
2470
2470 Examples:
2471 Examples:
2471
2472
2472 - compare a file in the current working directory to its parent::
2473 - compare a file in the current working directory to its parent::
2473
2474
2474 hg diff foo.c
2475 hg diff foo.c
2475
2476
2476 - compare two historical versions of a directory, with rename info::
2477 - compare two historical versions of a directory, with rename info::
2477
2478
2478 hg diff --git -r 1.0:1.2 lib/
2479 hg diff --git -r 1.0:1.2 lib/
2479
2480
2480 - get change stats relative to the last change on some date::
2481 - get change stats relative to the last change on some date::
2481
2482
2482 hg diff --stat -r "date('may 2')"
2483 hg diff --stat -r "date('may 2')"
2483
2484
2484 - diff all newly-added files that contain a keyword::
2485 - diff all newly-added files that contain a keyword::
2485
2486
2486 hg diff "set:added() and grep(GNU)"
2487 hg diff "set:added() and grep(GNU)"
2487
2488
2488 - compare a revision and its parents::
2489 - compare a revision and its parents::
2489
2490
2490 hg diff -c 9353 # compare against first parent
2491 hg diff -c 9353 # compare against first parent
2491 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^2:9353 # compare against the second parent
2493 hg diff -r 9353^2:9353 # compare against the second parent
2493
2494
2494 Returns 0 on success.
2495 Returns 0 on success.
2495 """
2496 """
2496
2497
2497 revs = opts.get('rev')
2498 revs = opts.get('rev')
2498 change = opts.get('change')
2499 change = opts.get('change')
2499 stat = opts.get('stat')
2500 stat = opts.get('stat')
2500 reverse = opts.get('reverse')
2501 reverse = opts.get('reverse')
2501
2502
2502 if revs and change:
2503 if revs and change:
2503 msg = _('cannot specify --rev and --change at the same time')
2504 msg = _('cannot specify --rev and --change at the same time')
2504 raise util.Abort(msg)
2505 raise util.Abort(msg)
2505 elif change:
2506 elif change:
2506 node2 = scmutil.revsingle(repo, change, None).node()
2507 node2 = scmutil.revsingle(repo, change, None).node()
2507 node1 = repo[node2].p1().node()
2508 node1 = repo[node2].p1().node()
2508 else:
2509 else:
2509 node1, node2 = scmutil.revpair(repo, revs)
2510 node1, node2 = scmutil.revpair(repo, revs)
2510
2511
2511 if reverse:
2512 if reverse:
2512 node1, node2 = node2, node1
2513 node1, node2 = node2, node1
2513
2514
2514 diffopts = patch.diffopts(ui, opts)
2515 diffopts = patch.diffopts(ui, opts)
2515 m = scmutil.match(repo[node2], pats, opts)
2516 m = scmutil.match(repo[node2], pats, opts)
2516 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2517 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2517 listsubrepos=opts.get('subrepos'))
2518 listsubrepos=opts.get('subrepos'))
2518
2519
2519 @command('^export',
2520 @command('^export',
2520 [('o', 'output', '',
2521 [('o', 'output', '',
2521 _('print output to file with formatted name'), _('FORMAT')),
2522 _('print output to file with formatted name'), _('FORMAT')),
2522 ('', 'switch-parent', None, _('diff against the second parent')),
2523 ('', 'switch-parent', None, _('diff against the second parent')),
2523 ('r', 'rev', [], _('revisions to export'), _('REV')),
2524 ('r', 'rev', [], _('revisions to export'), _('REV')),
2524 ] + diffopts,
2525 ] + diffopts,
2525 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2526 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2526 def export(ui, repo, *changesets, **opts):
2527 def export(ui, repo, *changesets, **opts):
2527 """dump the header and diffs for one or more changesets
2528 """dump the header and diffs for one or more changesets
2528
2529
2529 Print the changeset header and diffs for one or more revisions.
2530 Print the changeset header and diffs for one or more revisions.
2530
2531
2531 The information shown in the changeset header is: author, date,
2532 The information shown in the changeset header is: author, date,
2532 branch name (if non-default), changeset hash, parent(s) and commit
2533 branch name (if non-default), changeset hash, parent(s) and commit
2533 comment.
2534 comment.
2534
2535
2535 .. note::
2536 .. note::
2536 export may generate unexpected diff output for merge
2537 export may generate unexpected diff output for merge
2537 changesets, as it will compare the merge changeset against its
2538 changesets, as it will compare the merge changeset against its
2538 first parent only.
2539 first parent only.
2539
2540
2540 Output may be to a file, in which case the name of the file is
2541 Output may be to a file, in which case the name of the file is
2541 given using a format string. The formatting rules are as follows:
2542 given using a format string. The formatting rules are as follows:
2542
2543
2543 :``%%``: literal "%" character
2544 :``%%``: literal "%" character
2544 :``%H``: changeset hash (40 hexadecimal digits)
2545 :``%H``: changeset hash (40 hexadecimal digits)
2545 :``%N``: number of patches being generated
2546 :``%N``: number of patches being generated
2546 :``%R``: changeset revision number
2547 :``%R``: changeset revision number
2547 :``%b``: basename of the exporting repository
2548 :``%b``: basename of the exporting repository
2548 :``%h``: short-form changeset hash (12 hexadecimal digits)
2549 :``%h``: short-form changeset hash (12 hexadecimal digits)
2549 :``%m``: first line of the commit message (only alphanumeric characters)
2550 :``%m``: first line of the commit message (only alphanumeric characters)
2550 :``%n``: zero-padded sequence number, starting at 1
2551 :``%n``: zero-padded sequence number, starting at 1
2551 :``%r``: zero-padded changeset revision number
2552 :``%r``: zero-padded changeset revision number
2552
2553
2553 Without the -a/--text option, export will avoid generating diffs
2554 Without the -a/--text option, export will avoid generating diffs
2554 of files it detects as binary. With -a, export will generate a
2555 of files it detects as binary. With -a, export will generate a
2555 diff anyway, probably with undesirable results.
2556 diff anyway, probably with undesirable results.
2556
2557
2557 Use the -g/--git option to generate diffs in the git extended diff
2558 Use the -g/--git option to generate diffs in the git extended diff
2558 format. See :hg:`help diffs` for more information.
2559 format. See :hg:`help diffs` for more information.
2559
2560
2560 With the --switch-parent option, the diff will be against the
2561 With the --switch-parent option, the diff will be against the
2561 second parent. It can be useful to review a merge.
2562 second parent. It can be useful to review a merge.
2562
2563
2563 .. container:: verbose
2564 .. container:: verbose
2564
2565
2565 Examples:
2566 Examples:
2566
2567
2567 - use export and import to transplant a bugfix to the current
2568 - use export and import to transplant a bugfix to the current
2568 branch::
2569 branch::
2569
2570
2570 hg export -r 9353 | hg import -
2571 hg export -r 9353 | hg import -
2571
2572
2572 - export all the changesets between two revisions to a file with
2573 - export all the changesets between two revisions to a file with
2573 rename information::
2574 rename information::
2574
2575
2575 hg export --git -r 123:150 > changes.txt
2576 hg export --git -r 123:150 > changes.txt
2576
2577
2577 - split outgoing changes into a series of patches with
2578 - split outgoing changes into a series of patches with
2578 descriptive names::
2579 descriptive names::
2579
2580
2580 hg export -r "outgoing()" -o "%n-%m.patch"
2581 hg export -r "outgoing()" -o "%n-%m.patch"
2581
2582
2582 Returns 0 on success.
2583 Returns 0 on success.
2583 """
2584 """
2584 changesets += tuple(opts.get('rev', []))
2585 changesets += tuple(opts.get('rev', []))
2585 revs = scmutil.revrange(repo, changesets)
2586 revs = scmutil.revrange(repo, changesets)
2586 if not revs:
2587 if not revs:
2587 raise util.Abort(_("export requires at least one changeset"))
2588 raise util.Abort(_("export requires at least one changeset"))
2588 if len(revs) > 1:
2589 if len(revs) > 1:
2589 ui.note(_('exporting patches:\n'))
2590 ui.note(_('exporting patches:\n'))
2590 else:
2591 else:
2591 ui.note(_('exporting patch:\n'))
2592 ui.note(_('exporting patch:\n'))
2592 cmdutil.export(repo, revs, template=opts.get('output'),
2593 cmdutil.export(repo, revs, template=opts.get('output'),
2593 switch_parent=opts.get('switch_parent'),
2594 switch_parent=opts.get('switch_parent'),
2594 opts=patch.diffopts(ui, opts))
2595 opts=patch.diffopts(ui, opts))
2595
2596
2596 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2597 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2597 def forget(ui, repo, *pats, **opts):
2598 def forget(ui, repo, *pats, **opts):
2598 """forget the specified files on the next commit
2599 """forget the specified files on the next commit
2599
2600
2600 Mark the specified files so they will no longer be tracked
2601 Mark the specified files so they will no longer be tracked
2601 after the next commit.
2602 after the next commit.
2602
2603
2603 This only removes files from the current branch, not from the
2604 This only removes files from the current branch, not from the
2604 entire project history, and it does not delete them from the
2605 entire project history, and it does not delete them from the
2605 working directory.
2606 working directory.
2606
2607
2607 To undo a forget before the next commit, see :hg:`add`.
2608 To undo a forget before the next commit, see :hg:`add`.
2608
2609
2609 .. container:: verbose
2610 .. container:: verbose
2610
2611
2611 Examples:
2612 Examples:
2612
2613
2613 - forget newly-added binary files::
2614 - forget newly-added binary files::
2614
2615
2615 hg forget "set:added() and binary()"
2616 hg forget "set:added() and binary()"
2616
2617
2617 - forget files that would be excluded by .hgignore::
2618 - forget files that would be excluded by .hgignore::
2618
2619
2619 hg forget "set:hgignore()"
2620 hg forget "set:hgignore()"
2620
2621
2621 Returns 0 on success.
2622 Returns 0 on success.
2622 """
2623 """
2623
2624
2624 if not pats:
2625 if not pats:
2625 raise util.Abort(_('no files specified'))
2626 raise util.Abort(_('no files specified'))
2626
2627
2627 m = scmutil.match(repo[None], pats, opts)
2628 m = scmutil.match(repo[None], pats, opts)
2628 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2629 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2629 return rejected and 1 or 0
2630 return rejected and 1 or 0
2630
2631
2631 @command(
2632 @command(
2632 'graft',
2633 'graft',
2633 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2634 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2634 ('c', 'continue', False, _('resume interrupted graft')),
2635 ('c', 'continue', False, _('resume interrupted graft')),
2635 ('e', 'edit', False, _('invoke editor on commit messages')),
2636 ('e', 'edit', False, _('invoke editor on commit messages')),
2636 ('', 'log', None, _('append graft info to log message')),
2637 ('', 'log', None, _('append graft info to log message')),
2637 ('D', 'currentdate', False,
2638 ('D', 'currentdate', False,
2638 _('record the current date as commit date')),
2639 _('record the current date as commit date')),
2639 ('U', 'currentuser', False,
2640 ('U', 'currentuser', False,
2640 _('record the current user as committer'), _('DATE'))]
2641 _('record the current user as committer'), _('DATE'))]
2641 + commitopts2 + mergetoolopts + dryrunopts,
2642 + commitopts2 + mergetoolopts + dryrunopts,
2642 _('[OPTION]... [-r] REV...'))
2643 _('[OPTION]... [-r] REV...'))
2643 def graft(ui, repo, *revs, **opts):
2644 def graft(ui, repo, *revs, **opts):
2644 '''copy changes from other branches onto the current branch
2645 '''copy changes from other branches onto the current branch
2645
2646
2646 This command uses Mercurial's merge logic to copy individual
2647 This command uses Mercurial's merge logic to copy individual
2647 changes from other branches without merging branches in the
2648 changes from other branches without merging branches in the
2648 history graph. This is sometimes known as 'backporting' or
2649 history graph. This is sometimes known as 'backporting' or
2649 'cherry-picking'. By default, graft will copy user, date, and
2650 'cherry-picking'. By default, graft will copy user, date, and
2650 description from the source changesets.
2651 description from the source changesets.
2651
2652
2652 Changesets that are ancestors of the current revision, that have
2653 Changesets that are ancestors of the current revision, that have
2653 already been grafted, or that are merges will be skipped.
2654 already been grafted, or that are merges will be skipped.
2654
2655
2655 If --log is specified, log messages will have a comment appended
2656 If --log is specified, log messages will have a comment appended
2656 of the form::
2657 of the form::
2657
2658
2658 (grafted from CHANGESETHASH)
2659 (grafted from CHANGESETHASH)
2659
2660
2660 If a graft merge results in conflicts, the graft process is
2661 If a graft merge results in conflicts, the graft process is
2661 interrupted so that the current merge can be manually resolved.
2662 interrupted so that the current merge can be manually resolved.
2662 Once all conflicts are addressed, the graft process can be
2663 Once all conflicts are addressed, the graft process can be
2663 continued with the -c/--continue option.
2664 continued with the -c/--continue option.
2664
2665
2665 .. note::
2666 .. note::
2666 The -c/--continue option does not reapply earlier options.
2667 The -c/--continue option does not reapply earlier options.
2667
2668
2668 .. container:: verbose
2669 .. container:: verbose
2669
2670
2670 Examples:
2671 Examples:
2671
2672
2672 - copy a single change to the stable branch and edit its description::
2673 - copy a single change to the stable branch and edit its description::
2673
2674
2674 hg update stable
2675 hg update stable
2675 hg graft --edit 9393
2676 hg graft --edit 9393
2676
2677
2677 - graft a range of changesets with one exception, updating dates::
2678 - graft a range of changesets with one exception, updating dates::
2678
2679
2679 hg graft -D "2085::2093 and not 2091"
2680 hg graft -D "2085::2093 and not 2091"
2680
2681
2681 - continue a graft after resolving conflicts::
2682 - continue a graft after resolving conflicts::
2682
2683
2683 hg graft -c
2684 hg graft -c
2684
2685
2685 - show the source of a grafted changeset::
2686 - show the source of a grafted changeset::
2686
2687
2687 hg log --debug -r tip
2688 hg log --debug -r tip
2688
2689
2689 Returns 0 on successful completion.
2690 Returns 0 on successful completion.
2690 '''
2691 '''
2691
2692
2692 revs = list(revs)
2693 revs = list(revs)
2693 revs.extend(opts['rev'])
2694 revs.extend(opts['rev'])
2694
2695
2695 if not opts.get('user') and opts.get('currentuser'):
2696 if not opts.get('user') and opts.get('currentuser'):
2696 opts['user'] = ui.username()
2697 opts['user'] = ui.username()
2697 if not opts.get('date') and opts.get('currentdate'):
2698 if not opts.get('date') and opts.get('currentdate'):
2698 opts['date'] = "%d %d" % util.makedate()
2699 opts['date'] = "%d %d" % util.makedate()
2699
2700
2700 editor = None
2701 editor = None
2701 if opts.get('edit'):
2702 if opts.get('edit'):
2702 editor = cmdutil.commitforceeditor
2703 editor = cmdutil.commitforceeditor
2703
2704
2704 cont = False
2705 cont = False
2705 if opts['continue']:
2706 if opts['continue']:
2706 cont = True
2707 cont = True
2707 if revs:
2708 if revs:
2708 raise util.Abort(_("can't specify --continue and revisions"))
2709 raise util.Abort(_("can't specify --continue and revisions"))
2709 # read in unfinished revisions
2710 # read in unfinished revisions
2710 try:
2711 try:
2711 nodes = repo.opener.read('graftstate').splitlines()
2712 nodes = repo.opener.read('graftstate').splitlines()
2712 revs = [repo[node].rev() for node in nodes]
2713 revs = [repo[node].rev() for node in nodes]
2713 except IOError, inst:
2714 except IOError, inst:
2714 if inst.errno != errno.ENOENT:
2715 if inst.errno != errno.ENOENT:
2715 raise
2716 raise
2716 raise util.Abort(_("no graft state found, can't continue"))
2717 raise util.Abort(_("no graft state found, can't continue"))
2717 else:
2718 else:
2718 cmdutil.bailifchanged(repo)
2719 cmdutil.bailifchanged(repo)
2719 if not revs:
2720 if not revs:
2720 raise util.Abort(_('no revisions specified'))
2721 raise util.Abort(_('no revisions specified'))
2721 revs = scmutil.revrange(repo, revs)
2722 revs = scmutil.revrange(repo, revs)
2722
2723
2723 # check for merges
2724 # check for merges
2724 for rev in repo.revs('%ld and merge()', revs):
2725 for rev in repo.revs('%ld and merge()', revs):
2725 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2726 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2726 revs.remove(rev)
2727 revs.remove(rev)
2727 if not revs:
2728 if not revs:
2728 return -1
2729 return -1
2729
2730
2730 # check for ancestors of dest branch
2731 # check for ancestors of dest branch
2731 for rev in repo.revs('::. and %ld', revs):
2732 for rev in repo.revs('::. and %ld', revs):
2732 ui.warn(_('skipping ancestor revision %s\n') % rev)
2733 ui.warn(_('skipping ancestor revision %s\n') % rev)
2733 revs.remove(rev)
2734 revs.remove(rev)
2734 if not revs:
2735 if not revs:
2735 return -1
2736 return -1
2736
2737
2737 # analyze revs for earlier grafts
2738 # analyze revs for earlier grafts
2738 ids = {}
2739 ids = {}
2739 for ctx in repo.set("%ld", revs):
2740 for ctx in repo.set("%ld", revs):
2740 ids[ctx.hex()] = ctx.rev()
2741 ids[ctx.hex()] = ctx.rev()
2741 n = ctx.extra().get('source')
2742 n = ctx.extra().get('source')
2742 if n:
2743 if n:
2743 ids[n] = ctx.rev()
2744 ids[n] = ctx.rev()
2744
2745
2745 # check ancestors for earlier grafts
2746 # check ancestors for earlier grafts
2746 ui.debug('scanning for duplicate grafts\n')
2747 ui.debug('scanning for duplicate grafts\n')
2747 for ctx in repo.set("::. - ::%ld", revs):
2748 for ctx in repo.set("::. - ::%ld", revs):
2748 n = ctx.extra().get('source')
2749 n = ctx.extra().get('source')
2749 if n in ids:
2750 if n in ids:
2750 r = repo[n].rev()
2751 r = repo[n].rev()
2751 if r in revs:
2752 if r in revs:
2752 ui.warn(_('skipping already grafted revision %s\n') % r)
2753 ui.warn(_('skipping already grafted revision %s\n') % r)
2753 revs.remove(r)
2754 revs.remove(r)
2754 elif ids[n] in revs:
2755 elif ids[n] in revs:
2755 ui.warn(_('skipping already grafted revision %s '
2756 ui.warn(_('skipping already grafted revision %s '
2756 '(same origin %d)\n') % (ids[n], r))
2757 '(same origin %d)\n') % (ids[n], r))
2757 revs.remove(ids[n])
2758 revs.remove(ids[n])
2758 elif ctx.hex() in ids:
2759 elif ctx.hex() in ids:
2759 r = ids[ctx.hex()]
2760 r = ids[ctx.hex()]
2760 ui.warn(_('skipping already grafted revision %s '
2761 ui.warn(_('skipping already grafted revision %s '
2761 '(was grafted from %d)\n') % (r, ctx.rev()))
2762 '(was grafted from %d)\n') % (r, ctx.rev()))
2762 revs.remove(r)
2763 revs.remove(r)
2763 if not revs:
2764 if not revs:
2764 return -1
2765 return -1
2765
2766
2766 wlock = repo.wlock()
2767 wlock = repo.wlock()
2767 try:
2768 try:
2768 for pos, ctx in enumerate(repo.set("%ld", revs)):
2769 for pos, ctx in enumerate(repo.set("%ld", revs)):
2769 current = repo['.']
2770 current = repo['.']
2770
2771
2771 ui.status(_('grafting revision %s\n') % ctx.rev())
2772 ui.status(_('grafting revision %s\n') % ctx.rev())
2772 if opts.get('dry_run'):
2773 if opts.get('dry_run'):
2773 continue
2774 continue
2774
2775
2775 # we don't merge the first commit when continuing
2776 # we don't merge the first commit when continuing
2776 if not cont:
2777 if not cont:
2777 # perform the graft merge with p1(rev) as 'ancestor'
2778 # perform the graft merge with p1(rev) as 'ancestor'
2778 try:
2779 try:
2779 # ui.forcemerge is an internal variable, do not document
2780 # ui.forcemerge is an internal variable, do not document
2780 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2781 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2781 stats = mergemod.update(repo, ctx.node(), True, True, False,
2782 stats = mergemod.update(repo, ctx.node(), True, True, False,
2782 ctx.p1().node())
2783 ctx.p1().node())
2783 finally:
2784 finally:
2784 repo.ui.setconfig('ui', 'forcemerge', '')
2785 repo.ui.setconfig('ui', 'forcemerge', '')
2785 # report any conflicts
2786 # report any conflicts
2786 if stats and stats[3] > 0:
2787 if stats and stats[3] > 0:
2787 # write out state for --continue
2788 # write out state for --continue
2788 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2789 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2789 repo.opener.write('graftstate', ''.join(nodelines))
2790 repo.opener.write('graftstate', ''.join(nodelines))
2790 raise util.Abort(
2791 raise util.Abort(
2791 _("unresolved conflicts, can't continue"),
2792 _("unresolved conflicts, can't continue"),
2792 hint=_('use hg resolve and hg graft --continue'))
2793 hint=_('use hg resolve and hg graft --continue'))
2793 else:
2794 else:
2794 cont = False
2795 cont = False
2795
2796
2796 # drop the second merge parent
2797 # drop the second merge parent
2797 repo.setparents(current.node(), nullid)
2798 repo.setparents(current.node(), nullid)
2798 repo.dirstate.write()
2799 repo.dirstate.write()
2799 # fix up dirstate for copies and renames
2800 # fix up dirstate for copies and renames
2800 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2801 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2801
2802
2802 # commit
2803 # commit
2803 source = ctx.extra().get('source')
2804 source = ctx.extra().get('source')
2804 if not source:
2805 if not source:
2805 source = ctx.hex()
2806 source = ctx.hex()
2806 extra = {'source': source}
2807 extra = {'source': source}
2807 user = ctx.user()
2808 user = ctx.user()
2808 if opts.get('user'):
2809 if opts.get('user'):
2809 user = opts['user']
2810 user = opts['user']
2810 date = ctx.date()
2811 date = ctx.date()
2811 if opts.get('date'):
2812 if opts.get('date'):
2812 date = opts['date']
2813 date = opts['date']
2813 message = ctx.description()
2814 message = ctx.description()
2814 if opts.get('log'):
2815 if opts.get('log'):
2815 message += '\n(grafted from %s)' % ctx.hex()
2816 message += '\n(grafted from %s)' % ctx.hex()
2816 node = repo.commit(text=message, user=user,
2817 node = repo.commit(text=message, user=user,
2817 date=date, extra=extra, editor=editor)
2818 date=date, extra=extra, editor=editor)
2818 if node is None:
2819 if node is None:
2819 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2820 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2820 finally:
2821 finally:
2821 wlock.release()
2822 wlock.release()
2822
2823
2823 # remove state when we complete successfully
2824 # remove state when we complete successfully
2824 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2825 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2825 util.unlinkpath(repo.join('graftstate'))
2826 util.unlinkpath(repo.join('graftstate'))
2826
2827
2827 return 0
2828 return 0
2828
2829
2829 @command('grep',
2830 @command('grep',
2830 [('0', 'print0', None, _('end fields with NUL')),
2831 [('0', 'print0', None, _('end fields with NUL')),
2831 ('', 'all', None, _('print all revisions that match')),
2832 ('', 'all', None, _('print all revisions that match')),
2832 ('a', 'text', None, _('treat all files as text')),
2833 ('a', 'text', None, _('treat all files as text')),
2833 ('f', 'follow', None,
2834 ('f', 'follow', None,
2834 _('follow changeset history,'
2835 _('follow changeset history,'
2835 ' or file history across copies and renames')),
2836 ' or file history across copies and renames')),
2836 ('i', 'ignore-case', None, _('ignore case when matching')),
2837 ('i', 'ignore-case', None, _('ignore case when matching')),
2837 ('l', 'files-with-matches', None,
2838 ('l', 'files-with-matches', None,
2838 _('print only filenames and revisions that match')),
2839 _('print only filenames and revisions that match')),
2839 ('n', 'line-number', None, _('print matching line numbers')),
2840 ('n', 'line-number', None, _('print matching line numbers')),
2840 ('r', 'rev', [],
2841 ('r', 'rev', [],
2841 _('only search files changed within revision range'), _('REV')),
2842 _('only search files changed within revision range'), _('REV')),
2842 ('u', 'user', None, _('list the author (long with -v)')),
2843 ('u', 'user', None, _('list the author (long with -v)')),
2843 ('d', 'date', None, _('list the date (short with -q)')),
2844 ('d', 'date', None, _('list the date (short with -q)')),
2844 ] + walkopts,
2845 ] + walkopts,
2845 _('[OPTION]... PATTERN [FILE]...'))
2846 _('[OPTION]... PATTERN [FILE]...'))
2846 def grep(ui, repo, pattern, *pats, **opts):
2847 def grep(ui, repo, pattern, *pats, **opts):
2847 """search for a pattern in specified files and revisions
2848 """search for a pattern in specified files and revisions
2848
2849
2849 Search revisions of files for a regular expression.
2850 Search revisions of files for a regular expression.
2850
2851
2851 This command behaves differently than Unix grep. It only accepts
2852 This command behaves differently than Unix grep. It only accepts
2852 Python/Perl regexps. It searches repository history, not the
2853 Python/Perl regexps. It searches repository history, not the
2853 working directory. It always prints the revision number in which a
2854 working directory. It always prints the revision number in which a
2854 match appears.
2855 match appears.
2855
2856
2856 By default, grep only prints output for the first revision of a
2857 By default, grep only prints output for the first revision of a
2857 file in which it finds a match. To get it to print every revision
2858 file in which it finds a match. To get it to print every revision
2858 that contains a change in match status ("-" for a match that
2859 that contains a change in match status ("-" for a match that
2859 becomes a non-match, or "+" for a non-match that becomes a match),
2860 becomes a non-match, or "+" for a non-match that becomes a match),
2860 use the --all flag.
2861 use the --all flag.
2861
2862
2862 Returns 0 if a match is found, 1 otherwise.
2863 Returns 0 if a match is found, 1 otherwise.
2863 """
2864 """
2864 reflags = re.M
2865 reflags = re.M
2865 if opts.get('ignore_case'):
2866 if opts.get('ignore_case'):
2866 reflags |= re.I
2867 reflags |= re.I
2867 try:
2868 try:
2868 regexp = re.compile(pattern, reflags)
2869 regexp = re.compile(pattern, reflags)
2869 except re.error, inst:
2870 except re.error, inst:
2870 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2871 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2871 return 1
2872 return 1
2872 sep, eol = ':', '\n'
2873 sep, eol = ':', '\n'
2873 if opts.get('print0'):
2874 if opts.get('print0'):
2874 sep = eol = '\0'
2875 sep = eol = '\0'
2875
2876
2876 getfile = util.lrucachefunc(repo.file)
2877 getfile = util.lrucachefunc(repo.file)
2877
2878
2878 def matchlines(body):
2879 def matchlines(body):
2879 begin = 0
2880 begin = 0
2880 linenum = 0
2881 linenum = 0
2881 while True:
2882 while True:
2882 match = regexp.search(body, begin)
2883 match = regexp.search(body, begin)
2883 if not match:
2884 if not match:
2884 break
2885 break
2885 mstart, mend = match.span()
2886 mstart, mend = match.span()
2886 linenum += body.count('\n', begin, mstart) + 1
2887 linenum += body.count('\n', begin, mstart) + 1
2887 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2888 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2888 begin = body.find('\n', mend) + 1 or len(body) + 1
2889 begin = body.find('\n', mend) + 1 or len(body) + 1
2889 lend = begin - 1
2890 lend = begin - 1
2890 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2891 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2891
2892
2892 class linestate(object):
2893 class linestate(object):
2893 def __init__(self, line, linenum, colstart, colend):
2894 def __init__(self, line, linenum, colstart, colend):
2894 self.line = line
2895 self.line = line
2895 self.linenum = linenum
2896 self.linenum = linenum
2896 self.colstart = colstart
2897 self.colstart = colstart
2897 self.colend = colend
2898 self.colend = colend
2898
2899
2899 def __hash__(self):
2900 def __hash__(self):
2900 return hash((self.linenum, self.line))
2901 return hash((self.linenum, self.line))
2901
2902
2902 def __eq__(self, other):
2903 def __eq__(self, other):
2903 return self.line == other.line
2904 return self.line == other.line
2904
2905
2905 matches = {}
2906 matches = {}
2906 copies = {}
2907 copies = {}
2907 def grepbody(fn, rev, body):
2908 def grepbody(fn, rev, body):
2908 matches[rev].setdefault(fn, [])
2909 matches[rev].setdefault(fn, [])
2909 m = matches[rev][fn]
2910 m = matches[rev][fn]
2910 for lnum, cstart, cend, line in matchlines(body):
2911 for lnum, cstart, cend, line in matchlines(body):
2911 s = linestate(line, lnum, cstart, cend)
2912 s = linestate(line, lnum, cstart, cend)
2912 m.append(s)
2913 m.append(s)
2913
2914
2914 def difflinestates(a, b):
2915 def difflinestates(a, b):
2915 sm = difflib.SequenceMatcher(None, a, b)
2916 sm = difflib.SequenceMatcher(None, a, b)
2916 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2917 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2917 if tag == 'insert':
2918 if tag == 'insert':
2918 for i in xrange(blo, bhi):
2919 for i in xrange(blo, bhi):
2919 yield ('+', b[i])
2920 yield ('+', b[i])
2920 elif tag == 'delete':
2921 elif tag == 'delete':
2921 for i in xrange(alo, ahi):
2922 for i in xrange(alo, ahi):
2922 yield ('-', a[i])
2923 yield ('-', a[i])
2923 elif tag == 'replace':
2924 elif tag == 'replace':
2924 for i in xrange(alo, ahi):
2925 for i in xrange(alo, ahi):
2925 yield ('-', a[i])
2926 yield ('-', a[i])
2926 for i in xrange(blo, bhi):
2927 for i in xrange(blo, bhi):
2927 yield ('+', b[i])
2928 yield ('+', b[i])
2928
2929
2929 def display(fn, ctx, pstates, states):
2930 def display(fn, ctx, pstates, states):
2930 rev = ctx.rev()
2931 rev = ctx.rev()
2931 datefunc = ui.quiet and util.shortdate or util.datestr
2932 datefunc = ui.quiet and util.shortdate or util.datestr
2932 found = False
2933 found = False
2933 filerevmatches = {}
2934 filerevmatches = {}
2934 def binary():
2935 def binary():
2935 flog = getfile(fn)
2936 flog = getfile(fn)
2936 return util.binary(flog.read(ctx.filenode(fn)))
2937 return util.binary(flog.read(ctx.filenode(fn)))
2937
2938
2938 if opts.get('all'):
2939 if opts.get('all'):
2939 iter = difflinestates(pstates, states)
2940 iter = difflinestates(pstates, states)
2940 else:
2941 else:
2941 iter = [('', l) for l in states]
2942 iter = [('', l) for l in states]
2942 for change, l in iter:
2943 for change, l in iter:
2943 cols = [fn, str(rev)]
2944 cols = [fn, str(rev)]
2944 before, match, after = None, None, None
2945 before, match, after = None, None, None
2945 if opts.get('line_number'):
2946 if opts.get('line_number'):
2946 cols.append(str(l.linenum))
2947 cols.append(str(l.linenum))
2947 if opts.get('all'):
2948 if opts.get('all'):
2948 cols.append(change)
2949 cols.append(change)
2949 if opts.get('user'):
2950 if opts.get('user'):
2950 cols.append(ui.shortuser(ctx.user()))
2951 cols.append(ui.shortuser(ctx.user()))
2951 if opts.get('date'):
2952 if opts.get('date'):
2952 cols.append(datefunc(ctx.date()))
2953 cols.append(datefunc(ctx.date()))
2953 if opts.get('files_with_matches'):
2954 if opts.get('files_with_matches'):
2954 c = (fn, rev)
2955 c = (fn, rev)
2955 if c in filerevmatches:
2956 if c in filerevmatches:
2956 continue
2957 continue
2957 filerevmatches[c] = 1
2958 filerevmatches[c] = 1
2958 else:
2959 else:
2959 before = l.line[:l.colstart]
2960 before = l.line[:l.colstart]
2960 match = l.line[l.colstart:l.colend]
2961 match = l.line[l.colstart:l.colend]
2961 after = l.line[l.colend:]
2962 after = l.line[l.colend:]
2962 ui.write(sep.join(cols))
2963 ui.write(sep.join(cols))
2963 if before is not None:
2964 if before is not None:
2964 if not opts.get('text') and binary():
2965 if not opts.get('text') and binary():
2965 ui.write(sep + " Binary file matches")
2966 ui.write(sep + " Binary file matches")
2966 else:
2967 else:
2967 ui.write(sep + before)
2968 ui.write(sep + before)
2968 ui.write(match, label='grep.match')
2969 ui.write(match, label='grep.match')
2969 ui.write(after)
2970 ui.write(after)
2970 ui.write(eol)
2971 ui.write(eol)
2971 found = True
2972 found = True
2972 return found
2973 return found
2973
2974
2974 skip = {}
2975 skip = {}
2975 revfiles = {}
2976 revfiles = {}
2976 matchfn = scmutil.match(repo[None], pats, opts)
2977 matchfn = scmutil.match(repo[None], pats, opts)
2977 found = False
2978 found = False
2978 follow = opts.get('follow')
2979 follow = opts.get('follow')
2979
2980
2980 def prep(ctx, fns):
2981 def prep(ctx, fns):
2981 rev = ctx.rev()
2982 rev = ctx.rev()
2982 pctx = ctx.p1()
2983 pctx = ctx.p1()
2983 parent = pctx.rev()
2984 parent = pctx.rev()
2984 matches.setdefault(rev, {})
2985 matches.setdefault(rev, {})
2985 matches.setdefault(parent, {})
2986 matches.setdefault(parent, {})
2986 files = revfiles.setdefault(rev, [])
2987 files = revfiles.setdefault(rev, [])
2987 for fn in fns:
2988 for fn in fns:
2988 flog = getfile(fn)
2989 flog = getfile(fn)
2989 try:
2990 try:
2990 fnode = ctx.filenode(fn)
2991 fnode = ctx.filenode(fn)
2991 except error.LookupError:
2992 except error.LookupError:
2992 continue
2993 continue
2993
2994
2994 copied = flog.renamed(fnode)
2995 copied = flog.renamed(fnode)
2995 copy = follow and copied and copied[0]
2996 copy = follow and copied and copied[0]
2996 if copy:
2997 if copy:
2997 copies.setdefault(rev, {})[fn] = copy
2998 copies.setdefault(rev, {})[fn] = copy
2998 if fn in skip:
2999 if fn in skip:
2999 if copy:
3000 if copy:
3000 skip[copy] = True
3001 skip[copy] = True
3001 continue
3002 continue
3002 files.append(fn)
3003 files.append(fn)
3003
3004
3004 if fn not in matches[rev]:
3005 if fn not in matches[rev]:
3005 grepbody(fn, rev, flog.read(fnode))
3006 grepbody(fn, rev, flog.read(fnode))
3006
3007
3007 pfn = copy or fn
3008 pfn = copy or fn
3008 if pfn not in matches[parent]:
3009 if pfn not in matches[parent]:
3009 try:
3010 try:
3010 fnode = pctx.filenode(pfn)
3011 fnode = pctx.filenode(pfn)
3011 grepbody(pfn, parent, flog.read(fnode))
3012 grepbody(pfn, parent, flog.read(fnode))
3012 except error.LookupError:
3013 except error.LookupError:
3013 pass
3014 pass
3014
3015
3015 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3016 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3016 rev = ctx.rev()
3017 rev = ctx.rev()
3017 parent = ctx.p1().rev()
3018 parent = ctx.p1().rev()
3018 for fn in sorted(revfiles.get(rev, [])):
3019 for fn in sorted(revfiles.get(rev, [])):
3019 states = matches[rev][fn]
3020 states = matches[rev][fn]
3020 copy = copies.get(rev, {}).get(fn)
3021 copy = copies.get(rev, {}).get(fn)
3021 if fn in skip:
3022 if fn in skip:
3022 if copy:
3023 if copy:
3023 skip[copy] = True
3024 skip[copy] = True
3024 continue
3025 continue
3025 pstates = matches.get(parent, {}).get(copy or fn, [])
3026 pstates = matches.get(parent, {}).get(copy or fn, [])
3026 if pstates or states:
3027 if pstates or states:
3027 r = display(fn, ctx, pstates, states)
3028 r = display(fn, ctx, pstates, states)
3028 found = found or r
3029 found = found or r
3029 if r and not opts.get('all'):
3030 if r and not opts.get('all'):
3030 skip[fn] = True
3031 skip[fn] = True
3031 if copy:
3032 if copy:
3032 skip[copy] = True
3033 skip[copy] = True
3033 del matches[rev]
3034 del matches[rev]
3034 del revfiles[rev]
3035 del revfiles[rev]
3035
3036
3036 return not found
3037 return not found
3037
3038
3038 @command('heads',
3039 @command('heads',
3039 [('r', 'rev', '',
3040 [('r', 'rev', '',
3040 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3041 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3041 ('t', 'topo', False, _('show topological heads only')),
3042 ('t', 'topo', False, _('show topological heads only')),
3042 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3043 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3043 ('c', 'closed', False, _('show normal and closed branch heads')),
3044 ('c', 'closed', False, _('show normal and closed branch heads')),
3044 ] + templateopts,
3045 ] + templateopts,
3045 _('[-ct] [-r STARTREV] [REV]...'))
3046 _('[-ct] [-r STARTREV] [REV]...'))
3046 def heads(ui, repo, *branchrevs, **opts):
3047 def heads(ui, repo, *branchrevs, **opts):
3047 """show current repository heads or show branch heads
3048 """show current repository heads or show branch heads
3048
3049
3049 With no arguments, show all repository branch heads.
3050 With no arguments, show all repository branch heads.
3050
3051
3051 Repository "heads" are changesets with no child changesets. They are
3052 Repository "heads" are changesets with no child changesets. They are
3052 where development generally takes place and are the usual targets
3053 where development generally takes place and are the usual targets
3053 for update and merge operations. Branch heads are changesets that have
3054 for update and merge operations. Branch heads are changesets that have
3054 no child changeset on the same branch.
3055 no child changeset on the same branch.
3055
3056
3056 If one or more REVs are given, only branch heads on the branches
3057 If one or more REVs are given, only branch heads on the branches
3057 associated with the specified changesets are shown. This means
3058 associated with the specified changesets are shown. This means
3058 that you can use :hg:`heads foo` to see the heads on a branch
3059 that you can use :hg:`heads foo` to see the heads on a branch
3059 named ``foo``.
3060 named ``foo``.
3060
3061
3061 If -c/--closed is specified, also show branch heads marked closed
3062 If -c/--closed is specified, also show branch heads marked closed
3062 (see :hg:`commit --close-branch`).
3063 (see :hg:`commit --close-branch`).
3063
3064
3064 If STARTREV is specified, only those heads that are descendants of
3065 If STARTREV is specified, only those heads that are descendants of
3065 STARTREV will be displayed.
3066 STARTREV will be displayed.
3066
3067
3067 If -t/--topo is specified, named branch mechanics will be ignored and only
3068 If -t/--topo is specified, named branch mechanics will be ignored and only
3068 changesets without children will be shown.
3069 changesets without children will be shown.
3069
3070
3070 Returns 0 if matching heads are found, 1 if not.
3071 Returns 0 if matching heads are found, 1 if not.
3071 """
3072 """
3072
3073
3073 start = None
3074 start = None
3074 if 'rev' in opts:
3075 if 'rev' in opts:
3075 start = scmutil.revsingle(repo, opts['rev'], None).node()
3076 start = scmutil.revsingle(repo, opts['rev'], None).node()
3076
3077
3077 if opts.get('topo'):
3078 if opts.get('topo'):
3078 heads = [repo[h] for h in repo.heads(start)]
3079 heads = [repo[h] for h in repo.heads(start)]
3079 else:
3080 else:
3080 heads = []
3081 heads = []
3081 for branch in repo.branchmap():
3082 for branch in repo.branchmap():
3082 heads += repo.branchheads(branch, start, opts.get('closed'))
3083 heads += repo.branchheads(branch, start, opts.get('closed'))
3083 heads = [repo[h] for h in heads]
3084 heads = [repo[h] for h in heads]
3084
3085
3085 if branchrevs:
3086 if branchrevs:
3086 branches = set(repo[br].branch() for br in branchrevs)
3087 branches = set(repo[br].branch() for br in branchrevs)
3087 heads = [h for h in heads if h.branch() in branches]
3088 heads = [h for h in heads if h.branch() in branches]
3088
3089
3089 if opts.get('active') and branchrevs:
3090 if opts.get('active') and branchrevs:
3090 dagheads = repo.heads(start)
3091 dagheads = repo.heads(start)
3091 heads = [h for h in heads if h.node() in dagheads]
3092 heads = [h for h in heads if h.node() in dagheads]
3092
3093
3093 if branchrevs:
3094 if branchrevs:
3094 haveheads = set(h.branch() for h in heads)
3095 haveheads = set(h.branch() for h in heads)
3095 if branches - haveheads:
3096 if branches - haveheads:
3096 headless = ', '.join(b for b in branches - haveheads)
3097 headless = ', '.join(b for b in branches - haveheads)
3097 msg = _('no open branch heads found on branches %s')
3098 msg = _('no open branch heads found on branches %s')
3098 if opts.get('rev'):
3099 if opts.get('rev'):
3099 msg += _(' (started at %s)') % opts['rev']
3100 msg += _(' (started at %s)') % opts['rev']
3100 ui.warn((msg + '\n') % headless)
3101 ui.warn((msg + '\n') % headless)
3101
3102
3102 if not heads:
3103 if not heads:
3103 return 1
3104 return 1
3104
3105
3105 heads = sorted(heads, key=lambda x: -x.rev())
3106 heads = sorted(heads, key=lambda x: -x.rev())
3106 displayer = cmdutil.show_changeset(ui, repo, opts)
3107 displayer = cmdutil.show_changeset(ui, repo, opts)
3107 for ctx in heads:
3108 for ctx in heads:
3108 displayer.show(ctx)
3109 displayer.show(ctx)
3109 displayer.close()
3110 displayer.close()
3110
3111
3111 @command('help',
3112 @command('help',
3112 [('e', 'extension', None, _('show only help for extensions')),
3113 [('e', 'extension', None, _('show only help for extensions')),
3113 ('c', 'command', None, _('show only help for commands')),
3114 ('c', 'command', None, _('show only help for commands')),
3114 ('k', 'keyword', '', _('show topics matching keyword')),
3115 ('k', 'keyword', '', _('show topics matching keyword')),
3115 ],
3116 ],
3116 _('[-ec] [TOPIC]'))
3117 _('[-ec] [TOPIC]'))
3117 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3118 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3118 """show help for a given topic or a help overview
3119 """show help for a given topic or a help overview
3119
3120
3120 With no arguments, print a list of commands with short help messages.
3121 With no arguments, print a list of commands with short help messages.
3121
3122
3122 Given a topic, extension, or command name, print help for that
3123 Given a topic, extension, or command name, print help for that
3123 topic.
3124 topic.
3124
3125
3125 Returns 0 if successful.
3126 Returns 0 if successful.
3126 """
3127 """
3127
3128
3128 textwidth = min(ui.termwidth(), 80) - 2
3129 textwidth = min(ui.termwidth(), 80) - 2
3129
3130
3130 def helpcmd(name):
3131 def helpcmd(name):
3131 try:
3132 try:
3132 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3133 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3133 except error.AmbiguousCommand, inst:
3134 except error.AmbiguousCommand, inst:
3134 # py3k fix: except vars can't be used outside the scope of the
3135 # py3k fix: except vars can't be used outside the scope of the
3135 # except block, nor can be used inside a lambda. python issue4617
3136 # except block, nor can be used inside a lambda. python issue4617
3136 prefix = inst.args[0]
3137 prefix = inst.args[0]
3137 select = lambda c: c.lstrip('^').startswith(prefix)
3138 select = lambda c: c.lstrip('^').startswith(prefix)
3138 rst = helplist(select)
3139 rst = helplist(select)
3139 return rst
3140 return rst
3140
3141
3141 rst = []
3142 rst = []
3142
3143
3143 # check if it's an invalid alias and display its error if it is
3144 # check if it's an invalid alias and display its error if it is
3144 if getattr(entry[0], 'badalias', False):
3145 if getattr(entry[0], 'badalias', False):
3145 if not unknowncmd:
3146 if not unknowncmd:
3146 ui.pushbuffer()
3147 ui.pushbuffer()
3147 entry[0](ui)
3148 entry[0](ui)
3148 rst.append(ui.popbuffer())
3149 rst.append(ui.popbuffer())
3149 return rst
3150 return rst
3150
3151
3151 # synopsis
3152 # synopsis
3152 if len(entry) > 2:
3153 if len(entry) > 2:
3153 if entry[2].startswith('hg'):
3154 if entry[2].startswith('hg'):
3154 rst.append("%s\n" % entry[2])
3155 rst.append("%s\n" % entry[2])
3155 else:
3156 else:
3156 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3157 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3157 else:
3158 else:
3158 rst.append('hg %s\n' % aliases[0])
3159 rst.append('hg %s\n' % aliases[0])
3159 # aliases
3160 # aliases
3160 if full and not ui.quiet and len(aliases) > 1:
3161 if full and not ui.quiet and len(aliases) > 1:
3161 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3162 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3162 rst.append('\n')
3163 rst.append('\n')
3163
3164
3164 # description
3165 # description
3165 doc = gettext(entry[0].__doc__)
3166 doc = gettext(entry[0].__doc__)
3166 if not doc:
3167 if not doc:
3167 doc = _("(no help text available)")
3168 doc = _("(no help text available)")
3168 if util.safehasattr(entry[0], 'definition'): # aliased command
3169 if util.safehasattr(entry[0], 'definition'): # aliased command
3169 if entry[0].definition.startswith('!'): # shell alias
3170 if entry[0].definition.startswith('!'): # shell alias
3170 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3171 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3171 else:
3172 else:
3172 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3173 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3173 doc = doc.splitlines(True)
3174 doc = doc.splitlines(True)
3174 if ui.quiet or not full:
3175 if ui.quiet or not full:
3175 rst.append(doc[0])
3176 rst.append(doc[0])
3176 else:
3177 else:
3177 rst.extend(doc)
3178 rst.extend(doc)
3178 rst.append('\n')
3179 rst.append('\n')
3179
3180
3180 # check if this command shadows a non-trivial (multi-line)
3181 # check if this command shadows a non-trivial (multi-line)
3181 # extension help text
3182 # extension help text
3182 try:
3183 try:
3183 mod = extensions.find(name)
3184 mod = extensions.find(name)
3184 doc = gettext(mod.__doc__) or ''
3185 doc = gettext(mod.__doc__) or ''
3185 if '\n' in doc.strip():
3186 if '\n' in doc.strip():
3186 msg = _('use "hg help -e %s" to show help for '
3187 msg = _('use "hg help -e %s" to show help for '
3187 'the %s extension') % (name, name)
3188 'the %s extension') % (name, name)
3188 rst.append('\n%s\n' % msg)
3189 rst.append('\n%s\n' % msg)
3189 except KeyError:
3190 except KeyError:
3190 pass
3191 pass
3191
3192
3192 # options
3193 # options
3193 if not ui.quiet and entry[1]:
3194 if not ui.quiet and entry[1]:
3194 rst.append('\n%s\n\n' % _("options:"))
3195 rst.append('\n%s\n\n' % _("options:"))
3195 rst.append(help.optrst(entry[1], ui.verbose))
3196 rst.append(help.optrst(entry[1], ui.verbose))
3196
3197
3197 if ui.verbose:
3198 if ui.verbose:
3198 rst.append('\n%s\n\n' % _("global options:"))
3199 rst.append('\n%s\n\n' % _("global options:"))
3199 rst.append(help.optrst(globalopts, ui.verbose))
3200 rst.append(help.optrst(globalopts, ui.verbose))
3200
3201
3201 if not ui.verbose:
3202 if not ui.verbose:
3202 if not full:
3203 if not full:
3203 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3204 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3204 % name)
3205 % name)
3205 elif not ui.quiet:
3206 elif not ui.quiet:
3206 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3207 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3207 % name)
3208 % name)
3208 return rst
3209 return rst
3209
3210
3210
3211
3211 def helplist(select=None):
3212 def helplist(select=None):
3212 # list of commands
3213 # list of commands
3213 if name == "shortlist":
3214 if name == "shortlist":
3214 header = _('basic commands:\n\n')
3215 header = _('basic commands:\n\n')
3215 else:
3216 else:
3216 header = _('list of commands:\n\n')
3217 header = _('list of commands:\n\n')
3217
3218
3218 h = {}
3219 h = {}
3219 cmds = {}
3220 cmds = {}
3220 for c, e in table.iteritems():
3221 for c, e in table.iteritems():
3221 f = c.split("|", 1)[0]
3222 f = c.split("|", 1)[0]
3222 if select and not select(f):
3223 if select and not select(f):
3223 continue
3224 continue
3224 if (not select and name != 'shortlist' and
3225 if (not select and name != 'shortlist' and
3225 e[0].__module__ != __name__):
3226 e[0].__module__ != __name__):
3226 continue
3227 continue
3227 if name == "shortlist" and not f.startswith("^"):
3228 if name == "shortlist" and not f.startswith("^"):
3228 continue
3229 continue
3229 f = f.lstrip("^")
3230 f = f.lstrip("^")
3230 if not ui.debugflag and f.startswith("debug"):
3231 if not ui.debugflag and f.startswith("debug"):
3231 continue
3232 continue
3232 doc = e[0].__doc__
3233 doc = e[0].__doc__
3233 if doc and 'DEPRECATED' in doc and not ui.verbose:
3234 if doc and 'DEPRECATED' in doc and not ui.verbose:
3234 continue
3235 continue
3235 doc = gettext(doc)
3236 doc = gettext(doc)
3236 if not doc:
3237 if not doc:
3237 doc = _("(no help text available)")
3238 doc = _("(no help text available)")
3238 h[f] = doc.splitlines()[0].rstrip()
3239 h[f] = doc.splitlines()[0].rstrip()
3239 cmds[f] = c.lstrip("^")
3240 cmds[f] = c.lstrip("^")
3240
3241
3241 rst = []
3242 rst = []
3242 if not h:
3243 if not h:
3243 if not ui.quiet:
3244 if not ui.quiet:
3244 rst.append(_('no commands defined\n'))
3245 rst.append(_('no commands defined\n'))
3245 return rst
3246 return rst
3246
3247
3247 if not ui.quiet:
3248 if not ui.quiet:
3248 rst.append(header)
3249 rst.append(header)
3249 fns = sorted(h)
3250 fns = sorted(h)
3250 for f in fns:
3251 for f in fns:
3251 if ui.verbose:
3252 if ui.verbose:
3252 commands = cmds[f].replace("|",", ")
3253 commands = cmds[f].replace("|",", ")
3253 rst.append(" :%s: %s\n" % (commands, h[f]))
3254 rst.append(" :%s: %s\n" % (commands, h[f]))
3254 else:
3255 else:
3255 rst.append(' :%s: %s\n' % (f, h[f]))
3256 rst.append(' :%s: %s\n' % (f, h[f]))
3256
3257
3257 if not name:
3258 if not name:
3258 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3259 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3259 if exts:
3260 if exts:
3260 rst.append('\n')
3261 rst.append('\n')
3261 rst.extend(exts)
3262 rst.extend(exts)
3262
3263
3263 rst.append(_("\nadditional help topics:\n\n"))
3264 rst.append(_("\nadditional help topics:\n\n"))
3264 topics = []
3265 topics = []
3265 for names, header, doc in help.helptable:
3266 for names, header, doc in help.helptable:
3266 topics.append((sorted(names, key=len, reverse=True)[0], header))
3267 topics.append((sorted(names, key=len, reverse=True)[0], header))
3267 for t, desc in topics:
3268 for t, desc in topics:
3268 rst.append(" :%s: %s\n" % (t, desc))
3269 rst.append(" :%s: %s\n" % (t, desc))
3269
3270
3270 optlist = []
3271 optlist = []
3271 if not ui.quiet:
3272 if not ui.quiet:
3272 if ui.verbose:
3273 if ui.verbose:
3273 optlist.append((_("global options:"), globalopts))
3274 optlist.append((_("global options:"), globalopts))
3274 if name == 'shortlist':
3275 if name == 'shortlist':
3275 optlist.append((_('use "hg help" for the full list '
3276 optlist.append((_('use "hg help" for the full list '
3276 'of commands'), ()))
3277 'of commands'), ()))
3277 else:
3278 else:
3278 if name == 'shortlist':
3279 if name == 'shortlist':
3279 msg = _('use "hg help" for the full list of commands '
3280 msg = _('use "hg help" for the full list of commands '
3280 'or "hg -v" for details')
3281 'or "hg -v" for details')
3281 elif name and not full:
3282 elif name and not full:
3282 msg = _('use "hg help %s" to show the full help '
3283 msg = _('use "hg help %s" to show the full help '
3283 'text') % name
3284 'text') % name
3284 else:
3285 else:
3285 msg = _('use "hg -v help%s" to show builtin aliases and '
3286 msg = _('use "hg -v help%s" to show builtin aliases and '
3286 'global options') % (name and " " + name or "")
3287 'global options') % (name and " " + name or "")
3287 optlist.append((msg, ()))
3288 optlist.append((msg, ()))
3288
3289
3289 if optlist:
3290 if optlist:
3290 for title, options in optlist:
3291 for title, options in optlist:
3291 rst.append('\n%s\n' % title)
3292 rst.append('\n%s\n' % title)
3292 if options:
3293 if options:
3293 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3294 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3294 return rst
3295 return rst
3295
3296
3296 def helptopic(name):
3297 def helptopic(name):
3297 for names, header, doc in help.helptable:
3298 for names, header, doc in help.helptable:
3298 if name in names:
3299 if name in names:
3299 break
3300 break
3300 else:
3301 else:
3301 raise error.UnknownCommand(name)
3302 raise error.UnknownCommand(name)
3302
3303
3303 rst = ["%s\n\n" % header]
3304 rst = ["%s\n\n" % header]
3304 # description
3305 # description
3305 if not doc:
3306 if not doc:
3306 rst.append(" %s\n" % _("(no help text available)"))
3307 rst.append(" %s\n" % _("(no help text available)"))
3307 if util.safehasattr(doc, '__call__'):
3308 if util.safehasattr(doc, '__call__'):
3308 rst += [" %s\n" % l for l in doc().splitlines()]
3309 rst += [" %s\n" % l for l in doc().splitlines()]
3309
3310
3310 try:
3311 try:
3311 cmdutil.findcmd(name, table)
3312 cmdutil.findcmd(name, table)
3312 rst.append(_('\nuse "hg help -c %s" to see help for '
3313 rst.append(_('\nuse "hg help -c %s" to see help for '
3313 'the %s command\n') % (name, name))
3314 'the %s command\n') % (name, name))
3314 except error.UnknownCommand:
3315 except error.UnknownCommand:
3315 pass
3316 pass
3316 return rst
3317 return rst
3317
3318
3318 def helpext(name):
3319 def helpext(name):
3319 try:
3320 try:
3320 mod = extensions.find(name)
3321 mod = extensions.find(name)
3321 doc = gettext(mod.__doc__) or _('no help text available')
3322 doc = gettext(mod.__doc__) or _('no help text available')
3322 except KeyError:
3323 except KeyError:
3323 mod = None
3324 mod = None
3324 doc = extensions.disabledext(name)
3325 doc = extensions.disabledext(name)
3325 if not doc:
3326 if not doc:
3326 raise error.UnknownCommand(name)
3327 raise error.UnknownCommand(name)
3327
3328
3328 if '\n' not in doc:
3329 if '\n' not in doc:
3329 head, tail = doc, ""
3330 head, tail = doc, ""
3330 else:
3331 else:
3331 head, tail = doc.split('\n', 1)
3332 head, tail = doc.split('\n', 1)
3332 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3333 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3333 if tail:
3334 if tail:
3334 rst.extend(tail.splitlines(True))
3335 rst.extend(tail.splitlines(True))
3335 rst.append('\n')
3336 rst.append('\n')
3336
3337
3337 if mod:
3338 if mod:
3338 try:
3339 try:
3339 ct = mod.cmdtable
3340 ct = mod.cmdtable
3340 except AttributeError:
3341 except AttributeError:
3341 ct = {}
3342 ct = {}
3342 modcmds = set([c.split('|', 1)[0] for c in ct])
3343 modcmds = set([c.split('|', 1)[0] for c in ct])
3343 rst.extend(helplist(modcmds.__contains__))
3344 rst.extend(helplist(modcmds.__contains__))
3344 else:
3345 else:
3345 rst.append(_('use "hg help extensions" for information on enabling '
3346 rst.append(_('use "hg help extensions" for information on enabling '
3346 'extensions\n'))
3347 'extensions\n'))
3347 return rst
3348 return rst
3348
3349
3349 def helpextcmd(name):
3350 def helpextcmd(name):
3350 cmd, ext, mod = extensions.disabledcmd(ui, name,
3351 cmd, ext, mod = extensions.disabledcmd(ui, name,
3351 ui.configbool('ui', 'strict'))
3352 ui.configbool('ui', 'strict'))
3352 doc = gettext(mod.__doc__).splitlines()[0]
3353 doc = gettext(mod.__doc__).splitlines()[0]
3353
3354
3354 rst = help.listexts(_("'%s' is provided by the following "
3355 rst = help.listexts(_("'%s' is provided by the following "
3355 "extension:") % cmd, {ext: doc}, indent=4)
3356 "extension:") % cmd, {ext: doc}, indent=4)
3356 rst.append('\n')
3357 rst.append('\n')
3357 rst.append(_('use "hg help extensions" for information on enabling '
3358 rst.append(_('use "hg help extensions" for information on enabling '
3358 'extensions\n'))
3359 'extensions\n'))
3359 return rst
3360 return rst
3360
3361
3361
3362
3362 rst = []
3363 rst = []
3363 kw = opts.get('keyword')
3364 kw = opts.get('keyword')
3364 if kw:
3365 if kw:
3365 matches = help.topicmatch(kw)
3366 matches = help.topicmatch(kw)
3366 for t, title in (('topics', _('Topics')),
3367 for t, title in (('topics', _('Topics')),
3367 ('commands', _('Commands')),
3368 ('commands', _('Commands')),
3368 ('extensions', _('Extensions')),
3369 ('extensions', _('Extensions')),
3369 ('extensioncommands', _('Extension Commands'))):
3370 ('extensioncommands', _('Extension Commands'))):
3370 if matches[t]:
3371 if matches[t]:
3371 rst.append('%s:\n\n' % title)
3372 rst.append('%s:\n\n' % title)
3372 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3373 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3373 rst.append('\n')
3374 rst.append('\n')
3374 elif name and name != 'shortlist':
3375 elif name and name != 'shortlist':
3375 i = None
3376 i = None
3376 if unknowncmd:
3377 if unknowncmd:
3377 queries = (helpextcmd,)
3378 queries = (helpextcmd,)
3378 elif opts.get('extension'):
3379 elif opts.get('extension'):
3379 queries = (helpext,)
3380 queries = (helpext,)
3380 elif opts.get('command'):
3381 elif opts.get('command'):
3381 queries = (helpcmd,)
3382 queries = (helpcmd,)
3382 else:
3383 else:
3383 queries = (helptopic, helpcmd, helpext, helpextcmd)
3384 queries = (helptopic, helpcmd, helpext, helpextcmd)
3384 for f in queries:
3385 for f in queries:
3385 try:
3386 try:
3386 rst = f(name)
3387 rst = f(name)
3387 i = None
3388 i = None
3388 break
3389 break
3389 except error.UnknownCommand, inst:
3390 except error.UnknownCommand, inst:
3390 i = inst
3391 i = inst
3391 if i:
3392 if i:
3392 raise i
3393 raise i
3393 else:
3394 else:
3394 # program name
3395 # program name
3395 if not ui.quiet:
3396 if not ui.quiet:
3396 rst = [_("Mercurial Distributed SCM\n"), '\n']
3397 rst = [_("Mercurial Distributed SCM\n"), '\n']
3397 rst.extend(helplist())
3398 rst.extend(helplist())
3398
3399
3399 keep = ui.verbose and ['verbose'] or []
3400 keep = ui.verbose and ['verbose'] or []
3400 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3401 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3401 ui.write(formatted)
3402 ui.write(formatted)
3402
3403
3403
3404
3404 @command('identify|id',
3405 @command('identify|id',
3405 [('r', 'rev', '',
3406 [('r', 'rev', '',
3406 _('identify the specified revision'), _('REV')),
3407 _('identify the specified revision'), _('REV')),
3407 ('n', 'num', None, _('show local revision number')),
3408 ('n', 'num', None, _('show local revision number')),
3408 ('i', 'id', None, _('show global revision id')),
3409 ('i', 'id', None, _('show global revision id')),
3409 ('b', 'branch', None, _('show branch')),
3410 ('b', 'branch', None, _('show branch')),
3410 ('t', 'tags', None, _('show tags')),
3411 ('t', 'tags', None, _('show tags')),
3411 ('B', 'bookmarks', None, _('show bookmarks')),
3412 ('B', 'bookmarks', None, _('show bookmarks')),
3412 ] + remoteopts,
3413 ] + remoteopts,
3413 _('[-nibtB] [-r REV] [SOURCE]'))
3414 _('[-nibtB] [-r REV] [SOURCE]'))
3414 def identify(ui, repo, source=None, rev=None,
3415 def identify(ui, repo, source=None, rev=None,
3415 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3416 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3416 """identify the working copy or specified revision
3417 """identify the working copy or specified revision
3417
3418
3418 Print a summary identifying the repository state at REV using one or
3419 Print a summary identifying the repository state at REV using one or
3419 two parent hash identifiers, followed by a "+" if the working
3420 two parent hash identifiers, followed by a "+" if the working
3420 directory has uncommitted changes, the branch name (if not default),
3421 directory has uncommitted changes, the branch name (if not default),
3421 a list of tags, and a list of bookmarks.
3422 a list of tags, and a list of bookmarks.
3422
3423
3423 When REV is not given, print a summary of the current state of the
3424 When REV is not given, print a summary of the current state of the
3424 repository.
3425 repository.
3425
3426
3426 Specifying a path to a repository root or Mercurial bundle will
3427 Specifying a path to a repository root or Mercurial bundle will
3427 cause lookup to operate on that repository/bundle.
3428 cause lookup to operate on that repository/bundle.
3428
3429
3429 .. container:: verbose
3430 .. container:: verbose
3430
3431
3431 Examples:
3432 Examples:
3432
3433
3433 - generate a build identifier for the working directory::
3434 - generate a build identifier for the working directory::
3434
3435
3435 hg id --id > build-id.dat
3436 hg id --id > build-id.dat
3436
3437
3437 - find the revision corresponding to a tag::
3438 - find the revision corresponding to a tag::
3438
3439
3439 hg id -n -r 1.3
3440 hg id -n -r 1.3
3440
3441
3441 - check the most recent revision of a remote repository::
3442 - check the most recent revision of a remote repository::
3442
3443
3443 hg id -r tip http://selenic.com/hg/
3444 hg id -r tip http://selenic.com/hg/
3444
3445
3445 Returns 0 if successful.
3446 Returns 0 if successful.
3446 """
3447 """
3447
3448
3448 if not repo and not source:
3449 if not repo and not source:
3449 raise util.Abort(_("there is no Mercurial repository here "
3450 raise util.Abort(_("there is no Mercurial repository here "
3450 "(.hg not found)"))
3451 "(.hg not found)"))
3451
3452
3452 hexfunc = ui.debugflag and hex or short
3453 hexfunc = ui.debugflag and hex or short
3453 default = not (num or id or branch or tags or bookmarks)
3454 default = not (num or id or branch or tags or bookmarks)
3454 output = []
3455 output = []
3455 revs = []
3456 revs = []
3456
3457
3457 if source:
3458 if source:
3458 source, branches = hg.parseurl(ui.expandpath(source))
3459 source, branches = hg.parseurl(ui.expandpath(source))
3459 repo = hg.peer(ui, opts, source)
3460 repo = hg.peer(ui, opts, source)
3460 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3461 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3461
3462
3462 if not repo.local():
3463 if not repo.local():
3463 if num or branch or tags:
3464 if num or branch or tags:
3464 raise util.Abort(
3465 raise util.Abort(
3465 _("can't query remote revision number, branch, or tags"))
3466 _("can't query remote revision number, branch, or tags"))
3466 if not rev and revs:
3467 if not rev and revs:
3467 rev = revs[0]
3468 rev = revs[0]
3468 if not rev:
3469 if not rev:
3469 rev = "tip"
3470 rev = "tip"
3470
3471
3471 remoterev = repo.lookup(rev)
3472 remoterev = repo.lookup(rev)
3472 if default or id:
3473 if default or id:
3473 output = [hexfunc(remoterev)]
3474 output = [hexfunc(remoterev)]
3474
3475
3475 def getbms():
3476 def getbms():
3476 bms = []
3477 bms = []
3477
3478
3478 if 'bookmarks' in repo.listkeys('namespaces'):
3479 if 'bookmarks' in repo.listkeys('namespaces'):
3479 hexremoterev = hex(remoterev)
3480 hexremoterev = hex(remoterev)
3480 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3481 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3481 if bmr == hexremoterev]
3482 if bmr == hexremoterev]
3482
3483
3483 return bms
3484 return bms
3484
3485
3485 if bookmarks:
3486 if bookmarks:
3486 output.extend(getbms())
3487 output.extend(getbms())
3487 elif default and not ui.quiet:
3488 elif default and not ui.quiet:
3488 # multiple bookmarks for a single parent separated by '/'
3489 # multiple bookmarks for a single parent separated by '/'
3489 bm = '/'.join(getbms())
3490 bm = '/'.join(getbms())
3490 if bm:
3491 if bm:
3491 output.append(bm)
3492 output.append(bm)
3492 else:
3493 else:
3493 if not rev:
3494 if not rev:
3494 ctx = repo[None]
3495 ctx = repo[None]
3495 parents = ctx.parents()
3496 parents = ctx.parents()
3496 changed = ""
3497 changed = ""
3497 if default or id or num:
3498 if default or id or num:
3498 changed = util.any(repo.status()) and "+" or ""
3499 changed = util.any(repo.status()) and "+" or ""
3499 if default or id:
3500 if default or id:
3500 output = ["%s%s" %
3501 output = ["%s%s" %
3501 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3502 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3502 if num:
3503 if num:
3503 output.append("%s%s" %
3504 output.append("%s%s" %
3504 ('+'.join([str(p.rev()) for p in parents]), changed))
3505 ('+'.join([str(p.rev()) for p in parents]), changed))
3505 else:
3506 else:
3506 ctx = scmutil.revsingle(repo, rev)
3507 ctx = scmutil.revsingle(repo, rev)
3507 if default or id:
3508 if default or id:
3508 output = [hexfunc(ctx.node())]
3509 output = [hexfunc(ctx.node())]
3509 if num:
3510 if num:
3510 output.append(str(ctx.rev()))
3511 output.append(str(ctx.rev()))
3511
3512
3512 if default and not ui.quiet:
3513 if default and not ui.quiet:
3513 b = ctx.branch()
3514 b = ctx.branch()
3514 if b != 'default':
3515 if b != 'default':
3515 output.append("(%s)" % b)
3516 output.append("(%s)" % b)
3516
3517
3517 # multiple tags for a single parent separated by '/'
3518 # multiple tags for a single parent separated by '/'
3518 t = '/'.join(ctx.tags())
3519 t = '/'.join(ctx.tags())
3519 if t:
3520 if t:
3520 output.append(t)
3521 output.append(t)
3521
3522
3522 # multiple bookmarks for a single parent separated by '/'
3523 # multiple bookmarks for a single parent separated by '/'
3523 bm = '/'.join(ctx.bookmarks())
3524 bm = '/'.join(ctx.bookmarks())
3524 if bm:
3525 if bm:
3525 output.append(bm)
3526 output.append(bm)
3526 else:
3527 else:
3527 if branch:
3528 if branch:
3528 output.append(ctx.branch())
3529 output.append(ctx.branch())
3529
3530
3530 if tags:
3531 if tags:
3531 output.extend(ctx.tags())
3532 output.extend(ctx.tags())
3532
3533
3533 if bookmarks:
3534 if bookmarks:
3534 output.extend(ctx.bookmarks())
3535 output.extend(ctx.bookmarks())
3535
3536
3536 ui.write("%s\n" % ' '.join(output))
3537 ui.write("%s\n" % ' '.join(output))
3537
3538
3538 @command('import|patch',
3539 @command('import|patch',
3539 [('p', 'strip', 1,
3540 [('p', 'strip', 1,
3540 _('directory strip option for patch. This has the same '
3541 _('directory strip option for patch. This has the same '
3541 'meaning as the corresponding patch option'), _('NUM')),
3542 'meaning as the corresponding patch option'), _('NUM')),
3542 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3543 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3543 ('e', 'edit', False, _('invoke editor on commit messages')),
3544 ('e', 'edit', False, _('invoke editor on commit messages')),
3544 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3545 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3545 ('', 'no-commit', None,
3546 ('', 'no-commit', None,
3546 _("don't commit, just update the working directory")),
3547 _("don't commit, just update the working directory")),
3547 ('', 'bypass', None,
3548 ('', 'bypass', None,
3548 _("apply patch without touching the working directory")),
3549 _("apply patch without touching the working directory")),
3549 ('', 'exact', None,
3550 ('', 'exact', None,
3550 _('apply patch to the nodes from which it was generated')),
3551 _('apply patch to the nodes from which it was generated')),
3551 ('', 'import-branch', None,
3552 ('', 'import-branch', None,
3552 _('use any branch information in patch (implied by --exact)'))] +
3553 _('use any branch information in patch (implied by --exact)'))] +
3553 commitopts + commitopts2 + similarityopts,
3554 commitopts + commitopts2 + similarityopts,
3554 _('[OPTION]... PATCH...'))
3555 _('[OPTION]... PATCH...'))
3555 def import_(ui, repo, patch1=None, *patches, **opts):
3556 def import_(ui, repo, patch1=None, *patches, **opts):
3556 """import an ordered set of patches
3557 """import an ordered set of patches
3557
3558
3558 Import a list of patches and commit them individually (unless
3559 Import a list of patches and commit them individually (unless
3559 --no-commit is specified).
3560 --no-commit is specified).
3560
3561
3561 If there are outstanding changes in the working directory, import
3562 If there are outstanding changes in the working directory, import
3562 will abort unless given the -f/--force flag.
3563 will abort unless given the -f/--force flag.
3563
3564
3564 You can import a patch straight from a mail message. Even patches
3565 You can import a patch straight from a mail message. Even patches
3565 as attachments work (to use the body part, it must have type
3566 as attachments work (to use the body part, it must have type
3566 text/plain or text/x-patch). From and Subject headers of email
3567 text/plain or text/x-patch). From and Subject headers of email
3567 message are used as default committer and commit message. All
3568 message are used as default committer and commit message. All
3568 text/plain body parts before first diff are added to commit
3569 text/plain body parts before first diff are added to commit
3569 message.
3570 message.
3570
3571
3571 If the imported patch was generated by :hg:`export`, user and
3572 If the imported patch was generated by :hg:`export`, user and
3572 description from patch override values from message headers and
3573 description from patch override values from message headers and
3573 body. Values given on command line with -m/--message and -u/--user
3574 body. Values given on command line with -m/--message and -u/--user
3574 override these.
3575 override these.
3575
3576
3576 If --exact is specified, import will set the working directory to
3577 If --exact is specified, import will set the working directory to
3577 the parent of each patch before applying it, and will abort if the
3578 the parent of each patch before applying it, and will abort if the
3578 resulting changeset has a different ID than the one recorded in
3579 resulting changeset has a different ID than the one recorded in
3579 the patch. This may happen due to character set problems or other
3580 the patch. This may happen due to character set problems or other
3580 deficiencies in the text patch format.
3581 deficiencies in the text patch format.
3581
3582
3582 Use --bypass to apply and commit patches directly to the
3583 Use --bypass to apply and commit patches directly to the
3583 repository, not touching the working directory. Without --exact,
3584 repository, not touching the working directory. Without --exact,
3584 patches will be applied on top of the working directory parent
3585 patches will be applied on top of the working directory parent
3585 revision.
3586 revision.
3586
3587
3587 With -s/--similarity, hg will attempt to discover renames and
3588 With -s/--similarity, hg will attempt to discover renames and
3588 copies in the patch in the same way as :hg:`addremove`.
3589 copies in the patch in the same way as :hg:`addremove`.
3589
3590
3590 To read a patch from standard input, use "-" as the patch name. If
3591 To read a patch from standard input, use "-" as the patch name. If
3591 a URL is specified, the patch will be downloaded from it.
3592 a URL is specified, the patch will be downloaded from it.
3592 See :hg:`help dates` for a list of formats valid for -d/--date.
3593 See :hg:`help dates` for a list of formats valid for -d/--date.
3593
3594
3594 .. container:: verbose
3595 .. container:: verbose
3595
3596
3596 Examples:
3597 Examples:
3597
3598
3598 - import a traditional patch from a website and detect renames::
3599 - import a traditional patch from a website and detect renames::
3599
3600
3600 hg import -s 80 http://example.com/bugfix.patch
3601 hg import -s 80 http://example.com/bugfix.patch
3601
3602
3602 - import a changeset from an hgweb server::
3603 - import a changeset from an hgweb server::
3603
3604
3604 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3605 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3605
3606
3606 - import all the patches in an Unix-style mbox::
3607 - import all the patches in an Unix-style mbox::
3607
3608
3608 hg import incoming-patches.mbox
3609 hg import incoming-patches.mbox
3609
3610
3610 - attempt to exactly restore an exported changeset (not always
3611 - attempt to exactly restore an exported changeset (not always
3611 possible)::
3612 possible)::
3612
3613
3613 hg import --exact proposed-fix.patch
3614 hg import --exact proposed-fix.patch
3614
3615
3615 Returns 0 on success.
3616 Returns 0 on success.
3616 """
3617 """
3617
3618
3618 if not patch1:
3619 if not patch1:
3619 raise util.Abort(_('need at least one patch to import'))
3620 raise util.Abort(_('need at least one patch to import'))
3620
3621
3621 patches = (patch1,) + patches
3622 patches = (patch1,) + patches
3622
3623
3623 date = opts.get('date')
3624 date = opts.get('date')
3624 if date:
3625 if date:
3625 opts['date'] = util.parsedate(date)
3626 opts['date'] = util.parsedate(date)
3626
3627
3627 editor = cmdutil.commiteditor
3628 editor = cmdutil.commiteditor
3628 if opts.get('edit'):
3629 if opts.get('edit'):
3629 editor = cmdutil.commitforceeditor
3630 editor = cmdutil.commitforceeditor
3630
3631
3631 update = not opts.get('bypass')
3632 update = not opts.get('bypass')
3632 if not update and opts.get('no_commit'):
3633 if not update and opts.get('no_commit'):
3633 raise util.Abort(_('cannot use --no-commit with --bypass'))
3634 raise util.Abort(_('cannot use --no-commit with --bypass'))
3634 try:
3635 try:
3635 sim = float(opts.get('similarity') or 0)
3636 sim = float(opts.get('similarity') or 0)
3636 except ValueError:
3637 except ValueError:
3637 raise util.Abort(_('similarity must be a number'))
3638 raise util.Abort(_('similarity must be a number'))
3638 if sim < 0 or sim > 100:
3639 if sim < 0 or sim > 100:
3639 raise util.Abort(_('similarity must be between 0 and 100'))
3640 raise util.Abort(_('similarity must be between 0 and 100'))
3640 if sim and not update:
3641 if sim and not update:
3641 raise util.Abort(_('cannot use --similarity with --bypass'))
3642 raise util.Abort(_('cannot use --similarity with --bypass'))
3642
3643
3643 if (opts.get('exact') or not opts.get('force')) and update:
3644 if (opts.get('exact') or not opts.get('force')) and update:
3644 cmdutil.bailifchanged(repo)
3645 cmdutil.bailifchanged(repo)
3645
3646
3646 base = opts["base"]
3647 base = opts["base"]
3647 strip = opts["strip"]
3648 strip = opts["strip"]
3648 wlock = lock = tr = None
3649 wlock = lock = tr = None
3649 msgs = []
3650 msgs = []
3650
3651
3651 def checkexact(repo, n, nodeid):
3652 def checkexact(repo, n, nodeid):
3652 if opts.get('exact') and hex(n) != nodeid:
3653 if opts.get('exact') and hex(n) != nodeid:
3653 repo.rollback()
3654 repo.rollback()
3654 raise util.Abort(_('patch is damaged or loses information'))
3655 raise util.Abort(_('patch is damaged or loses information'))
3655
3656
3656 def tryone(ui, hunk, parents):
3657 def tryone(ui, hunk, parents):
3657 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3658 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3658 patch.extract(ui, hunk)
3659 patch.extract(ui, hunk)
3659
3660
3660 if not tmpname:
3661 if not tmpname:
3661 return (None, None)
3662 return (None, None)
3662 msg = _('applied to working directory')
3663 msg = _('applied to working directory')
3663
3664
3664 try:
3665 try:
3665 cmdline_message = cmdutil.logmessage(ui, opts)
3666 cmdline_message = cmdutil.logmessage(ui, opts)
3666 if cmdline_message:
3667 if cmdline_message:
3667 # pickup the cmdline msg
3668 # pickup the cmdline msg
3668 message = cmdline_message
3669 message = cmdline_message
3669 elif message:
3670 elif message:
3670 # pickup the patch msg
3671 # pickup the patch msg
3671 message = message.strip()
3672 message = message.strip()
3672 else:
3673 else:
3673 # launch the editor
3674 # launch the editor
3674 message = None
3675 message = None
3675 ui.debug('message:\n%s\n' % message)
3676 ui.debug('message:\n%s\n' % message)
3676
3677
3677 if len(parents) == 1:
3678 if len(parents) == 1:
3678 parents.append(repo[nullid])
3679 parents.append(repo[nullid])
3679 if opts.get('exact'):
3680 if opts.get('exact'):
3680 if not nodeid or not p1:
3681 if not nodeid or not p1:
3681 raise util.Abort(_('not a Mercurial patch'))
3682 raise util.Abort(_('not a Mercurial patch'))
3682 p1 = repo[p1]
3683 p1 = repo[p1]
3683 p2 = repo[p2 or nullid]
3684 p2 = repo[p2 or nullid]
3684 elif p2:
3685 elif p2:
3685 try:
3686 try:
3686 p1 = repo[p1]
3687 p1 = repo[p1]
3687 p2 = repo[p2]
3688 p2 = repo[p2]
3688 # Without any options, consider p2 only if the
3689 # Without any options, consider p2 only if the
3689 # patch is being applied on top of the recorded
3690 # patch is being applied on top of the recorded
3690 # first parent.
3691 # first parent.
3691 if p1 != parents[0]:
3692 if p1 != parents[0]:
3692 p1 = parents[0]
3693 p1 = parents[0]
3693 p2 = repo[nullid]
3694 p2 = repo[nullid]
3694 except error.RepoError:
3695 except error.RepoError:
3695 p1, p2 = parents
3696 p1, p2 = parents
3696 else:
3697 else:
3697 p1, p2 = parents
3698 p1, p2 = parents
3698
3699
3699 n = None
3700 n = None
3700 if update:
3701 if update:
3701 if p1 != parents[0]:
3702 if p1 != parents[0]:
3702 hg.clean(repo, p1.node())
3703 hg.clean(repo, p1.node())
3703 if p2 != parents[1]:
3704 if p2 != parents[1]:
3704 repo.setparents(p1.node(), p2.node())
3705 repo.setparents(p1.node(), p2.node())
3705
3706
3706 if opts.get('exact') or opts.get('import_branch'):
3707 if opts.get('exact') or opts.get('import_branch'):
3707 repo.dirstate.setbranch(branch or 'default')
3708 repo.dirstate.setbranch(branch or 'default')
3708
3709
3709 files = set()
3710 files = set()
3710 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3711 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3711 eolmode=None, similarity=sim / 100.0)
3712 eolmode=None, similarity=sim / 100.0)
3712 files = list(files)
3713 files = list(files)
3713 if opts.get('no_commit'):
3714 if opts.get('no_commit'):
3714 if message:
3715 if message:
3715 msgs.append(message)
3716 msgs.append(message)
3716 else:
3717 else:
3717 if opts.get('exact') or p2:
3718 if opts.get('exact') or p2:
3718 # If you got here, you either use --force and know what
3719 # If you got here, you either use --force and know what
3719 # you are doing or used --exact or a merge patch while
3720 # you are doing or used --exact or a merge patch while
3720 # being updated to its first parent.
3721 # being updated to its first parent.
3721 m = None
3722 m = None
3722 else:
3723 else:
3723 m = scmutil.matchfiles(repo, files or [])
3724 m = scmutil.matchfiles(repo, files or [])
3724 n = repo.commit(message, opts.get('user') or user,
3725 n = repo.commit(message, opts.get('user') or user,
3725 opts.get('date') or date, match=m,
3726 opts.get('date') or date, match=m,
3726 editor=editor)
3727 editor=editor)
3727 checkexact(repo, n, nodeid)
3728 checkexact(repo, n, nodeid)
3728 else:
3729 else:
3729 if opts.get('exact') or opts.get('import_branch'):
3730 if opts.get('exact') or opts.get('import_branch'):
3730 branch = branch or 'default'
3731 branch = branch or 'default'
3731 else:
3732 else:
3732 branch = p1.branch()
3733 branch = p1.branch()
3733 store = patch.filestore()
3734 store = patch.filestore()
3734 try:
3735 try:
3735 files = set()
3736 files = set()
3736 try:
3737 try:
3737 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3738 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3738 files, eolmode=None)
3739 files, eolmode=None)
3739 except patch.PatchError, e:
3740 except patch.PatchError, e:
3740 raise util.Abort(str(e))
3741 raise util.Abort(str(e))
3741 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3742 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3742 message,
3743 message,
3743 opts.get('user') or user,
3744 opts.get('user') or user,
3744 opts.get('date') or date,
3745 opts.get('date') or date,
3745 branch, files, store,
3746 branch, files, store,
3746 editor=cmdutil.commiteditor)
3747 editor=cmdutil.commiteditor)
3747 repo.savecommitmessage(memctx.description())
3748 repo.savecommitmessage(memctx.description())
3748 n = memctx.commit()
3749 n = memctx.commit()
3749 checkexact(repo, n, nodeid)
3750 checkexact(repo, n, nodeid)
3750 finally:
3751 finally:
3751 store.close()
3752 store.close()
3752 if n:
3753 if n:
3753 # i18n: refers to a short changeset id
3754 # i18n: refers to a short changeset id
3754 msg = _('created %s') % short(n)
3755 msg = _('created %s') % short(n)
3755 return (msg, n)
3756 return (msg, n)
3756 finally:
3757 finally:
3757 os.unlink(tmpname)
3758 os.unlink(tmpname)
3758
3759
3759 try:
3760 try:
3760 try:
3761 try:
3761 wlock = repo.wlock()
3762 wlock = repo.wlock()
3762 if not opts.get('no_commit'):
3763 if not opts.get('no_commit'):
3763 lock = repo.lock()
3764 lock = repo.lock()
3764 tr = repo.transaction('import')
3765 tr = repo.transaction('import')
3765 parents = repo.parents()
3766 parents = repo.parents()
3766 for patchurl in patches:
3767 for patchurl in patches:
3767 if patchurl == '-':
3768 if patchurl == '-':
3768 ui.status(_('applying patch from stdin\n'))
3769 ui.status(_('applying patch from stdin\n'))
3769 patchfile = ui.fin
3770 patchfile = ui.fin
3770 patchurl = 'stdin' # for error message
3771 patchurl = 'stdin' # for error message
3771 else:
3772 else:
3772 patchurl = os.path.join(base, patchurl)
3773 patchurl = os.path.join(base, patchurl)
3773 ui.status(_('applying %s\n') % patchurl)
3774 ui.status(_('applying %s\n') % patchurl)
3774 patchfile = url.open(ui, patchurl)
3775 patchfile = url.open(ui, patchurl)
3775
3776
3776 haspatch = False
3777 haspatch = False
3777 for hunk in patch.split(patchfile):
3778 for hunk in patch.split(patchfile):
3778 (msg, node) = tryone(ui, hunk, parents)
3779 (msg, node) = tryone(ui, hunk, parents)
3779 if msg:
3780 if msg:
3780 haspatch = True
3781 haspatch = True
3781 ui.note(msg + '\n')
3782 ui.note(msg + '\n')
3782 if update or opts.get('exact'):
3783 if update or opts.get('exact'):
3783 parents = repo.parents()
3784 parents = repo.parents()
3784 else:
3785 else:
3785 parents = [repo[node]]
3786 parents = [repo[node]]
3786
3787
3787 if not haspatch:
3788 if not haspatch:
3788 raise util.Abort(_('%s: no diffs found') % patchurl)
3789 raise util.Abort(_('%s: no diffs found') % patchurl)
3789
3790
3790 if tr:
3791 if tr:
3791 tr.close()
3792 tr.close()
3792 if msgs:
3793 if msgs:
3793 repo.savecommitmessage('\n* * *\n'.join(msgs))
3794 repo.savecommitmessage('\n* * *\n'.join(msgs))
3794 except: # re-raises
3795 except: # re-raises
3795 # wlock.release() indirectly calls dirstate.write(): since
3796 # wlock.release() indirectly calls dirstate.write(): since
3796 # we're crashing, we do not want to change the working dir
3797 # we're crashing, we do not want to change the working dir
3797 # parent after all, so make sure it writes nothing
3798 # parent after all, so make sure it writes nothing
3798 repo.dirstate.invalidate()
3799 repo.dirstate.invalidate()
3799 raise
3800 raise
3800 finally:
3801 finally:
3801 if tr:
3802 if tr:
3802 tr.release()
3803 tr.release()
3803 release(lock, wlock)
3804 release(lock, wlock)
3804
3805
3805 @command('incoming|in',
3806 @command('incoming|in',
3806 [('f', 'force', None,
3807 [('f', 'force', None,
3807 _('run even if remote repository is unrelated')),
3808 _('run even if remote repository is unrelated')),
3808 ('n', 'newest-first', None, _('show newest record first')),
3809 ('n', 'newest-first', None, _('show newest record first')),
3809 ('', 'bundle', '',
3810 ('', 'bundle', '',
3810 _('file to store the bundles into'), _('FILE')),
3811 _('file to store the bundles into'), _('FILE')),
3811 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3812 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3812 ('B', 'bookmarks', False, _("compare bookmarks")),
3813 ('B', 'bookmarks', False, _("compare bookmarks")),
3813 ('b', 'branch', [],
3814 ('b', 'branch', [],
3814 _('a specific branch you would like to pull'), _('BRANCH')),
3815 _('a specific branch you would like to pull'), _('BRANCH')),
3815 ] + logopts + remoteopts + subrepoopts,
3816 ] + logopts + remoteopts + subrepoopts,
3816 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3817 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3817 def incoming(ui, repo, source="default", **opts):
3818 def incoming(ui, repo, source="default", **opts):
3818 """show new changesets found in source
3819 """show new changesets found in source
3819
3820
3820 Show new changesets found in the specified path/URL or the default
3821 Show new changesets found in the specified path/URL or the default
3821 pull location. These are the changesets that would have been pulled
3822 pull location. These are the changesets that would have been pulled
3822 if a pull at the time you issued this command.
3823 if a pull at the time you issued this command.
3823
3824
3824 For remote repository, using --bundle avoids downloading the
3825 For remote repository, using --bundle avoids downloading the
3825 changesets twice if the incoming is followed by a pull.
3826 changesets twice if the incoming is followed by a pull.
3826
3827
3827 See pull for valid source format details.
3828 See pull for valid source format details.
3828
3829
3829 Returns 0 if there are incoming changes, 1 otherwise.
3830 Returns 0 if there are incoming changes, 1 otherwise.
3830 """
3831 """
3832 if opts.get('graph'):
3833 cmdutil.checkunsupportedgraphflags([], opts)
3834 def display(other, chlist, displayer):
3835 revdag = cmdutil.graphrevs(other, chlist, opts)
3836 showparents = [ctx.node() for ctx in repo[None].parents()]
3837 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3838 graphmod.asciiedges)
3839
3840 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3841 return 0
3842
3831 if opts.get('bundle') and opts.get('subrepos'):
3843 if opts.get('bundle') and opts.get('subrepos'):
3832 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3844 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3833
3845
3834 if opts.get('bookmarks'):
3846 if opts.get('bookmarks'):
3835 source, branches = hg.parseurl(ui.expandpath(source),
3847 source, branches = hg.parseurl(ui.expandpath(source),
3836 opts.get('branch'))
3848 opts.get('branch'))
3837 other = hg.peer(repo, opts, source)
3849 other = hg.peer(repo, opts, source)
3838 if 'bookmarks' not in other.listkeys('namespaces'):
3850 if 'bookmarks' not in other.listkeys('namespaces'):
3839 ui.warn(_("remote doesn't support bookmarks\n"))
3851 ui.warn(_("remote doesn't support bookmarks\n"))
3840 return 0
3852 return 0
3841 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3853 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3842 return bookmarks.diff(ui, repo, other)
3854 return bookmarks.diff(ui, repo, other)
3843
3855
3844 repo._subtoppath = ui.expandpath(source)
3856 repo._subtoppath = ui.expandpath(source)
3845 try:
3857 try:
3846 return hg.incoming(ui, repo, source, opts)
3858 return hg.incoming(ui, repo, source, opts)
3847 finally:
3859 finally:
3848 del repo._subtoppath
3860 del repo._subtoppath
3849
3861
3850
3862
3851 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3863 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3852 def init(ui, dest=".", **opts):
3864 def init(ui, dest=".", **opts):
3853 """create a new repository in the given directory
3865 """create a new repository in the given directory
3854
3866
3855 Initialize a new repository in the given directory. If the given
3867 Initialize a new repository in the given directory. If the given
3856 directory does not exist, it will be created.
3868 directory does not exist, it will be created.
3857
3869
3858 If no directory is given, the current directory is used.
3870 If no directory is given, the current directory is used.
3859
3871
3860 It is possible to specify an ``ssh://`` URL as the destination.
3872 It is possible to specify an ``ssh://`` URL as the destination.
3861 See :hg:`help urls` for more information.
3873 See :hg:`help urls` for more information.
3862
3874
3863 Returns 0 on success.
3875 Returns 0 on success.
3864 """
3876 """
3865 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3877 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3866
3878
3867 @command('locate',
3879 @command('locate',
3868 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3880 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3869 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3881 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3870 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3882 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3871 ] + walkopts,
3883 ] + walkopts,
3872 _('[OPTION]... [PATTERN]...'))
3884 _('[OPTION]... [PATTERN]...'))
3873 def locate(ui, repo, *pats, **opts):
3885 def locate(ui, repo, *pats, **opts):
3874 """locate files matching specific patterns
3886 """locate files matching specific patterns
3875
3887
3876 Print files under Mercurial control in the working directory whose
3888 Print files under Mercurial control in the working directory whose
3877 names match the given patterns.
3889 names match the given patterns.
3878
3890
3879 By default, this command searches all directories in the working
3891 By default, this command searches all directories in the working
3880 directory. To search just the current directory and its
3892 directory. To search just the current directory and its
3881 subdirectories, use "--include .".
3893 subdirectories, use "--include .".
3882
3894
3883 If no patterns are given to match, this command prints the names
3895 If no patterns are given to match, this command prints the names
3884 of all files under Mercurial control in the working directory.
3896 of all files under Mercurial control in the working directory.
3885
3897
3886 If you want to feed the output of this command into the "xargs"
3898 If you want to feed the output of this command into the "xargs"
3887 command, use the -0 option to both this command and "xargs". This
3899 command, use the -0 option to both this command and "xargs". This
3888 will avoid the problem of "xargs" treating single filenames that
3900 will avoid the problem of "xargs" treating single filenames that
3889 contain whitespace as multiple filenames.
3901 contain whitespace as multiple filenames.
3890
3902
3891 Returns 0 if a match is found, 1 otherwise.
3903 Returns 0 if a match is found, 1 otherwise.
3892 """
3904 """
3893 end = opts.get('print0') and '\0' or '\n'
3905 end = opts.get('print0') and '\0' or '\n'
3894 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3906 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3895
3907
3896 ret = 1
3908 ret = 1
3897 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3909 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3898 m.bad = lambda x, y: False
3910 m.bad = lambda x, y: False
3899 for abs in repo[rev].walk(m):
3911 for abs in repo[rev].walk(m):
3900 if not rev and abs not in repo.dirstate:
3912 if not rev and abs not in repo.dirstate:
3901 continue
3913 continue
3902 if opts.get('fullpath'):
3914 if opts.get('fullpath'):
3903 ui.write(repo.wjoin(abs), end)
3915 ui.write(repo.wjoin(abs), end)
3904 else:
3916 else:
3905 ui.write(((pats and m.rel(abs)) or abs), end)
3917 ui.write(((pats and m.rel(abs)) or abs), end)
3906 ret = 0
3918 ret = 0
3907
3919
3908 return ret
3920 return ret
3909
3921
3910 @command('^log|history',
3922 @command('^log|history',
3911 [('f', 'follow', None,
3923 [('f', 'follow', None,
3912 _('follow changeset history, or file history across copies and renames')),
3924 _('follow changeset history, or file history across copies and renames')),
3913 ('', 'follow-first', None,
3925 ('', 'follow-first', None,
3914 _('only follow the first parent of merge changesets (DEPRECATED)')),
3926 _('only follow the first parent of merge changesets (DEPRECATED)')),
3915 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3927 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3916 ('C', 'copies', None, _('show copied files')),
3928 ('C', 'copies', None, _('show copied files')),
3917 ('k', 'keyword', [],
3929 ('k', 'keyword', [],
3918 _('do case-insensitive search for a given text'), _('TEXT')),
3930 _('do case-insensitive search for a given text'), _('TEXT')),
3919 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3931 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3920 ('', 'removed', None, _('include revisions where files were removed')),
3932 ('', 'removed', None, _('include revisions where files were removed')),
3921 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3933 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3922 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3934 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3923 ('', 'only-branch', [],
3935 ('', 'only-branch', [],
3924 _('show only changesets within the given named branch (DEPRECATED)'),
3936 _('show only changesets within the given named branch (DEPRECATED)'),
3925 _('BRANCH')),
3937 _('BRANCH')),
3926 ('b', 'branch', [],
3938 ('b', 'branch', [],
3927 _('show changesets within the given named branch'), _('BRANCH')),
3939 _('show changesets within the given named branch'), _('BRANCH')),
3928 ('P', 'prune', [],
3940 ('P', 'prune', [],
3929 _('do not display revision or any of its ancestors'), _('REV')),
3941 _('do not display revision or any of its ancestors'), _('REV')),
3930 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3942 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3931 ('G', 'graph', None, _("show the revision DAG")),
3932 ] + logopts + walkopts,
3943 ] + logopts + walkopts,
3933 _('[OPTION]... [FILE]'))
3944 _('[OPTION]... [FILE]'))
3934 def log(ui, repo, *pats, **opts):
3945 def log(ui, repo, *pats, **opts):
3935 """show revision history of entire repository or files
3946 """show revision history of entire repository or files
3936
3947
3937 Print the revision history of the specified files or the entire
3948 Print the revision history of the specified files or the entire
3938 project.
3949 project.
3939
3950
3940 If no revision range is specified, the default is ``tip:0`` unless
3951 If no revision range is specified, the default is ``tip:0`` unless
3941 --follow is set, in which case the working directory parent is
3952 --follow is set, in which case the working directory parent is
3942 used as the starting revision.
3953 used as the starting revision.
3943
3954
3944 File history is shown without following rename or copy history of
3955 File history is shown without following rename or copy history of
3945 files. Use -f/--follow with a filename to follow history across
3956 files. Use -f/--follow with a filename to follow history across
3946 renames and copies. --follow without a filename will only show
3957 renames and copies. --follow without a filename will only show
3947 ancestors or descendants of the starting revision.
3958 ancestors or descendants of the starting revision.
3948
3959
3949 By default this command prints revision number and changeset id,
3960 By default this command prints revision number and changeset id,
3950 tags, non-trivial parents, user, date and time, and a summary for
3961 tags, non-trivial parents, user, date and time, and a summary for
3951 each commit. When the -v/--verbose switch is used, the list of
3962 each commit. When the -v/--verbose switch is used, the list of
3952 changed files and full commit message are shown.
3963 changed files and full commit message are shown.
3953
3964
3954 .. note::
3965 .. note::
3955 log -p/--patch may generate unexpected diff output for merge
3966 log -p/--patch may generate unexpected diff output for merge
3956 changesets, as it will only compare the merge changeset against
3967 changesets, as it will only compare the merge changeset against
3957 its first parent. Also, only files different from BOTH parents
3968 its first parent. Also, only files different from BOTH parents
3958 will appear in files:.
3969 will appear in files:.
3959
3970
3960 .. note::
3971 .. note::
3961 for performance reasons, log FILE may omit duplicate changes
3972 for performance reasons, log FILE may omit duplicate changes
3962 made on branches and will not show deletions. To see all
3973 made on branches and will not show deletions. To see all
3963 changes including duplicates and deletions, use the --removed
3974 changes including duplicates and deletions, use the --removed
3964 switch.
3975 switch.
3965
3976
3966 .. container:: verbose
3977 .. container:: verbose
3967
3978
3968 Some examples:
3979 Some examples:
3969
3980
3970 - changesets with full descriptions and file lists::
3981 - changesets with full descriptions and file lists::
3971
3982
3972 hg log -v
3983 hg log -v
3973
3984
3974 - changesets ancestral to the working directory::
3985 - changesets ancestral to the working directory::
3975
3986
3976 hg log -f
3987 hg log -f
3977
3988
3978 - last 10 commits on the current branch::
3989 - last 10 commits on the current branch::
3979
3990
3980 hg log -l 10 -b .
3991 hg log -l 10 -b .
3981
3992
3982 - changesets showing all modifications of a file, including removals::
3993 - changesets showing all modifications of a file, including removals::
3983
3994
3984 hg log --removed file.c
3995 hg log --removed file.c
3985
3996
3986 - all changesets that touch a directory, with diffs, excluding merges::
3997 - all changesets that touch a directory, with diffs, excluding merges::
3987
3998
3988 hg log -Mp lib/
3999 hg log -Mp lib/
3989
4000
3990 - all revision numbers that match a keyword::
4001 - all revision numbers that match a keyword::
3991
4002
3992 hg log -k bug --template "{rev}\\n"
4003 hg log -k bug --template "{rev}\\n"
3993
4004
3994 - check if a given changeset is included is a tagged release::
4005 - check if a given changeset is included is a tagged release::
3995
4006
3996 hg log -r "a21ccf and ancestor(1.9)"
4007 hg log -r "a21ccf and ancestor(1.9)"
3997
4008
3998 - find all changesets by some user in a date range::
4009 - find all changesets by some user in a date range::
3999
4010
4000 hg log -k alice -d "may 2008 to jul 2008"
4011 hg log -k alice -d "may 2008 to jul 2008"
4001
4012
4002 - summary of all changesets after the last tag::
4013 - summary of all changesets after the last tag::
4003
4014
4004 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4015 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4005
4016
4006 See :hg:`help dates` for a list of formats valid for -d/--date.
4017 See :hg:`help dates` for a list of formats valid for -d/--date.
4007
4018
4008 See :hg:`help revisions` and :hg:`help revsets` for more about
4019 See :hg:`help revisions` and :hg:`help revsets` for more about
4009 specifying revisions.
4020 specifying revisions.
4010
4021
4011 See :hg:`help templates` for more about pre-packaged styles and
4022 See :hg:`help templates` for more about pre-packaged styles and
4012 specifying custom templates.
4023 specifying custom templates.
4013
4024
4014 Returns 0 on success.
4025 Returns 0 on success.
4015 """
4026 """
4016 if opts.get('graph'):
4027 if opts.get('graph'):
4017 return cmdutil.graphlog(ui, repo, *pats, **opts)
4028 return cmdutil.graphlog(ui, repo, *pats, **opts)
4018
4029
4019 matchfn = scmutil.match(repo[None], pats, opts)
4030 matchfn = scmutil.match(repo[None], pats, opts)
4020 limit = cmdutil.loglimit(opts)
4031 limit = cmdutil.loglimit(opts)
4021 count = 0
4032 count = 0
4022
4033
4023 getrenamed, endrev = None, None
4034 getrenamed, endrev = None, None
4024 if opts.get('copies'):
4035 if opts.get('copies'):
4025 if opts.get('rev'):
4036 if opts.get('rev'):
4026 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4037 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4027 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4038 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4028
4039
4029 df = False
4040 df = False
4030 if opts["date"]:
4041 if opts["date"]:
4031 df = util.matchdate(opts["date"])
4042 df = util.matchdate(opts["date"])
4032
4043
4033 branches = opts.get('branch', []) + opts.get('only_branch', [])
4044 branches = opts.get('branch', []) + opts.get('only_branch', [])
4034 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4045 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4035
4046
4036 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4047 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4037 def prep(ctx, fns):
4048 def prep(ctx, fns):
4038 rev = ctx.rev()
4049 rev = ctx.rev()
4039 parents = [p for p in repo.changelog.parentrevs(rev)
4050 parents = [p for p in repo.changelog.parentrevs(rev)
4040 if p != nullrev]
4051 if p != nullrev]
4041 if opts.get('no_merges') and len(parents) == 2:
4052 if opts.get('no_merges') and len(parents) == 2:
4042 return
4053 return
4043 if opts.get('only_merges') and len(parents) != 2:
4054 if opts.get('only_merges') and len(parents) != 2:
4044 return
4055 return
4045 if opts.get('branch') and ctx.branch() not in opts['branch']:
4056 if opts.get('branch') and ctx.branch() not in opts['branch']:
4046 return
4057 return
4047 if not opts.get('hidden') and ctx.hidden():
4058 if not opts.get('hidden') and ctx.hidden():
4048 return
4059 return
4049 if df and not df(ctx.date()[0]):
4060 if df and not df(ctx.date()[0]):
4050 return
4061 return
4051
4062
4052 lower = encoding.lower
4063 lower = encoding.lower
4053 if opts.get('user'):
4064 if opts.get('user'):
4054 luser = lower(ctx.user())
4065 luser = lower(ctx.user())
4055 for k in [lower(x) for x in opts['user']]:
4066 for k in [lower(x) for x in opts['user']]:
4056 if (k in luser):
4067 if (k in luser):
4057 break
4068 break
4058 else:
4069 else:
4059 return
4070 return
4060 if opts.get('keyword'):
4071 if opts.get('keyword'):
4061 luser = lower(ctx.user())
4072 luser = lower(ctx.user())
4062 ldesc = lower(ctx.description())
4073 ldesc = lower(ctx.description())
4063 lfiles = lower(" ".join(ctx.files()))
4074 lfiles = lower(" ".join(ctx.files()))
4064 for k in [lower(x) for x in opts['keyword']]:
4075 for k in [lower(x) for x in opts['keyword']]:
4065 if (k in luser or k in ldesc or k in lfiles):
4076 if (k in luser or k in ldesc or k in lfiles):
4066 break
4077 break
4067 else:
4078 else:
4068 return
4079 return
4069
4080
4070 copies = None
4081 copies = None
4071 if getrenamed is not None and rev:
4082 if getrenamed is not None and rev:
4072 copies = []
4083 copies = []
4073 for fn in ctx.files():
4084 for fn in ctx.files():
4074 rename = getrenamed(fn, rev)
4085 rename = getrenamed(fn, rev)
4075 if rename:
4086 if rename:
4076 copies.append((fn, rename[0]))
4087 copies.append((fn, rename[0]))
4077
4088
4078 revmatchfn = None
4089 revmatchfn = None
4079 if opts.get('patch') or opts.get('stat'):
4090 if opts.get('patch') or opts.get('stat'):
4080 if opts.get('follow') or opts.get('follow_first'):
4091 if opts.get('follow') or opts.get('follow_first'):
4081 # note: this might be wrong when following through merges
4092 # note: this might be wrong when following through merges
4082 revmatchfn = scmutil.match(repo[None], fns, default='path')
4093 revmatchfn = scmutil.match(repo[None], fns, default='path')
4083 else:
4094 else:
4084 revmatchfn = matchfn
4095 revmatchfn = matchfn
4085
4096
4086 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4097 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4087
4098
4088 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4099 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4089 if count == limit:
4100 if count == limit:
4090 break
4101 break
4091 if displayer.flush(ctx.rev()):
4102 if displayer.flush(ctx.rev()):
4092 count += 1
4103 count += 1
4093 displayer.close()
4104 displayer.close()
4094
4105
4095 @command('manifest',
4106 @command('manifest',
4096 [('r', 'rev', '', _('revision to display'), _('REV')),
4107 [('r', 'rev', '', _('revision to display'), _('REV')),
4097 ('', 'all', False, _("list files from all revisions"))],
4108 ('', 'all', False, _("list files from all revisions"))],
4098 _('[-r REV]'))
4109 _('[-r REV]'))
4099 def manifest(ui, repo, node=None, rev=None, **opts):
4110 def manifest(ui, repo, node=None, rev=None, **opts):
4100 """output the current or given revision of the project manifest
4111 """output the current or given revision of the project manifest
4101
4112
4102 Print a list of version controlled files for the given revision.
4113 Print a list of version controlled files for the given revision.
4103 If no revision is given, the first parent of the working directory
4114 If no revision is given, the first parent of the working directory
4104 is used, or the null revision if no revision is checked out.
4115 is used, or the null revision if no revision is checked out.
4105
4116
4106 With -v, print file permissions, symlink and executable bits.
4117 With -v, print file permissions, symlink and executable bits.
4107 With --debug, print file revision hashes.
4118 With --debug, print file revision hashes.
4108
4119
4109 If option --all is specified, the list of all files from all revisions
4120 If option --all is specified, the list of all files from all revisions
4110 is printed. This includes deleted and renamed files.
4121 is printed. This includes deleted and renamed files.
4111
4122
4112 Returns 0 on success.
4123 Returns 0 on success.
4113 """
4124 """
4114 if opts.get('all'):
4125 if opts.get('all'):
4115 if rev or node:
4126 if rev or node:
4116 raise util.Abort(_("can't specify a revision with --all"))
4127 raise util.Abort(_("can't specify a revision with --all"))
4117
4128
4118 res = []
4129 res = []
4119 prefix = "data/"
4130 prefix = "data/"
4120 suffix = ".i"
4131 suffix = ".i"
4121 plen = len(prefix)
4132 plen = len(prefix)
4122 slen = len(suffix)
4133 slen = len(suffix)
4123 lock = repo.lock()
4134 lock = repo.lock()
4124 try:
4135 try:
4125 for fn, b, size in repo.store.datafiles():
4136 for fn, b, size in repo.store.datafiles():
4126 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4137 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4127 res.append(fn[plen:-slen])
4138 res.append(fn[plen:-slen])
4128 finally:
4139 finally:
4129 lock.release()
4140 lock.release()
4130 for f in sorted(res):
4141 for f in sorted(res):
4131 ui.write("%s\n" % f)
4142 ui.write("%s\n" % f)
4132 return
4143 return
4133
4144
4134 if rev and node:
4145 if rev and node:
4135 raise util.Abort(_("please specify just one revision"))
4146 raise util.Abort(_("please specify just one revision"))
4136
4147
4137 if not node:
4148 if not node:
4138 node = rev
4149 node = rev
4139
4150
4140 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4151 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4141 ctx = scmutil.revsingle(repo, node)
4152 ctx = scmutil.revsingle(repo, node)
4142 for f in ctx:
4153 for f in ctx:
4143 if ui.debugflag:
4154 if ui.debugflag:
4144 ui.write("%40s " % hex(ctx.manifest()[f]))
4155 ui.write("%40s " % hex(ctx.manifest()[f]))
4145 if ui.verbose:
4156 if ui.verbose:
4146 ui.write(decor[ctx.flags(f)])
4157 ui.write(decor[ctx.flags(f)])
4147 ui.write("%s\n" % f)
4158 ui.write("%s\n" % f)
4148
4159
4149 @command('^merge',
4160 @command('^merge',
4150 [('f', 'force', None, _('force a merge with outstanding changes')),
4161 [('f', 'force', None, _('force a merge with outstanding changes')),
4151 ('r', 'rev', '', _('revision to merge'), _('REV')),
4162 ('r', 'rev', '', _('revision to merge'), _('REV')),
4152 ('P', 'preview', None,
4163 ('P', 'preview', None,
4153 _('review revisions to merge (no merge is performed)'))
4164 _('review revisions to merge (no merge is performed)'))
4154 ] + mergetoolopts,
4165 ] + mergetoolopts,
4155 _('[-P] [-f] [[-r] REV]'))
4166 _('[-P] [-f] [[-r] REV]'))
4156 def merge(ui, repo, node=None, **opts):
4167 def merge(ui, repo, node=None, **opts):
4157 """merge working directory with another revision
4168 """merge working directory with another revision
4158
4169
4159 The current working directory is updated with all changes made in
4170 The current working directory is updated with all changes made in
4160 the requested revision since the last common predecessor revision.
4171 the requested revision since the last common predecessor revision.
4161
4172
4162 Files that changed between either parent are marked as changed for
4173 Files that changed between either parent are marked as changed for
4163 the next commit and a commit must be performed before any further
4174 the next commit and a commit must be performed before any further
4164 updates to the repository are allowed. The next commit will have
4175 updates to the repository are allowed. The next commit will have
4165 two parents.
4176 two parents.
4166
4177
4167 ``--tool`` can be used to specify the merge tool used for file
4178 ``--tool`` can be used to specify the merge tool used for file
4168 merges. It overrides the HGMERGE environment variable and your
4179 merges. It overrides the HGMERGE environment variable and your
4169 configuration files. See :hg:`help merge-tools` for options.
4180 configuration files. See :hg:`help merge-tools` for options.
4170
4181
4171 If no revision is specified, the working directory's parent is a
4182 If no revision is specified, the working directory's parent is a
4172 head revision, and the current branch contains exactly one other
4183 head revision, and the current branch contains exactly one other
4173 head, the other head is merged with by default. Otherwise, an
4184 head, the other head is merged with by default. Otherwise, an
4174 explicit revision with which to merge with must be provided.
4185 explicit revision with which to merge with must be provided.
4175
4186
4176 :hg:`resolve` must be used to resolve unresolved files.
4187 :hg:`resolve` must be used to resolve unresolved files.
4177
4188
4178 To undo an uncommitted merge, use :hg:`update --clean .` which
4189 To undo an uncommitted merge, use :hg:`update --clean .` which
4179 will check out a clean copy of the original merge parent, losing
4190 will check out a clean copy of the original merge parent, losing
4180 all changes.
4191 all changes.
4181
4192
4182 Returns 0 on success, 1 if there are unresolved files.
4193 Returns 0 on success, 1 if there are unresolved files.
4183 """
4194 """
4184
4195
4185 if opts.get('rev') and node:
4196 if opts.get('rev') and node:
4186 raise util.Abort(_("please specify just one revision"))
4197 raise util.Abort(_("please specify just one revision"))
4187 if not node:
4198 if not node:
4188 node = opts.get('rev')
4199 node = opts.get('rev')
4189
4200
4190 if node:
4201 if node:
4191 node = scmutil.revsingle(repo, node).node()
4202 node = scmutil.revsingle(repo, node).node()
4192
4203
4193 if not node and repo._bookmarkcurrent:
4204 if not node and repo._bookmarkcurrent:
4194 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4205 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4195 curhead = repo[repo._bookmarkcurrent]
4206 curhead = repo[repo._bookmarkcurrent]
4196 if len(bmheads) == 2:
4207 if len(bmheads) == 2:
4197 if curhead == bmheads[0]:
4208 if curhead == bmheads[0]:
4198 node = bmheads[1]
4209 node = bmheads[1]
4199 else:
4210 else:
4200 node = bmheads[0]
4211 node = bmheads[0]
4201 elif len(bmheads) > 2:
4212 elif len(bmheads) > 2:
4202 raise util.Abort(_("multiple matching bookmarks to merge - "
4213 raise util.Abort(_("multiple matching bookmarks to merge - "
4203 "please merge with an explicit rev or bookmark"),
4214 "please merge with an explicit rev or bookmark"),
4204 hint=_("run 'hg heads' to see all heads"))
4215 hint=_("run 'hg heads' to see all heads"))
4205 elif len(bmheads) <= 1:
4216 elif len(bmheads) <= 1:
4206 raise util.Abort(_("no matching bookmark to merge - "
4217 raise util.Abort(_("no matching bookmark to merge - "
4207 "please merge with an explicit rev or bookmark"),
4218 "please merge with an explicit rev or bookmark"),
4208 hint=_("run 'hg heads' to see all heads"))
4219 hint=_("run 'hg heads' to see all heads"))
4209
4220
4210 if not node and not repo._bookmarkcurrent:
4221 if not node and not repo._bookmarkcurrent:
4211 branch = repo[None].branch()
4222 branch = repo[None].branch()
4212 bheads = repo.branchheads(branch)
4223 bheads = repo.branchheads(branch)
4213 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4224 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4214
4225
4215 if len(nbhs) > 2:
4226 if len(nbhs) > 2:
4216 raise util.Abort(_("branch '%s' has %d heads - "
4227 raise util.Abort(_("branch '%s' has %d heads - "
4217 "please merge with an explicit rev")
4228 "please merge with an explicit rev")
4218 % (branch, len(bheads)),
4229 % (branch, len(bheads)),
4219 hint=_("run 'hg heads .' to see heads"))
4230 hint=_("run 'hg heads .' to see heads"))
4220
4231
4221 parent = repo.dirstate.p1()
4232 parent = repo.dirstate.p1()
4222 if len(nbhs) == 1:
4233 if len(nbhs) == 1:
4223 if len(bheads) > 1:
4234 if len(bheads) > 1:
4224 raise util.Abort(_("heads are bookmarked - "
4235 raise util.Abort(_("heads are bookmarked - "
4225 "please merge with an explicit rev"),
4236 "please merge with an explicit rev"),
4226 hint=_("run 'hg heads' to see all heads"))
4237 hint=_("run 'hg heads' to see all heads"))
4227 if len(repo.heads()) > 1:
4238 if len(repo.heads()) > 1:
4228 raise util.Abort(_("branch '%s' has one head - "
4239 raise util.Abort(_("branch '%s' has one head - "
4229 "please merge with an explicit rev")
4240 "please merge with an explicit rev")
4230 % branch,
4241 % branch,
4231 hint=_("run 'hg heads' to see all heads"))
4242 hint=_("run 'hg heads' to see all heads"))
4232 msg, hint = _('nothing to merge'), None
4243 msg, hint = _('nothing to merge'), None
4233 if parent != repo.lookup(branch):
4244 if parent != repo.lookup(branch):
4234 hint = _("use 'hg update' instead")
4245 hint = _("use 'hg update' instead")
4235 raise util.Abort(msg, hint=hint)
4246 raise util.Abort(msg, hint=hint)
4236
4247
4237 if parent not in bheads:
4248 if parent not in bheads:
4238 raise util.Abort(_('working directory not at a head revision'),
4249 raise util.Abort(_('working directory not at a head revision'),
4239 hint=_("use 'hg update' or merge with an "
4250 hint=_("use 'hg update' or merge with an "
4240 "explicit revision"))
4251 "explicit revision"))
4241 if parent == nbhs[0]:
4252 if parent == nbhs[0]:
4242 node = nbhs[-1]
4253 node = nbhs[-1]
4243 else:
4254 else:
4244 node = nbhs[0]
4255 node = nbhs[0]
4245
4256
4246 if opts.get('preview'):
4257 if opts.get('preview'):
4247 # find nodes that are ancestors of p2 but not of p1
4258 # find nodes that are ancestors of p2 but not of p1
4248 p1 = repo.lookup('.')
4259 p1 = repo.lookup('.')
4249 p2 = repo.lookup(node)
4260 p2 = repo.lookup(node)
4250 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4261 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4251
4262
4252 displayer = cmdutil.show_changeset(ui, repo, opts)
4263 displayer = cmdutil.show_changeset(ui, repo, opts)
4253 for node in nodes:
4264 for node in nodes:
4254 displayer.show(repo[node])
4265 displayer.show(repo[node])
4255 displayer.close()
4266 displayer.close()
4256 return 0
4267 return 0
4257
4268
4258 try:
4269 try:
4259 # ui.forcemerge is an internal variable, do not document
4270 # ui.forcemerge is an internal variable, do not document
4260 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4261 return hg.merge(repo, node, force=opts.get('force'))
4272 return hg.merge(repo, node, force=opts.get('force'))
4262 finally:
4273 finally:
4263 ui.setconfig('ui', 'forcemerge', '')
4274 ui.setconfig('ui', 'forcemerge', '')
4264
4275
4265 @command('outgoing|out',
4276 @command('outgoing|out',
4266 [('f', 'force', None, _('run even when the destination is unrelated')),
4277 [('f', 'force', None, _('run even when the destination is unrelated')),
4267 ('r', 'rev', [],
4278 ('r', 'rev', [],
4268 _('a changeset intended to be included in the destination'), _('REV')),
4279 _('a changeset intended to be included in the destination'), _('REV')),
4269 ('n', 'newest-first', None, _('show newest record first')),
4280 ('n', 'newest-first', None, _('show newest record first')),
4270 ('B', 'bookmarks', False, _('compare bookmarks')),
4281 ('B', 'bookmarks', False, _('compare bookmarks')),
4271 ('b', 'branch', [], _('a specific branch you would like to push'),
4282 ('b', 'branch', [], _('a specific branch you would like to push'),
4272 _('BRANCH')),
4283 _('BRANCH')),
4273 ] + logopts + remoteopts + subrepoopts,
4284 ] + logopts + remoteopts + subrepoopts,
4274 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4285 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4275 def outgoing(ui, repo, dest=None, **opts):
4286 def outgoing(ui, repo, dest=None, **opts):
4276 """show changesets not found in the destination
4287 """show changesets not found in the destination
4277
4288
4278 Show changesets not found in the specified destination repository
4289 Show changesets not found in the specified destination repository
4279 or the default push location. These are the changesets that would
4290 or the default push location. These are the changesets that would
4280 be pushed if a push was requested.
4291 be pushed if a push was requested.
4281
4292
4282 See pull for details of valid destination formats.
4293 See pull for details of valid destination formats.
4283
4294
4284 Returns 0 if there are outgoing changes, 1 otherwise.
4295 Returns 0 if there are outgoing changes, 1 otherwise.
4285 """
4296 """
4297 if opts.get('graph'):
4298 cmdutil.checkunsupportedgraphflags([], opts)
4299 o = hg._outgoing(ui, repo, dest, opts)
4300 if o is None:
4301 return
4302
4303 revdag = cmdutil.graphrevs(repo, o, opts)
4304 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4305 showparents = [ctx.node() for ctx in repo[None].parents()]
4306 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4307 graphmod.asciiedges)
4308 return 0
4286
4309
4287 if opts.get('bookmarks'):
4310 if opts.get('bookmarks'):
4288 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4311 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4289 dest, branches = hg.parseurl(dest, opts.get('branch'))
4312 dest, branches = hg.parseurl(dest, opts.get('branch'))
4290 other = hg.peer(repo, opts, dest)
4313 other = hg.peer(repo, opts, dest)
4291 if 'bookmarks' not in other.listkeys('namespaces'):
4314 if 'bookmarks' not in other.listkeys('namespaces'):
4292 ui.warn(_("remote doesn't support bookmarks\n"))
4315 ui.warn(_("remote doesn't support bookmarks\n"))
4293 return 0
4316 return 0
4294 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4317 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4295 return bookmarks.diff(ui, other, repo)
4318 return bookmarks.diff(ui, other, repo)
4296
4319
4297 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4320 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4298 try:
4321 try:
4299 return hg.outgoing(ui, repo, dest, opts)
4322 return hg.outgoing(ui, repo, dest, opts)
4300 finally:
4323 finally:
4301 del repo._subtoppath
4324 del repo._subtoppath
4302
4325
4303 @command('parents',
4326 @command('parents',
4304 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4327 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4305 ] + templateopts,
4328 ] + templateopts,
4306 _('[-r REV] [FILE]'))
4329 _('[-r REV] [FILE]'))
4307 def parents(ui, repo, file_=None, **opts):
4330 def parents(ui, repo, file_=None, **opts):
4308 """show the parents of the working directory or revision
4331 """show the parents of the working directory or revision
4309
4332
4310 Print the working directory's parent revisions. If a revision is
4333 Print the working directory's parent revisions. If a revision is
4311 given via -r/--rev, the parent of that revision will be printed.
4334 given via -r/--rev, the parent of that revision will be printed.
4312 If a file argument is given, the revision in which the file was
4335 If a file argument is given, the revision in which the file was
4313 last changed (before the working directory revision or the
4336 last changed (before the working directory revision or the
4314 argument to --rev if given) is printed.
4337 argument to --rev if given) is printed.
4315
4338
4316 Returns 0 on success.
4339 Returns 0 on success.
4317 """
4340 """
4318
4341
4319 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4342 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4320
4343
4321 if file_:
4344 if file_:
4322 m = scmutil.match(ctx, (file_,), opts)
4345 m = scmutil.match(ctx, (file_,), opts)
4323 if m.anypats() or len(m.files()) != 1:
4346 if m.anypats() or len(m.files()) != 1:
4324 raise util.Abort(_('can only specify an explicit filename'))
4347 raise util.Abort(_('can only specify an explicit filename'))
4325 file_ = m.files()[0]
4348 file_ = m.files()[0]
4326 filenodes = []
4349 filenodes = []
4327 for cp in ctx.parents():
4350 for cp in ctx.parents():
4328 if not cp:
4351 if not cp:
4329 continue
4352 continue
4330 try:
4353 try:
4331 filenodes.append(cp.filenode(file_))
4354 filenodes.append(cp.filenode(file_))
4332 except error.LookupError:
4355 except error.LookupError:
4333 pass
4356 pass
4334 if not filenodes:
4357 if not filenodes:
4335 raise util.Abort(_("'%s' not found in manifest!") % file_)
4358 raise util.Abort(_("'%s' not found in manifest!") % file_)
4336 fl = repo.file(file_)
4359 fl = repo.file(file_)
4337 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4360 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4338 else:
4361 else:
4339 p = [cp.node() for cp in ctx.parents()]
4362 p = [cp.node() for cp in ctx.parents()]
4340
4363
4341 displayer = cmdutil.show_changeset(ui, repo, opts)
4364 displayer = cmdutil.show_changeset(ui, repo, opts)
4342 for n in p:
4365 for n in p:
4343 if n != nullid:
4366 if n != nullid:
4344 displayer.show(repo[n])
4367 displayer.show(repo[n])
4345 displayer.close()
4368 displayer.close()
4346
4369
4347 @command('paths', [], _('[NAME]'))
4370 @command('paths', [], _('[NAME]'))
4348 def paths(ui, repo, search=None):
4371 def paths(ui, repo, search=None):
4349 """show aliases for remote repositories
4372 """show aliases for remote repositories
4350
4373
4351 Show definition of symbolic path name NAME. If no name is given,
4374 Show definition of symbolic path name NAME. If no name is given,
4352 show definition of all available names.
4375 show definition of all available names.
4353
4376
4354 Option -q/--quiet suppresses all output when searching for NAME
4377 Option -q/--quiet suppresses all output when searching for NAME
4355 and shows only the path names when listing all definitions.
4378 and shows only the path names when listing all definitions.
4356
4379
4357 Path names are defined in the [paths] section of your
4380 Path names are defined in the [paths] section of your
4358 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4381 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4359 repository, ``.hg/hgrc`` is used, too.
4382 repository, ``.hg/hgrc`` is used, too.
4360
4383
4361 The path names ``default`` and ``default-push`` have a special
4384 The path names ``default`` and ``default-push`` have a special
4362 meaning. When performing a push or pull operation, they are used
4385 meaning. When performing a push or pull operation, they are used
4363 as fallbacks if no location is specified on the command-line.
4386 as fallbacks if no location is specified on the command-line.
4364 When ``default-push`` is set, it will be used for push and
4387 When ``default-push`` is set, it will be used for push and
4365 ``default`` will be used for pull; otherwise ``default`` is used
4388 ``default`` will be used for pull; otherwise ``default`` is used
4366 as the fallback for both. When cloning a repository, the clone
4389 as the fallback for both. When cloning a repository, the clone
4367 source is written as ``default`` in ``.hg/hgrc``. Note that
4390 source is written as ``default`` in ``.hg/hgrc``. Note that
4368 ``default`` and ``default-push`` apply to all inbound (e.g.
4391 ``default`` and ``default-push`` apply to all inbound (e.g.
4369 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4392 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4370 :hg:`bundle`) operations.
4393 :hg:`bundle`) operations.
4371
4394
4372 See :hg:`help urls` for more information.
4395 See :hg:`help urls` for more information.
4373
4396
4374 Returns 0 on success.
4397 Returns 0 on success.
4375 """
4398 """
4376 if search:
4399 if search:
4377 for name, path in ui.configitems("paths"):
4400 for name, path in ui.configitems("paths"):
4378 if name == search:
4401 if name == search:
4379 ui.status("%s\n" % util.hidepassword(path))
4402 ui.status("%s\n" % util.hidepassword(path))
4380 return
4403 return
4381 if not ui.quiet:
4404 if not ui.quiet:
4382 ui.warn(_("not found!\n"))
4405 ui.warn(_("not found!\n"))
4383 return 1
4406 return 1
4384 else:
4407 else:
4385 for name, path in ui.configitems("paths"):
4408 for name, path in ui.configitems("paths"):
4386 if ui.quiet:
4409 if ui.quiet:
4387 ui.write("%s\n" % name)
4410 ui.write("%s\n" % name)
4388 else:
4411 else:
4389 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4412 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4390
4413
4391 @command('^phase',
4414 @command('^phase',
4392 [('p', 'public', False, _('set changeset phase to public')),
4415 [('p', 'public', False, _('set changeset phase to public')),
4393 ('d', 'draft', False, _('set changeset phase to draft')),
4416 ('d', 'draft', False, _('set changeset phase to draft')),
4394 ('s', 'secret', False, _('set changeset phase to secret')),
4417 ('s', 'secret', False, _('set changeset phase to secret')),
4395 ('f', 'force', False, _('allow to move boundary backward')),
4418 ('f', 'force', False, _('allow to move boundary backward')),
4396 ('r', 'rev', [], _('target revision'), _('REV')),
4419 ('r', 'rev', [], _('target revision'), _('REV')),
4397 ],
4420 ],
4398 _('[-p|-d|-s] [-f] [-r] REV...'))
4421 _('[-p|-d|-s] [-f] [-r] REV...'))
4399 def phase(ui, repo, *revs, **opts):
4422 def phase(ui, repo, *revs, **opts):
4400 """set or show the current phase name
4423 """set or show the current phase name
4401
4424
4402 With no argument, show the phase name of specified revisions.
4425 With no argument, show the phase name of specified revisions.
4403
4426
4404 With one of -p/--public, -d/--draft or -s/--secret, change the
4427 With one of -p/--public, -d/--draft or -s/--secret, change the
4405 phase value of the specified revisions.
4428 phase value of the specified revisions.
4406
4429
4407 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4430 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4408 lower phase to an higher phase. Phases are ordered as follows::
4431 lower phase to an higher phase. Phases are ordered as follows::
4409
4432
4410 public < draft < secret
4433 public < draft < secret
4411
4434
4412 Return 0 on success, 1 if no phases were changed or some could not
4435 Return 0 on success, 1 if no phases were changed or some could not
4413 be changed.
4436 be changed.
4414 """
4437 """
4415 # search for a unique phase argument
4438 # search for a unique phase argument
4416 targetphase = None
4439 targetphase = None
4417 for idx, name in enumerate(phases.phasenames):
4440 for idx, name in enumerate(phases.phasenames):
4418 if opts[name]:
4441 if opts[name]:
4419 if targetphase is not None:
4442 if targetphase is not None:
4420 raise util.Abort(_('only one phase can be specified'))
4443 raise util.Abort(_('only one phase can be specified'))
4421 targetphase = idx
4444 targetphase = idx
4422
4445
4423 # look for specified revision
4446 # look for specified revision
4424 revs = list(revs)
4447 revs = list(revs)
4425 revs.extend(opts['rev'])
4448 revs.extend(opts['rev'])
4426 if not revs:
4449 if not revs:
4427 raise util.Abort(_('no revisions specified'))
4450 raise util.Abort(_('no revisions specified'))
4428
4451
4429 revs = scmutil.revrange(repo, revs)
4452 revs = scmutil.revrange(repo, revs)
4430
4453
4431 lock = None
4454 lock = None
4432 ret = 0
4455 ret = 0
4433 if targetphase is None:
4456 if targetphase is None:
4434 # display
4457 # display
4435 for r in revs:
4458 for r in revs:
4436 ctx = repo[r]
4459 ctx = repo[r]
4437 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4460 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4438 else:
4461 else:
4439 lock = repo.lock()
4462 lock = repo.lock()
4440 try:
4463 try:
4441 # set phase
4464 # set phase
4442 if not revs:
4465 if not revs:
4443 raise util.Abort(_('empty revision set'))
4466 raise util.Abort(_('empty revision set'))
4444 nodes = [repo[r].node() for r in revs]
4467 nodes = [repo[r].node() for r in revs]
4445 olddata = repo._phasecache.getphaserevs(repo)[:]
4468 olddata = repo._phasecache.getphaserevs(repo)[:]
4446 phases.advanceboundary(repo, targetphase, nodes)
4469 phases.advanceboundary(repo, targetphase, nodes)
4447 if opts['force']:
4470 if opts['force']:
4448 phases.retractboundary(repo, targetphase, nodes)
4471 phases.retractboundary(repo, targetphase, nodes)
4449 finally:
4472 finally:
4450 lock.release()
4473 lock.release()
4451 newdata = repo._phasecache.getphaserevs(repo)
4474 newdata = repo._phasecache.getphaserevs(repo)
4452 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4475 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4453 rejected = [n for n in nodes
4476 rejected = [n for n in nodes
4454 if newdata[repo[n].rev()] < targetphase]
4477 if newdata[repo[n].rev()] < targetphase]
4455 if rejected:
4478 if rejected:
4456 ui.warn(_('cannot move %i changesets to a more permissive '
4479 ui.warn(_('cannot move %i changesets to a more permissive '
4457 'phase, use --force\n') % len(rejected))
4480 'phase, use --force\n') % len(rejected))
4458 ret = 1
4481 ret = 1
4459 if changes:
4482 if changes:
4460 msg = _('phase changed for %i changesets\n') % changes
4483 msg = _('phase changed for %i changesets\n') % changes
4461 if ret:
4484 if ret:
4462 ui.status(msg)
4485 ui.status(msg)
4463 else:
4486 else:
4464 ui.note(msg)
4487 ui.note(msg)
4465 else:
4488 else:
4466 ui.warn(_('no phases changed\n'))
4489 ui.warn(_('no phases changed\n'))
4467 ret = 1
4490 ret = 1
4468 return ret
4491 return ret
4469
4492
4470 def postincoming(ui, repo, modheads, optupdate, checkout):
4493 def postincoming(ui, repo, modheads, optupdate, checkout):
4471 if modheads == 0:
4494 if modheads == 0:
4472 return
4495 return
4473 if optupdate:
4496 if optupdate:
4474 movemarkfrom = repo['.'].node()
4497 movemarkfrom = repo['.'].node()
4475 try:
4498 try:
4476 ret = hg.update(repo, checkout)
4499 ret = hg.update(repo, checkout)
4477 except util.Abort, inst:
4500 except util.Abort, inst:
4478 ui.warn(_("not updating: %s\n") % str(inst))
4501 ui.warn(_("not updating: %s\n") % str(inst))
4479 return 0
4502 return 0
4480 if not ret and not checkout:
4503 if not ret and not checkout:
4481 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4504 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4482 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4505 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4483 return ret
4506 return ret
4484 if modheads > 1:
4507 if modheads > 1:
4485 currentbranchheads = len(repo.branchheads())
4508 currentbranchheads = len(repo.branchheads())
4486 if currentbranchheads == modheads:
4509 if currentbranchheads == modheads:
4487 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4510 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4488 elif currentbranchheads > 1:
4511 elif currentbranchheads > 1:
4489 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4512 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4490 "merge)\n"))
4513 "merge)\n"))
4491 else:
4514 else:
4492 ui.status(_("(run 'hg heads' to see heads)\n"))
4515 ui.status(_("(run 'hg heads' to see heads)\n"))
4493 else:
4516 else:
4494 ui.status(_("(run 'hg update' to get a working copy)\n"))
4517 ui.status(_("(run 'hg update' to get a working copy)\n"))
4495
4518
4496 @command('^pull',
4519 @command('^pull',
4497 [('u', 'update', None,
4520 [('u', 'update', None,
4498 _('update to new branch head if changesets were pulled')),
4521 _('update to new branch head if changesets were pulled')),
4499 ('f', 'force', None, _('run even when remote repository is unrelated')),
4522 ('f', 'force', None, _('run even when remote repository is unrelated')),
4500 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4523 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4501 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4524 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4502 ('b', 'branch', [], _('a specific branch you would like to pull'),
4525 ('b', 'branch', [], _('a specific branch you would like to pull'),
4503 _('BRANCH')),
4526 _('BRANCH')),
4504 ] + remoteopts,
4527 ] + remoteopts,
4505 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4528 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4506 def pull(ui, repo, source="default", **opts):
4529 def pull(ui, repo, source="default", **opts):
4507 """pull changes from the specified source
4530 """pull changes from the specified source
4508
4531
4509 Pull changes from a remote repository to a local one.
4532 Pull changes from a remote repository to a local one.
4510
4533
4511 This finds all changes from the repository at the specified path
4534 This finds all changes from the repository at the specified path
4512 or URL and adds them to a local repository (the current one unless
4535 or URL and adds them to a local repository (the current one unless
4513 -R is specified). By default, this does not update the copy of the
4536 -R is specified). By default, this does not update the copy of the
4514 project in the working directory.
4537 project in the working directory.
4515
4538
4516 Use :hg:`incoming` if you want to see what would have been added
4539 Use :hg:`incoming` if you want to see what would have been added
4517 by a pull at the time you issued this command. If you then decide
4540 by a pull at the time you issued this command. If you then decide
4518 to add those changes to the repository, you should use :hg:`pull
4541 to add those changes to the repository, you should use :hg:`pull
4519 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4542 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4520
4543
4521 If SOURCE is omitted, the 'default' path will be used.
4544 If SOURCE is omitted, the 'default' path will be used.
4522 See :hg:`help urls` for more information.
4545 See :hg:`help urls` for more information.
4523
4546
4524 Returns 0 on success, 1 if an update had unresolved files.
4547 Returns 0 on success, 1 if an update had unresolved files.
4525 """
4548 """
4526 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4549 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4527 other = hg.peer(repo, opts, source)
4550 other = hg.peer(repo, opts, source)
4528 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4551 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4529 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4552 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4530
4553
4531 if opts.get('bookmark'):
4554 if opts.get('bookmark'):
4532 if not revs:
4555 if not revs:
4533 revs = []
4556 revs = []
4534 rb = other.listkeys('bookmarks')
4557 rb = other.listkeys('bookmarks')
4535 for b in opts['bookmark']:
4558 for b in opts['bookmark']:
4536 if b not in rb:
4559 if b not in rb:
4537 raise util.Abort(_('remote bookmark %s not found!') % b)
4560 raise util.Abort(_('remote bookmark %s not found!') % b)
4538 revs.append(rb[b])
4561 revs.append(rb[b])
4539
4562
4540 if revs:
4563 if revs:
4541 try:
4564 try:
4542 revs = [other.lookup(rev) for rev in revs]
4565 revs = [other.lookup(rev) for rev in revs]
4543 except error.CapabilityError:
4566 except error.CapabilityError:
4544 err = _("other repository doesn't support revision lookup, "
4567 err = _("other repository doesn't support revision lookup, "
4545 "so a rev cannot be specified.")
4568 "so a rev cannot be specified.")
4546 raise util.Abort(err)
4569 raise util.Abort(err)
4547
4570
4548 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4571 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4549 bookmarks.updatefromremote(ui, repo, other, source)
4572 bookmarks.updatefromremote(ui, repo, other, source)
4550 if checkout:
4573 if checkout:
4551 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4574 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4552 repo._subtoppath = source
4575 repo._subtoppath = source
4553 try:
4576 try:
4554 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4577 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4555
4578
4556 finally:
4579 finally:
4557 del repo._subtoppath
4580 del repo._subtoppath
4558
4581
4559 # update specified bookmarks
4582 # update specified bookmarks
4560 if opts.get('bookmark'):
4583 if opts.get('bookmark'):
4561 for b in opts['bookmark']:
4584 for b in opts['bookmark']:
4562 # explicit pull overrides local bookmark if any
4585 # explicit pull overrides local bookmark if any
4563 ui.status(_("importing bookmark %s\n") % b)
4586 ui.status(_("importing bookmark %s\n") % b)
4564 repo._bookmarks[b] = repo[rb[b]].node()
4587 repo._bookmarks[b] = repo[rb[b]].node()
4565 bookmarks.write(repo)
4588 bookmarks.write(repo)
4566
4589
4567 return ret
4590 return ret
4568
4591
4569 @command('^push',
4592 @command('^push',
4570 [('f', 'force', None, _('force push')),
4593 [('f', 'force', None, _('force push')),
4571 ('r', 'rev', [],
4594 ('r', 'rev', [],
4572 _('a changeset intended to be included in the destination'),
4595 _('a changeset intended to be included in the destination'),
4573 _('REV')),
4596 _('REV')),
4574 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4597 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4575 ('b', 'branch', [],
4598 ('b', 'branch', [],
4576 _('a specific branch you would like to push'), _('BRANCH')),
4599 _('a specific branch you would like to push'), _('BRANCH')),
4577 ('', 'new-branch', False, _('allow pushing a new branch')),
4600 ('', 'new-branch', False, _('allow pushing a new branch')),
4578 ] + remoteopts,
4601 ] + remoteopts,
4579 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4602 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4580 def push(ui, repo, dest=None, **opts):
4603 def push(ui, repo, dest=None, **opts):
4581 """push changes to the specified destination
4604 """push changes to the specified destination
4582
4605
4583 Push changesets from the local repository to the specified
4606 Push changesets from the local repository to the specified
4584 destination.
4607 destination.
4585
4608
4586 This operation is symmetrical to pull: it is identical to a pull
4609 This operation is symmetrical to pull: it is identical to a pull
4587 in the destination repository from the current one.
4610 in the destination repository from the current one.
4588
4611
4589 By default, push will not allow creation of new heads at the
4612 By default, push will not allow creation of new heads at the
4590 destination, since multiple heads would make it unclear which head
4613 destination, since multiple heads would make it unclear which head
4591 to use. In this situation, it is recommended to pull and merge
4614 to use. In this situation, it is recommended to pull and merge
4592 before pushing.
4615 before pushing.
4593
4616
4594 Use --new-branch if you want to allow push to create a new named
4617 Use --new-branch if you want to allow push to create a new named
4595 branch that is not present at the destination. This allows you to
4618 branch that is not present at the destination. This allows you to
4596 only create a new branch without forcing other changes.
4619 only create a new branch without forcing other changes.
4597
4620
4598 Use -f/--force to override the default behavior and push all
4621 Use -f/--force to override the default behavior and push all
4599 changesets on all branches.
4622 changesets on all branches.
4600
4623
4601 If -r/--rev is used, the specified revision and all its ancestors
4624 If -r/--rev is used, the specified revision and all its ancestors
4602 will be pushed to the remote repository.
4625 will be pushed to the remote repository.
4603
4626
4604 Please see :hg:`help urls` for important details about ``ssh://``
4627 Please see :hg:`help urls` for important details about ``ssh://``
4605 URLs. If DESTINATION is omitted, a default path will be used.
4628 URLs. If DESTINATION is omitted, a default path will be used.
4606
4629
4607 Returns 0 if push was successful, 1 if nothing to push.
4630 Returns 0 if push was successful, 1 if nothing to push.
4608 """
4631 """
4609
4632
4610 if opts.get('bookmark'):
4633 if opts.get('bookmark'):
4611 for b in opts['bookmark']:
4634 for b in opts['bookmark']:
4612 # translate -B options to -r so changesets get pushed
4635 # translate -B options to -r so changesets get pushed
4613 if b in repo._bookmarks:
4636 if b in repo._bookmarks:
4614 opts.setdefault('rev', []).append(b)
4637 opts.setdefault('rev', []).append(b)
4615 else:
4638 else:
4616 # if we try to push a deleted bookmark, translate it to null
4639 # if we try to push a deleted bookmark, translate it to null
4617 # this lets simultaneous -r, -b options continue working
4640 # this lets simultaneous -r, -b options continue working
4618 opts.setdefault('rev', []).append("null")
4641 opts.setdefault('rev', []).append("null")
4619
4642
4620 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4643 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4621 dest, branches = hg.parseurl(dest, opts.get('branch'))
4644 dest, branches = hg.parseurl(dest, opts.get('branch'))
4622 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4645 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4623 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4646 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4624 other = hg.peer(repo, opts, dest)
4647 other = hg.peer(repo, opts, dest)
4625 if revs:
4648 if revs:
4626 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4649 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4627
4650
4628 repo._subtoppath = dest
4651 repo._subtoppath = dest
4629 try:
4652 try:
4630 # push subrepos depth-first for coherent ordering
4653 # push subrepos depth-first for coherent ordering
4631 c = repo['']
4654 c = repo['']
4632 subs = c.substate # only repos that are committed
4655 subs = c.substate # only repos that are committed
4633 for s in sorted(subs):
4656 for s in sorted(subs):
4634 if c.sub(s).push(opts) == 0:
4657 if c.sub(s).push(opts) == 0:
4635 return False
4658 return False
4636 finally:
4659 finally:
4637 del repo._subtoppath
4660 del repo._subtoppath
4638 result = repo.push(other, opts.get('force'), revs=revs,
4661 result = repo.push(other, opts.get('force'), revs=revs,
4639 newbranch=opts.get('new_branch'))
4662 newbranch=opts.get('new_branch'))
4640
4663
4641 result = not result
4664 result = not result
4642
4665
4643 if opts.get('bookmark'):
4666 if opts.get('bookmark'):
4644 rb = other.listkeys('bookmarks')
4667 rb = other.listkeys('bookmarks')
4645 for b in opts['bookmark']:
4668 for b in opts['bookmark']:
4646 # explicit push overrides remote bookmark if any
4669 # explicit push overrides remote bookmark if any
4647 if b in repo._bookmarks:
4670 if b in repo._bookmarks:
4648 ui.status(_("exporting bookmark %s\n") % b)
4671 ui.status(_("exporting bookmark %s\n") % b)
4649 new = repo[b].hex()
4672 new = repo[b].hex()
4650 elif b in rb:
4673 elif b in rb:
4651 ui.status(_("deleting remote bookmark %s\n") % b)
4674 ui.status(_("deleting remote bookmark %s\n") % b)
4652 new = '' # delete
4675 new = '' # delete
4653 else:
4676 else:
4654 ui.warn(_('bookmark %s does not exist on the local '
4677 ui.warn(_('bookmark %s does not exist on the local '
4655 'or remote repository!\n') % b)
4678 'or remote repository!\n') % b)
4656 return 2
4679 return 2
4657 old = rb.get(b, '')
4680 old = rb.get(b, '')
4658 r = other.pushkey('bookmarks', b, old, new)
4681 r = other.pushkey('bookmarks', b, old, new)
4659 if not r:
4682 if not r:
4660 ui.warn(_('updating bookmark %s failed!\n') % b)
4683 ui.warn(_('updating bookmark %s failed!\n') % b)
4661 if not result:
4684 if not result:
4662 result = 2
4685 result = 2
4663
4686
4664 return result
4687 return result
4665
4688
4666 @command('recover', [])
4689 @command('recover', [])
4667 def recover(ui, repo):
4690 def recover(ui, repo):
4668 """roll back an interrupted transaction
4691 """roll back an interrupted transaction
4669
4692
4670 Recover from an interrupted commit or pull.
4693 Recover from an interrupted commit or pull.
4671
4694
4672 This command tries to fix the repository status after an
4695 This command tries to fix the repository status after an
4673 interrupted operation. It should only be necessary when Mercurial
4696 interrupted operation. It should only be necessary when Mercurial
4674 suggests it.
4697 suggests it.
4675
4698
4676 Returns 0 if successful, 1 if nothing to recover or verify fails.
4699 Returns 0 if successful, 1 if nothing to recover or verify fails.
4677 """
4700 """
4678 if repo.recover():
4701 if repo.recover():
4679 return hg.verify(repo)
4702 return hg.verify(repo)
4680 return 1
4703 return 1
4681
4704
4682 @command('^remove|rm',
4705 @command('^remove|rm',
4683 [('A', 'after', None, _('record delete for missing files')),
4706 [('A', 'after', None, _('record delete for missing files')),
4684 ('f', 'force', None,
4707 ('f', 'force', None,
4685 _('remove (and delete) file even if added or modified')),
4708 _('remove (and delete) file even if added or modified')),
4686 ] + walkopts,
4709 ] + walkopts,
4687 _('[OPTION]... FILE...'))
4710 _('[OPTION]... FILE...'))
4688 def remove(ui, repo, *pats, **opts):
4711 def remove(ui, repo, *pats, **opts):
4689 """remove the specified files on the next commit
4712 """remove the specified files on the next commit
4690
4713
4691 Schedule the indicated files for removal from the current branch.
4714 Schedule the indicated files for removal from the current branch.
4692
4715
4693 This command schedules the files to be removed at the next commit.
4716 This command schedules the files to be removed at the next commit.
4694 To undo a remove before that, see :hg:`revert`. To undo added
4717 To undo a remove before that, see :hg:`revert`. To undo added
4695 files, see :hg:`forget`.
4718 files, see :hg:`forget`.
4696
4719
4697 .. container:: verbose
4720 .. container:: verbose
4698
4721
4699 -A/--after can be used to remove only files that have already
4722 -A/--after can be used to remove only files that have already
4700 been deleted, -f/--force can be used to force deletion, and -Af
4723 been deleted, -f/--force can be used to force deletion, and -Af
4701 can be used to remove files from the next revision without
4724 can be used to remove files from the next revision without
4702 deleting them from the working directory.
4725 deleting them from the working directory.
4703
4726
4704 The following table details the behavior of remove for different
4727 The following table details the behavior of remove for different
4705 file states (columns) and option combinations (rows). The file
4728 file states (columns) and option combinations (rows). The file
4706 states are Added [A], Clean [C], Modified [M] and Missing [!]
4729 states are Added [A], Clean [C], Modified [M] and Missing [!]
4707 (as reported by :hg:`status`). The actions are Warn, Remove
4730 (as reported by :hg:`status`). The actions are Warn, Remove
4708 (from branch) and Delete (from disk):
4731 (from branch) and Delete (from disk):
4709
4732
4710 ======= == == == ==
4733 ======= == == == ==
4711 A C M !
4734 A C M !
4712 ======= == == == ==
4735 ======= == == == ==
4713 none W RD W R
4736 none W RD W R
4714 -f R RD RD R
4737 -f R RD RD R
4715 -A W W W R
4738 -A W W W R
4716 -Af R R R R
4739 -Af R R R R
4717 ======= == == == ==
4740 ======= == == == ==
4718
4741
4719 Note that remove never deletes files in Added [A] state from the
4742 Note that remove never deletes files in Added [A] state from the
4720 working directory, not even if option --force is specified.
4743 working directory, not even if option --force is specified.
4721
4744
4722 Returns 0 on success, 1 if any warnings encountered.
4745 Returns 0 on success, 1 if any warnings encountered.
4723 """
4746 """
4724
4747
4725 ret = 0
4748 ret = 0
4726 after, force = opts.get('after'), opts.get('force')
4749 after, force = opts.get('after'), opts.get('force')
4727 if not pats and not after:
4750 if not pats and not after:
4728 raise util.Abort(_('no files specified'))
4751 raise util.Abort(_('no files specified'))
4729
4752
4730 m = scmutil.match(repo[None], pats, opts)
4753 m = scmutil.match(repo[None], pats, opts)
4731 s = repo.status(match=m, clean=True)
4754 s = repo.status(match=m, clean=True)
4732 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4755 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4733
4756
4734 for f in m.files():
4757 for f in m.files():
4735 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4758 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4736 if os.path.exists(m.rel(f)):
4759 if os.path.exists(m.rel(f)):
4737 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4760 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4738 ret = 1
4761 ret = 1
4739
4762
4740 if force:
4763 if force:
4741 list = modified + deleted + clean + added
4764 list = modified + deleted + clean + added
4742 elif after:
4765 elif after:
4743 list = deleted
4766 list = deleted
4744 for f in modified + added + clean:
4767 for f in modified + added + clean:
4745 ui.warn(_('not removing %s: file still exists (use -f'
4768 ui.warn(_('not removing %s: file still exists (use -f'
4746 ' to force removal)\n') % m.rel(f))
4769 ' to force removal)\n') % m.rel(f))
4747 ret = 1
4770 ret = 1
4748 else:
4771 else:
4749 list = deleted + clean
4772 list = deleted + clean
4750 for f in modified:
4773 for f in modified:
4751 ui.warn(_('not removing %s: file is modified (use -f'
4774 ui.warn(_('not removing %s: file is modified (use -f'
4752 ' to force removal)\n') % m.rel(f))
4775 ' to force removal)\n') % m.rel(f))
4753 ret = 1
4776 ret = 1
4754 for f in added:
4777 for f in added:
4755 ui.warn(_('not removing %s: file has been marked for add'
4778 ui.warn(_('not removing %s: file has been marked for add'
4756 ' (use forget to undo)\n') % m.rel(f))
4779 ' (use forget to undo)\n') % m.rel(f))
4757 ret = 1
4780 ret = 1
4758
4781
4759 for f in sorted(list):
4782 for f in sorted(list):
4760 if ui.verbose or not m.exact(f):
4783 if ui.verbose or not m.exact(f):
4761 ui.status(_('removing %s\n') % m.rel(f))
4784 ui.status(_('removing %s\n') % m.rel(f))
4762
4785
4763 wlock = repo.wlock()
4786 wlock = repo.wlock()
4764 try:
4787 try:
4765 if not after:
4788 if not after:
4766 for f in list:
4789 for f in list:
4767 if f in added:
4790 if f in added:
4768 continue # we never unlink added files on remove
4791 continue # we never unlink added files on remove
4769 try:
4792 try:
4770 util.unlinkpath(repo.wjoin(f))
4793 util.unlinkpath(repo.wjoin(f))
4771 except OSError, inst:
4794 except OSError, inst:
4772 if inst.errno != errno.ENOENT:
4795 if inst.errno != errno.ENOENT:
4773 raise
4796 raise
4774 repo[None].forget(list)
4797 repo[None].forget(list)
4775 finally:
4798 finally:
4776 wlock.release()
4799 wlock.release()
4777
4800
4778 return ret
4801 return ret
4779
4802
4780 @command('rename|move|mv',
4803 @command('rename|move|mv',
4781 [('A', 'after', None, _('record a rename that has already occurred')),
4804 [('A', 'after', None, _('record a rename that has already occurred')),
4782 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4805 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4783 ] + walkopts + dryrunopts,
4806 ] + walkopts + dryrunopts,
4784 _('[OPTION]... SOURCE... DEST'))
4807 _('[OPTION]... SOURCE... DEST'))
4785 def rename(ui, repo, *pats, **opts):
4808 def rename(ui, repo, *pats, **opts):
4786 """rename files; equivalent of copy + remove
4809 """rename files; equivalent of copy + remove
4787
4810
4788 Mark dest as copies of sources; mark sources for deletion. If dest
4811 Mark dest as copies of sources; mark sources for deletion. If dest
4789 is a directory, copies are put in that directory. If dest is a
4812 is a directory, copies are put in that directory. If dest is a
4790 file, there can only be one source.
4813 file, there can only be one source.
4791
4814
4792 By default, this command copies the contents of files as they
4815 By default, this command copies the contents of files as they
4793 exist in the working directory. If invoked with -A/--after, the
4816 exist in the working directory. If invoked with -A/--after, the
4794 operation is recorded, but no copying is performed.
4817 operation is recorded, but no copying is performed.
4795
4818
4796 This command takes effect at the next commit. To undo a rename
4819 This command takes effect at the next commit. To undo a rename
4797 before that, see :hg:`revert`.
4820 before that, see :hg:`revert`.
4798
4821
4799 Returns 0 on success, 1 if errors are encountered.
4822 Returns 0 on success, 1 if errors are encountered.
4800 """
4823 """
4801 wlock = repo.wlock(False)
4824 wlock = repo.wlock(False)
4802 try:
4825 try:
4803 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4826 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4804 finally:
4827 finally:
4805 wlock.release()
4828 wlock.release()
4806
4829
4807 @command('resolve',
4830 @command('resolve',
4808 [('a', 'all', None, _('select all unresolved files')),
4831 [('a', 'all', None, _('select all unresolved files')),
4809 ('l', 'list', None, _('list state of files needing merge')),
4832 ('l', 'list', None, _('list state of files needing merge')),
4810 ('m', 'mark', None, _('mark files as resolved')),
4833 ('m', 'mark', None, _('mark files as resolved')),
4811 ('u', 'unmark', None, _('mark files as unresolved')),
4834 ('u', 'unmark', None, _('mark files as unresolved')),
4812 ('n', 'no-status', None, _('hide status prefix'))]
4835 ('n', 'no-status', None, _('hide status prefix'))]
4813 + mergetoolopts + walkopts,
4836 + mergetoolopts + walkopts,
4814 _('[OPTION]... [FILE]...'))
4837 _('[OPTION]... [FILE]...'))
4815 def resolve(ui, repo, *pats, **opts):
4838 def resolve(ui, repo, *pats, **opts):
4816 """redo merges or set/view the merge status of files
4839 """redo merges or set/view the merge status of files
4817
4840
4818 Merges with unresolved conflicts are often the result of
4841 Merges with unresolved conflicts are often the result of
4819 non-interactive merging using the ``internal:merge`` configuration
4842 non-interactive merging using the ``internal:merge`` configuration
4820 setting, or a command-line merge tool like ``diff3``. The resolve
4843 setting, or a command-line merge tool like ``diff3``. The resolve
4821 command is used to manage the files involved in a merge, after
4844 command is used to manage the files involved in a merge, after
4822 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4845 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4823 working directory must have two parents). See :hg:`help
4846 working directory must have two parents). See :hg:`help
4824 merge-tools` for information on configuring merge tools.
4847 merge-tools` for information on configuring merge tools.
4825
4848
4826 The resolve command can be used in the following ways:
4849 The resolve command can be used in the following ways:
4827
4850
4828 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4851 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4829 files, discarding any previous merge attempts. Re-merging is not
4852 files, discarding any previous merge attempts. Re-merging is not
4830 performed for files already marked as resolved. Use ``--all/-a``
4853 performed for files already marked as resolved. Use ``--all/-a``
4831 to select all unresolved files. ``--tool`` can be used to specify
4854 to select all unresolved files. ``--tool`` can be used to specify
4832 the merge tool used for the given files. It overrides the HGMERGE
4855 the merge tool used for the given files. It overrides the HGMERGE
4833 environment variable and your configuration files. Previous file
4856 environment variable and your configuration files. Previous file
4834 contents are saved with a ``.orig`` suffix.
4857 contents are saved with a ``.orig`` suffix.
4835
4858
4836 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4859 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4837 (e.g. after having manually fixed-up the files). The default is
4860 (e.g. after having manually fixed-up the files). The default is
4838 to mark all unresolved files.
4861 to mark all unresolved files.
4839
4862
4840 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4863 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4841 default is to mark all resolved files.
4864 default is to mark all resolved files.
4842
4865
4843 - :hg:`resolve -l`: list files which had or still have conflicts.
4866 - :hg:`resolve -l`: list files which had or still have conflicts.
4844 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4867 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4845
4868
4846 Note that Mercurial will not let you commit files with unresolved
4869 Note that Mercurial will not let you commit files with unresolved
4847 merge conflicts. You must use :hg:`resolve -m ...` before you can
4870 merge conflicts. You must use :hg:`resolve -m ...` before you can
4848 commit after a conflicting merge.
4871 commit after a conflicting merge.
4849
4872
4850 Returns 0 on success, 1 if any files fail a resolve attempt.
4873 Returns 0 on success, 1 if any files fail a resolve attempt.
4851 """
4874 """
4852
4875
4853 all, mark, unmark, show, nostatus = \
4876 all, mark, unmark, show, nostatus = \
4854 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4877 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4855
4878
4856 if (show and (mark or unmark)) or (mark and unmark):
4879 if (show and (mark or unmark)) or (mark and unmark):
4857 raise util.Abort(_("too many options specified"))
4880 raise util.Abort(_("too many options specified"))
4858 if pats and all:
4881 if pats and all:
4859 raise util.Abort(_("can't specify --all and patterns"))
4882 raise util.Abort(_("can't specify --all and patterns"))
4860 if not (all or pats or show or mark or unmark):
4883 if not (all or pats or show or mark or unmark):
4861 raise util.Abort(_('no files or directories specified; '
4884 raise util.Abort(_('no files or directories specified; '
4862 'use --all to remerge all files'))
4885 'use --all to remerge all files'))
4863
4886
4864 ms = mergemod.mergestate(repo)
4887 ms = mergemod.mergestate(repo)
4865 m = scmutil.match(repo[None], pats, opts)
4888 m = scmutil.match(repo[None], pats, opts)
4866 ret = 0
4889 ret = 0
4867
4890
4868 for f in ms:
4891 for f in ms:
4869 if m(f):
4892 if m(f):
4870 if show:
4893 if show:
4871 if nostatus:
4894 if nostatus:
4872 ui.write("%s\n" % f)
4895 ui.write("%s\n" % f)
4873 else:
4896 else:
4874 ui.write("%s %s\n" % (ms[f].upper(), f),
4897 ui.write("%s %s\n" % (ms[f].upper(), f),
4875 label='resolve.' +
4898 label='resolve.' +
4876 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4899 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4877 elif mark:
4900 elif mark:
4878 ms.mark(f, "r")
4901 ms.mark(f, "r")
4879 elif unmark:
4902 elif unmark:
4880 ms.mark(f, "u")
4903 ms.mark(f, "u")
4881 else:
4904 else:
4882 wctx = repo[None]
4905 wctx = repo[None]
4883 mctx = wctx.parents()[-1]
4906 mctx = wctx.parents()[-1]
4884
4907
4885 # backup pre-resolve (merge uses .orig for its own purposes)
4908 # backup pre-resolve (merge uses .orig for its own purposes)
4886 a = repo.wjoin(f)
4909 a = repo.wjoin(f)
4887 util.copyfile(a, a + ".resolve")
4910 util.copyfile(a, a + ".resolve")
4888
4911
4889 try:
4912 try:
4890 # resolve file
4913 # resolve file
4891 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4914 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4892 if ms.resolve(f, wctx, mctx):
4915 if ms.resolve(f, wctx, mctx):
4893 ret = 1
4916 ret = 1
4894 finally:
4917 finally:
4895 ui.setconfig('ui', 'forcemerge', '')
4918 ui.setconfig('ui', 'forcemerge', '')
4896
4919
4897 # replace filemerge's .orig file with our resolve file
4920 # replace filemerge's .orig file with our resolve file
4898 util.rename(a + ".resolve", a + ".orig")
4921 util.rename(a + ".resolve", a + ".orig")
4899
4922
4900 ms.commit()
4923 ms.commit()
4901 return ret
4924 return ret
4902
4925
4903 @command('revert',
4926 @command('revert',
4904 [('a', 'all', None, _('revert all changes when no arguments given')),
4927 [('a', 'all', None, _('revert all changes when no arguments given')),
4905 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4928 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4906 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4929 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4907 ('C', 'no-backup', None, _('do not save backup copies of files')),
4930 ('C', 'no-backup', None, _('do not save backup copies of files')),
4908 ] + walkopts + dryrunopts,
4931 ] + walkopts + dryrunopts,
4909 _('[OPTION]... [-r REV] [NAME]...'))
4932 _('[OPTION]... [-r REV] [NAME]...'))
4910 def revert(ui, repo, *pats, **opts):
4933 def revert(ui, repo, *pats, **opts):
4911 """restore files to their checkout state
4934 """restore files to their checkout state
4912
4935
4913 .. note::
4936 .. note::
4914
4937
4915 To check out earlier revisions, you should use :hg:`update REV`.
4938 To check out earlier revisions, you should use :hg:`update REV`.
4916 To cancel an uncommitted merge (and lose your changes), use
4939 To cancel an uncommitted merge (and lose your changes), use
4917 :hg:`update --clean .`.
4940 :hg:`update --clean .`.
4918
4941
4919 With no revision specified, revert the specified files or directories
4942 With no revision specified, revert the specified files or directories
4920 to the contents they had in the parent of the working directory.
4943 to the contents they had in the parent of the working directory.
4921 This restores the contents of files to an unmodified
4944 This restores the contents of files to an unmodified
4922 state and unschedules adds, removes, copies, and renames. If the
4945 state and unschedules adds, removes, copies, and renames. If the
4923 working directory has two parents, you must explicitly specify a
4946 working directory has two parents, you must explicitly specify a
4924 revision.
4947 revision.
4925
4948
4926 Using the -r/--rev or -d/--date options, revert the given files or
4949 Using the -r/--rev or -d/--date options, revert the given files or
4927 directories to their states as of a specific revision. Because
4950 directories to their states as of a specific revision. Because
4928 revert does not change the working directory parents, this will
4951 revert does not change the working directory parents, this will
4929 cause these files to appear modified. This can be helpful to "back
4952 cause these files to appear modified. This can be helpful to "back
4930 out" some or all of an earlier change. See :hg:`backout` for a
4953 out" some or all of an earlier change. See :hg:`backout` for a
4931 related method.
4954 related method.
4932
4955
4933 Modified files are saved with a .orig suffix before reverting.
4956 Modified files are saved with a .orig suffix before reverting.
4934 To disable these backups, use --no-backup.
4957 To disable these backups, use --no-backup.
4935
4958
4936 See :hg:`help dates` for a list of formats valid for -d/--date.
4959 See :hg:`help dates` for a list of formats valid for -d/--date.
4937
4960
4938 Returns 0 on success.
4961 Returns 0 on success.
4939 """
4962 """
4940
4963
4941 if opts.get("date"):
4964 if opts.get("date"):
4942 if opts.get("rev"):
4965 if opts.get("rev"):
4943 raise util.Abort(_("you can't specify a revision and a date"))
4966 raise util.Abort(_("you can't specify a revision and a date"))
4944 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4967 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4945
4968
4946 parent, p2 = repo.dirstate.parents()
4969 parent, p2 = repo.dirstate.parents()
4947 if not opts.get('rev') and p2 != nullid:
4970 if not opts.get('rev') and p2 != nullid:
4948 # revert after merge is a trap for new users (issue2915)
4971 # revert after merge is a trap for new users (issue2915)
4949 raise util.Abort(_('uncommitted merge with no revision specified'),
4972 raise util.Abort(_('uncommitted merge with no revision specified'),
4950 hint=_('use "hg update" or see "hg help revert"'))
4973 hint=_('use "hg update" or see "hg help revert"'))
4951
4974
4952 ctx = scmutil.revsingle(repo, opts.get('rev'))
4975 ctx = scmutil.revsingle(repo, opts.get('rev'))
4953
4976
4954 if not pats and not opts.get('all'):
4977 if not pats and not opts.get('all'):
4955 msg = _("no files or directories specified")
4978 msg = _("no files or directories specified")
4956 if p2 != nullid:
4979 if p2 != nullid:
4957 hint = _("uncommitted merge, use --all to discard all changes,"
4980 hint = _("uncommitted merge, use --all to discard all changes,"
4958 " or 'hg update -C .' to abort the merge")
4981 " or 'hg update -C .' to abort the merge")
4959 raise util.Abort(msg, hint=hint)
4982 raise util.Abort(msg, hint=hint)
4960 dirty = util.any(repo.status())
4983 dirty = util.any(repo.status())
4961 node = ctx.node()
4984 node = ctx.node()
4962 if node != parent:
4985 if node != parent:
4963 if dirty:
4986 if dirty:
4964 hint = _("uncommitted changes, use --all to discard all"
4987 hint = _("uncommitted changes, use --all to discard all"
4965 " changes, or 'hg update %s' to update") % ctx.rev()
4988 " changes, or 'hg update %s' to update") % ctx.rev()
4966 else:
4989 else:
4967 hint = _("use --all to revert all files,"
4990 hint = _("use --all to revert all files,"
4968 " or 'hg update %s' to update") % ctx.rev()
4991 " or 'hg update %s' to update") % ctx.rev()
4969 elif dirty:
4992 elif dirty:
4970 hint = _("uncommitted changes, use --all to discard all changes")
4993 hint = _("uncommitted changes, use --all to discard all changes")
4971 else:
4994 else:
4972 hint = _("use --all to revert all files")
4995 hint = _("use --all to revert all files")
4973 raise util.Abort(msg, hint=hint)
4996 raise util.Abort(msg, hint=hint)
4974
4997
4975 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4998 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4976
4999
4977 @command('rollback', dryrunopts +
5000 @command('rollback', dryrunopts +
4978 [('f', 'force', False, _('ignore safety measures'))])
5001 [('f', 'force', False, _('ignore safety measures'))])
4979 def rollback(ui, repo, **opts):
5002 def rollback(ui, repo, **opts):
4980 """roll back the last transaction (dangerous)
5003 """roll back the last transaction (dangerous)
4981
5004
4982 This command should be used with care. There is only one level of
5005 This command should be used with care. There is only one level of
4983 rollback, and there is no way to undo a rollback. It will also
5006 rollback, and there is no way to undo a rollback. It will also
4984 restore the dirstate at the time of the last transaction, losing
5007 restore the dirstate at the time of the last transaction, losing
4985 any dirstate changes since that time. This command does not alter
5008 any dirstate changes since that time. This command does not alter
4986 the working directory.
5009 the working directory.
4987
5010
4988 Transactions are used to encapsulate the effects of all commands
5011 Transactions are used to encapsulate the effects of all commands
4989 that create new changesets or propagate existing changesets into a
5012 that create new changesets or propagate existing changesets into a
4990 repository.
5013 repository.
4991
5014
4992 .. container:: verbose
5015 .. container:: verbose
4993
5016
4994 For example, the following commands are transactional, and their
5017 For example, the following commands are transactional, and their
4995 effects can be rolled back:
5018 effects can be rolled back:
4996
5019
4997 - commit
5020 - commit
4998 - import
5021 - import
4999 - pull
5022 - pull
5000 - push (with this repository as the destination)
5023 - push (with this repository as the destination)
5001 - unbundle
5024 - unbundle
5002
5025
5003 To avoid permanent data loss, rollback will refuse to rollback a
5026 To avoid permanent data loss, rollback will refuse to rollback a
5004 commit transaction if it isn't checked out. Use --force to
5027 commit transaction if it isn't checked out. Use --force to
5005 override this protection.
5028 override this protection.
5006
5029
5007 This command is not intended for use on public repositories. Once
5030 This command is not intended for use on public repositories. Once
5008 changes are visible for pull by other users, rolling a transaction
5031 changes are visible for pull by other users, rolling a transaction
5009 back locally is ineffective (someone else may already have pulled
5032 back locally is ineffective (someone else may already have pulled
5010 the changes). Furthermore, a race is possible with readers of the
5033 the changes). Furthermore, a race is possible with readers of the
5011 repository; for example an in-progress pull from the repository
5034 repository; for example an in-progress pull from the repository
5012 may fail if a rollback is performed.
5035 may fail if a rollback is performed.
5013
5036
5014 Returns 0 on success, 1 if no rollback data is available.
5037 Returns 0 on success, 1 if no rollback data is available.
5015 """
5038 """
5016 return repo.rollback(dryrun=opts.get('dry_run'),
5039 return repo.rollback(dryrun=opts.get('dry_run'),
5017 force=opts.get('force'))
5040 force=opts.get('force'))
5018
5041
5019 @command('root', [])
5042 @command('root', [])
5020 def root(ui, repo):
5043 def root(ui, repo):
5021 """print the root (top) of the current working directory
5044 """print the root (top) of the current working directory
5022
5045
5023 Print the root directory of the current repository.
5046 Print the root directory of the current repository.
5024
5047
5025 Returns 0 on success.
5048 Returns 0 on success.
5026 """
5049 """
5027 ui.write(repo.root + "\n")
5050 ui.write(repo.root + "\n")
5028
5051
5029 @command('^serve',
5052 @command('^serve',
5030 [('A', 'accesslog', '', _('name of access log file to write to'),
5053 [('A', 'accesslog', '', _('name of access log file to write to'),
5031 _('FILE')),
5054 _('FILE')),
5032 ('d', 'daemon', None, _('run server in background')),
5055 ('d', 'daemon', None, _('run server in background')),
5033 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5056 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5034 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5057 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5035 # use string type, then we can check if something was passed
5058 # use string type, then we can check if something was passed
5036 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5059 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5037 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5060 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5038 _('ADDR')),
5061 _('ADDR')),
5039 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5062 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5040 _('PREFIX')),
5063 _('PREFIX')),
5041 ('n', 'name', '',
5064 ('n', 'name', '',
5042 _('name to show in web pages (default: working directory)'), _('NAME')),
5065 _('name to show in web pages (default: working directory)'), _('NAME')),
5043 ('', 'web-conf', '',
5066 ('', 'web-conf', '',
5044 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5067 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5045 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5068 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5046 _('FILE')),
5069 _('FILE')),
5047 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5070 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5048 ('', 'stdio', None, _('for remote clients')),
5071 ('', 'stdio', None, _('for remote clients')),
5049 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5072 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5050 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5073 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5051 ('', 'style', '', _('template style to use'), _('STYLE')),
5074 ('', 'style', '', _('template style to use'), _('STYLE')),
5052 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5075 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5053 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5076 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5054 _('[OPTION]...'))
5077 _('[OPTION]...'))
5055 def serve(ui, repo, **opts):
5078 def serve(ui, repo, **opts):
5056 """start stand-alone webserver
5079 """start stand-alone webserver
5057
5080
5058 Start a local HTTP repository browser and pull server. You can use
5081 Start a local HTTP repository browser and pull server. You can use
5059 this for ad-hoc sharing and browsing of repositories. It is
5082 this for ad-hoc sharing and browsing of repositories. It is
5060 recommended to use a real web server to serve a repository for
5083 recommended to use a real web server to serve a repository for
5061 longer periods of time.
5084 longer periods of time.
5062
5085
5063 Please note that the server does not implement access control.
5086 Please note that the server does not implement access control.
5064 This means that, by default, anybody can read from the server and
5087 This means that, by default, anybody can read from the server and
5065 nobody can write to it by default. Set the ``web.allow_push``
5088 nobody can write to it by default. Set the ``web.allow_push``
5066 option to ``*`` to allow everybody to push to the server. You
5089 option to ``*`` to allow everybody to push to the server. You
5067 should use a real web server if you need to authenticate users.
5090 should use a real web server if you need to authenticate users.
5068
5091
5069 By default, the server logs accesses to stdout and errors to
5092 By default, the server logs accesses to stdout and errors to
5070 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5093 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5071 files.
5094 files.
5072
5095
5073 To have the server choose a free port number to listen on, specify
5096 To have the server choose a free port number to listen on, specify
5074 a port number of 0; in this case, the server will print the port
5097 a port number of 0; in this case, the server will print the port
5075 number it uses.
5098 number it uses.
5076
5099
5077 Returns 0 on success.
5100 Returns 0 on success.
5078 """
5101 """
5079
5102
5080 if opts["stdio"] and opts["cmdserver"]:
5103 if opts["stdio"] and opts["cmdserver"]:
5081 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5104 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5082
5105
5083 def checkrepo():
5106 def checkrepo():
5084 if repo is None:
5107 if repo is None:
5085 raise error.RepoError(_("there is no Mercurial repository here"
5108 raise error.RepoError(_("there is no Mercurial repository here"
5086 " (.hg not found)"))
5109 " (.hg not found)"))
5087
5110
5088 if opts["stdio"]:
5111 if opts["stdio"]:
5089 checkrepo()
5112 checkrepo()
5090 s = sshserver.sshserver(ui, repo)
5113 s = sshserver.sshserver(ui, repo)
5091 s.serve_forever()
5114 s.serve_forever()
5092
5115
5093 if opts["cmdserver"]:
5116 if opts["cmdserver"]:
5094 checkrepo()
5117 checkrepo()
5095 s = commandserver.server(ui, repo, opts["cmdserver"])
5118 s = commandserver.server(ui, repo, opts["cmdserver"])
5096 return s.serve()
5119 return s.serve()
5097
5120
5098 # this way we can check if something was given in the command-line
5121 # this way we can check if something was given in the command-line
5099 if opts.get('port'):
5122 if opts.get('port'):
5100 opts['port'] = util.getport(opts.get('port'))
5123 opts['port'] = util.getport(opts.get('port'))
5101
5124
5102 baseui = repo and repo.baseui or ui
5125 baseui = repo and repo.baseui or ui
5103 optlist = ("name templates style address port prefix ipv6"
5126 optlist = ("name templates style address port prefix ipv6"
5104 " accesslog errorlog certificate encoding")
5127 " accesslog errorlog certificate encoding")
5105 for o in optlist.split():
5128 for o in optlist.split():
5106 val = opts.get(o, '')
5129 val = opts.get(o, '')
5107 if val in (None, ''): # should check against default options instead
5130 if val in (None, ''): # should check against default options instead
5108 continue
5131 continue
5109 baseui.setconfig("web", o, val)
5132 baseui.setconfig("web", o, val)
5110 if repo and repo.ui != baseui:
5133 if repo and repo.ui != baseui:
5111 repo.ui.setconfig("web", o, val)
5134 repo.ui.setconfig("web", o, val)
5112
5135
5113 o = opts.get('web_conf') or opts.get('webdir_conf')
5136 o = opts.get('web_conf') or opts.get('webdir_conf')
5114 if not o:
5137 if not o:
5115 if not repo:
5138 if not repo:
5116 raise error.RepoError(_("there is no Mercurial repository"
5139 raise error.RepoError(_("there is no Mercurial repository"
5117 " here (.hg not found)"))
5140 " here (.hg not found)"))
5118 o = repo.root
5141 o = repo.root
5119
5142
5120 app = hgweb.hgweb(o, baseui=ui)
5143 app = hgweb.hgweb(o, baseui=ui)
5121
5144
5122 class service(object):
5145 class service(object):
5123 def init(self):
5146 def init(self):
5124 util.setsignalhandler()
5147 util.setsignalhandler()
5125 self.httpd = hgweb.server.create_server(ui, app)
5148 self.httpd = hgweb.server.create_server(ui, app)
5126
5149
5127 if opts['port'] and not ui.verbose:
5150 if opts['port'] and not ui.verbose:
5128 return
5151 return
5129
5152
5130 if self.httpd.prefix:
5153 if self.httpd.prefix:
5131 prefix = self.httpd.prefix.strip('/') + '/'
5154 prefix = self.httpd.prefix.strip('/') + '/'
5132 else:
5155 else:
5133 prefix = ''
5156 prefix = ''
5134
5157
5135 port = ':%d' % self.httpd.port
5158 port = ':%d' % self.httpd.port
5136 if port == ':80':
5159 if port == ':80':
5137 port = ''
5160 port = ''
5138
5161
5139 bindaddr = self.httpd.addr
5162 bindaddr = self.httpd.addr
5140 if bindaddr == '0.0.0.0':
5163 if bindaddr == '0.0.0.0':
5141 bindaddr = '*'
5164 bindaddr = '*'
5142 elif ':' in bindaddr: # IPv6
5165 elif ':' in bindaddr: # IPv6
5143 bindaddr = '[%s]' % bindaddr
5166 bindaddr = '[%s]' % bindaddr
5144
5167
5145 fqaddr = self.httpd.fqaddr
5168 fqaddr = self.httpd.fqaddr
5146 if ':' in fqaddr:
5169 if ':' in fqaddr:
5147 fqaddr = '[%s]' % fqaddr
5170 fqaddr = '[%s]' % fqaddr
5148 if opts['port']:
5171 if opts['port']:
5149 write = ui.status
5172 write = ui.status
5150 else:
5173 else:
5151 write = ui.write
5174 write = ui.write
5152 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5175 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5153 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5176 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5154
5177
5155 def run(self):
5178 def run(self):
5156 self.httpd.serve_forever()
5179 self.httpd.serve_forever()
5157
5180
5158 service = service()
5181 service = service()
5159
5182
5160 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5183 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5161
5184
5162 @command('showconfig|debugconfig',
5185 @command('showconfig|debugconfig',
5163 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5186 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5164 _('[-u] [NAME]...'))
5187 _('[-u] [NAME]...'))
5165 def showconfig(ui, repo, *values, **opts):
5188 def showconfig(ui, repo, *values, **opts):
5166 """show combined config settings from all hgrc files
5189 """show combined config settings from all hgrc files
5167
5190
5168 With no arguments, print names and values of all config items.
5191 With no arguments, print names and values of all config items.
5169
5192
5170 With one argument of the form section.name, print just the value
5193 With one argument of the form section.name, print just the value
5171 of that config item.
5194 of that config item.
5172
5195
5173 With multiple arguments, print names and values of all config
5196 With multiple arguments, print names and values of all config
5174 items with matching section names.
5197 items with matching section names.
5175
5198
5176 With --debug, the source (filename and line number) is printed
5199 With --debug, the source (filename and line number) is printed
5177 for each config item.
5200 for each config item.
5178
5201
5179 Returns 0 on success.
5202 Returns 0 on success.
5180 """
5203 """
5181
5204
5182 for f in scmutil.rcpath():
5205 for f in scmutil.rcpath():
5183 ui.debug('read config from: %s\n' % f)
5206 ui.debug('read config from: %s\n' % f)
5184 untrusted = bool(opts.get('untrusted'))
5207 untrusted = bool(opts.get('untrusted'))
5185 if values:
5208 if values:
5186 sections = [v for v in values if '.' not in v]
5209 sections = [v for v in values if '.' not in v]
5187 items = [v for v in values if '.' in v]
5210 items = [v for v in values if '.' in v]
5188 if len(items) > 1 or items and sections:
5211 if len(items) > 1 or items and sections:
5189 raise util.Abort(_('only one config item permitted'))
5212 raise util.Abort(_('only one config item permitted'))
5190 for section, name, value in ui.walkconfig(untrusted=untrusted):
5213 for section, name, value in ui.walkconfig(untrusted=untrusted):
5191 value = str(value).replace('\n', '\\n')
5214 value = str(value).replace('\n', '\\n')
5192 sectname = section + '.' + name
5215 sectname = section + '.' + name
5193 if values:
5216 if values:
5194 for v in values:
5217 for v in values:
5195 if v == section:
5218 if v == section:
5196 ui.debug('%s: ' %
5219 ui.debug('%s: ' %
5197 ui.configsource(section, name, untrusted))
5220 ui.configsource(section, name, untrusted))
5198 ui.write('%s=%s\n' % (sectname, value))
5221 ui.write('%s=%s\n' % (sectname, value))
5199 elif v == sectname:
5222 elif v == sectname:
5200 ui.debug('%s: ' %
5223 ui.debug('%s: ' %
5201 ui.configsource(section, name, untrusted))
5224 ui.configsource(section, name, untrusted))
5202 ui.write(value, '\n')
5225 ui.write(value, '\n')
5203 else:
5226 else:
5204 ui.debug('%s: ' %
5227 ui.debug('%s: ' %
5205 ui.configsource(section, name, untrusted))
5228 ui.configsource(section, name, untrusted))
5206 ui.write('%s=%s\n' % (sectname, value))
5229 ui.write('%s=%s\n' % (sectname, value))
5207
5230
5208 @command('^status|st',
5231 @command('^status|st',
5209 [('A', 'all', None, _('show status of all files')),
5232 [('A', 'all', None, _('show status of all files')),
5210 ('m', 'modified', None, _('show only modified files')),
5233 ('m', 'modified', None, _('show only modified files')),
5211 ('a', 'added', None, _('show only added files')),
5234 ('a', 'added', None, _('show only added files')),
5212 ('r', 'removed', None, _('show only removed files')),
5235 ('r', 'removed', None, _('show only removed files')),
5213 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5236 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5214 ('c', 'clean', None, _('show only files without changes')),
5237 ('c', 'clean', None, _('show only files without changes')),
5215 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5238 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5216 ('i', 'ignored', None, _('show only ignored files')),
5239 ('i', 'ignored', None, _('show only ignored files')),
5217 ('n', 'no-status', None, _('hide status prefix')),
5240 ('n', 'no-status', None, _('hide status prefix')),
5218 ('C', 'copies', None, _('show source of copied files')),
5241 ('C', 'copies', None, _('show source of copied files')),
5219 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5242 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5220 ('', 'rev', [], _('show difference from revision'), _('REV')),
5243 ('', 'rev', [], _('show difference from revision'), _('REV')),
5221 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5244 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5222 ] + walkopts + subrepoopts,
5245 ] + walkopts + subrepoopts,
5223 _('[OPTION]... [FILE]...'))
5246 _('[OPTION]... [FILE]...'))
5224 def status(ui, repo, *pats, **opts):
5247 def status(ui, repo, *pats, **opts):
5225 """show changed files in the working directory
5248 """show changed files in the working directory
5226
5249
5227 Show status of files in the repository. If names are given, only
5250 Show status of files in the repository. If names are given, only
5228 files that match are shown. Files that are clean or ignored or
5251 files that match are shown. Files that are clean or ignored or
5229 the source of a copy/move operation, are not listed unless
5252 the source of a copy/move operation, are not listed unless
5230 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5253 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5231 Unless options described with "show only ..." are given, the
5254 Unless options described with "show only ..." are given, the
5232 options -mardu are used.
5255 options -mardu are used.
5233
5256
5234 Option -q/--quiet hides untracked (unknown and ignored) files
5257 Option -q/--quiet hides untracked (unknown and ignored) files
5235 unless explicitly requested with -u/--unknown or -i/--ignored.
5258 unless explicitly requested with -u/--unknown or -i/--ignored.
5236
5259
5237 .. note::
5260 .. note::
5238 status may appear to disagree with diff if permissions have
5261 status may appear to disagree with diff if permissions have
5239 changed or a merge has occurred. The standard diff format does
5262 changed or a merge has occurred. The standard diff format does
5240 not report permission changes and diff only reports changes
5263 not report permission changes and diff only reports changes
5241 relative to one merge parent.
5264 relative to one merge parent.
5242
5265
5243 If one revision is given, it is used as the base revision.
5266 If one revision is given, it is used as the base revision.
5244 If two revisions are given, the differences between them are
5267 If two revisions are given, the differences between them are
5245 shown. The --change option can also be used as a shortcut to list
5268 shown. The --change option can also be used as a shortcut to list
5246 the changed files of a revision from its first parent.
5269 the changed files of a revision from its first parent.
5247
5270
5248 The codes used to show the status of files are::
5271 The codes used to show the status of files are::
5249
5272
5250 M = modified
5273 M = modified
5251 A = added
5274 A = added
5252 R = removed
5275 R = removed
5253 C = clean
5276 C = clean
5254 ! = missing (deleted by non-hg command, but still tracked)
5277 ! = missing (deleted by non-hg command, but still tracked)
5255 ? = not tracked
5278 ? = not tracked
5256 I = ignored
5279 I = ignored
5257 = origin of the previous file listed as A (added)
5280 = origin of the previous file listed as A (added)
5258
5281
5259 .. container:: verbose
5282 .. container:: verbose
5260
5283
5261 Examples:
5284 Examples:
5262
5285
5263 - show changes in the working directory relative to a
5286 - show changes in the working directory relative to a
5264 changeset::
5287 changeset::
5265
5288
5266 hg status --rev 9353
5289 hg status --rev 9353
5267
5290
5268 - show all changes including copies in an existing changeset::
5291 - show all changes including copies in an existing changeset::
5269
5292
5270 hg status --copies --change 9353
5293 hg status --copies --change 9353
5271
5294
5272 - get a NUL separated list of added files, suitable for xargs::
5295 - get a NUL separated list of added files, suitable for xargs::
5273
5296
5274 hg status -an0
5297 hg status -an0
5275
5298
5276 Returns 0 on success.
5299 Returns 0 on success.
5277 """
5300 """
5278
5301
5279 revs = opts.get('rev')
5302 revs = opts.get('rev')
5280 change = opts.get('change')
5303 change = opts.get('change')
5281
5304
5282 if revs and change:
5305 if revs and change:
5283 msg = _('cannot specify --rev and --change at the same time')
5306 msg = _('cannot specify --rev and --change at the same time')
5284 raise util.Abort(msg)
5307 raise util.Abort(msg)
5285 elif change:
5308 elif change:
5286 node2 = scmutil.revsingle(repo, change, None).node()
5309 node2 = scmutil.revsingle(repo, change, None).node()
5287 node1 = repo[node2].p1().node()
5310 node1 = repo[node2].p1().node()
5288 else:
5311 else:
5289 node1, node2 = scmutil.revpair(repo, revs)
5312 node1, node2 = scmutil.revpair(repo, revs)
5290
5313
5291 cwd = (pats and repo.getcwd()) or ''
5314 cwd = (pats and repo.getcwd()) or ''
5292 end = opts.get('print0') and '\0' or '\n'
5315 end = opts.get('print0') and '\0' or '\n'
5293 copy = {}
5316 copy = {}
5294 states = 'modified added removed deleted unknown ignored clean'.split()
5317 states = 'modified added removed deleted unknown ignored clean'.split()
5295 show = [k for k in states if opts.get(k)]
5318 show = [k for k in states if opts.get(k)]
5296 if opts.get('all'):
5319 if opts.get('all'):
5297 show += ui.quiet and (states[:4] + ['clean']) or states
5320 show += ui.quiet and (states[:4] + ['clean']) or states
5298 if not show:
5321 if not show:
5299 show = ui.quiet and states[:4] or states[:5]
5322 show = ui.quiet and states[:4] or states[:5]
5300
5323
5301 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5324 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5302 'ignored' in show, 'clean' in show, 'unknown' in show,
5325 'ignored' in show, 'clean' in show, 'unknown' in show,
5303 opts.get('subrepos'))
5326 opts.get('subrepos'))
5304 changestates = zip(states, 'MAR!?IC', stat)
5327 changestates = zip(states, 'MAR!?IC', stat)
5305
5328
5306 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5329 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5307 copy = copies.pathcopies(repo[node1], repo[node2])
5330 copy = copies.pathcopies(repo[node1], repo[node2])
5308
5331
5309 fm = ui.formatter('status', opts)
5332 fm = ui.formatter('status', opts)
5310 format = '%s %s' + end
5333 format = '%s %s' + end
5311 if opts.get('no_status'):
5334 if opts.get('no_status'):
5312 format = '%.0s%s' + end
5335 format = '%.0s%s' + end
5313
5336
5314 for state, char, files in changestates:
5337 for state, char, files in changestates:
5315 if state in show:
5338 if state in show:
5316 label = 'status.' + state
5339 label = 'status.' + state
5317 for f in files:
5340 for f in files:
5318 fm.startitem()
5341 fm.startitem()
5319 fm.write("status path", format, char,
5342 fm.write("status path", format, char,
5320 repo.pathto(f, cwd), label=label)
5343 repo.pathto(f, cwd), label=label)
5321 if f in copy:
5344 if f in copy:
5322 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5345 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5323 label='status.copied')
5346 label='status.copied')
5324 fm.end()
5347 fm.end()
5325
5348
5326 @command('^summary|sum',
5349 @command('^summary|sum',
5327 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5350 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5328 def summary(ui, repo, **opts):
5351 def summary(ui, repo, **opts):
5329 """summarize working directory state
5352 """summarize working directory state
5330
5353
5331 This generates a brief summary of the working directory state,
5354 This generates a brief summary of the working directory state,
5332 including parents, branch, commit status, and available updates.
5355 including parents, branch, commit status, and available updates.
5333
5356
5334 With the --remote option, this will check the default paths for
5357 With the --remote option, this will check the default paths for
5335 incoming and outgoing changes. This can be time-consuming.
5358 incoming and outgoing changes. This can be time-consuming.
5336
5359
5337 Returns 0 on success.
5360 Returns 0 on success.
5338 """
5361 """
5339
5362
5340 ctx = repo[None]
5363 ctx = repo[None]
5341 parents = ctx.parents()
5364 parents = ctx.parents()
5342 pnode = parents[0].node()
5365 pnode = parents[0].node()
5343 marks = []
5366 marks = []
5344
5367
5345 for p in parents:
5368 for p in parents:
5346 # label with log.changeset (instead of log.parent) since this
5369 # label with log.changeset (instead of log.parent) since this
5347 # shows a working directory parent *changeset*:
5370 # shows a working directory parent *changeset*:
5348 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5371 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5349 label='log.changeset')
5372 label='log.changeset')
5350 ui.write(' '.join(p.tags()), label='log.tag')
5373 ui.write(' '.join(p.tags()), label='log.tag')
5351 if p.bookmarks():
5374 if p.bookmarks():
5352 marks.extend(p.bookmarks())
5375 marks.extend(p.bookmarks())
5353 if p.rev() == -1:
5376 if p.rev() == -1:
5354 if not len(repo):
5377 if not len(repo):
5355 ui.write(_(' (empty repository)'))
5378 ui.write(_(' (empty repository)'))
5356 else:
5379 else:
5357 ui.write(_(' (no revision checked out)'))
5380 ui.write(_(' (no revision checked out)'))
5358 ui.write('\n')
5381 ui.write('\n')
5359 if p.description():
5382 if p.description():
5360 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5383 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5361 label='log.summary')
5384 label='log.summary')
5362
5385
5363 branch = ctx.branch()
5386 branch = ctx.branch()
5364 bheads = repo.branchheads(branch)
5387 bheads = repo.branchheads(branch)
5365 m = _('branch: %s\n') % branch
5388 m = _('branch: %s\n') % branch
5366 if branch != 'default':
5389 if branch != 'default':
5367 ui.write(m, label='log.branch')
5390 ui.write(m, label='log.branch')
5368 else:
5391 else:
5369 ui.status(m, label='log.branch')
5392 ui.status(m, label='log.branch')
5370
5393
5371 if marks:
5394 if marks:
5372 current = repo._bookmarkcurrent
5395 current = repo._bookmarkcurrent
5373 ui.write(_('bookmarks:'), label='log.bookmark')
5396 ui.write(_('bookmarks:'), label='log.bookmark')
5374 if current is not None:
5397 if current is not None:
5375 try:
5398 try:
5376 marks.remove(current)
5399 marks.remove(current)
5377 ui.write(' *' + current, label='bookmarks.current')
5400 ui.write(' *' + current, label='bookmarks.current')
5378 except ValueError:
5401 except ValueError:
5379 # current bookmark not in parent ctx marks
5402 # current bookmark not in parent ctx marks
5380 pass
5403 pass
5381 for m in marks:
5404 for m in marks:
5382 ui.write(' ' + m, label='log.bookmark')
5405 ui.write(' ' + m, label='log.bookmark')
5383 ui.write('\n', label='log.bookmark')
5406 ui.write('\n', label='log.bookmark')
5384
5407
5385 st = list(repo.status(unknown=True))[:6]
5408 st = list(repo.status(unknown=True))[:6]
5386
5409
5387 c = repo.dirstate.copies()
5410 c = repo.dirstate.copies()
5388 copied, renamed = [], []
5411 copied, renamed = [], []
5389 for d, s in c.iteritems():
5412 for d, s in c.iteritems():
5390 if s in st[2]:
5413 if s in st[2]:
5391 st[2].remove(s)
5414 st[2].remove(s)
5392 renamed.append(d)
5415 renamed.append(d)
5393 else:
5416 else:
5394 copied.append(d)
5417 copied.append(d)
5395 if d in st[1]:
5418 if d in st[1]:
5396 st[1].remove(d)
5419 st[1].remove(d)
5397 st.insert(3, renamed)
5420 st.insert(3, renamed)
5398 st.insert(4, copied)
5421 st.insert(4, copied)
5399
5422
5400 ms = mergemod.mergestate(repo)
5423 ms = mergemod.mergestate(repo)
5401 st.append([f for f in ms if ms[f] == 'u'])
5424 st.append([f for f in ms if ms[f] == 'u'])
5402
5425
5403 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5426 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5404 st.append(subs)
5427 st.append(subs)
5405
5428
5406 labels = [ui.label(_('%d modified'), 'status.modified'),
5429 labels = [ui.label(_('%d modified'), 'status.modified'),
5407 ui.label(_('%d added'), 'status.added'),
5430 ui.label(_('%d added'), 'status.added'),
5408 ui.label(_('%d removed'), 'status.removed'),
5431 ui.label(_('%d removed'), 'status.removed'),
5409 ui.label(_('%d renamed'), 'status.copied'),
5432 ui.label(_('%d renamed'), 'status.copied'),
5410 ui.label(_('%d copied'), 'status.copied'),
5433 ui.label(_('%d copied'), 'status.copied'),
5411 ui.label(_('%d deleted'), 'status.deleted'),
5434 ui.label(_('%d deleted'), 'status.deleted'),
5412 ui.label(_('%d unknown'), 'status.unknown'),
5435 ui.label(_('%d unknown'), 'status.unknown'),
5413 ui.label(_('%d ignored'), 'status.ignored'),
5436 ui.label(_('%d ignored'), 'status.ignored'),
5414 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5437 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5415 ui.label(_('%d subrepos'), 'status.modified')]
5438 ui.label(_('%d subrepos'), 'status.modified')]
5416 t = []
5439 t = []
5417 for s, l in zip(st, labels):
5440 for s, l in zip(st, labels):
5418 if s:
5441 if s:
5419 t.append(l % len(s))
5442 t.append(l % len(s))
5420
5443
5421 t = ', '.join(t)
5444 t = ', '.join(t)
5422 cleanworkdir = False
5445 cleanworkdir = False
5423
5446
5424 if len(parents) > 1:
5447 if len(parents) > 1:
5425 t += _(' (merge)')
5448 t += _(' (merge)')
5426 elif branch != parents[0].branch():
5449 elif branch != parents[0].branch():
5427 t += _(' (new branch)')
5450 t += _(' (new branch)')
5428 elif (parents[0].closesbranch() and
5451 elif (parents[0].closesbranch() and
5429 pnode in repo.branchheads(branch, closed=True)):
5452 pnode in repo.branchheads(branch, closed=True)):
5430 t += _(' (head closed)')
5453 t += _(' (head closed)')
5431 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5454 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5432 t += _(' (clean)')
5455 t += _(' (clean)')
5433 cleanworkdir = True
5456 cleanworkdir = True
5434 elif pnode not in bheads:
5457 elif pnode not in bheads:
5435 t += _(' (new branch head)')
5458 t += _(' (new branch head)')
5436
5459
5437 if cleanworkdir:
5460 if cleanworkdir:
5438 ui.status(_('commit: %s\n') % t.strip())
5461 ui.status(_('commit: %s\n') % t.strip())
5439 else:
5462 else:
5440 ui.write(_('commit: %s\n') % t.strip())
5463 ui.write(_('commit: %s\n') % t.strip())
5441
5464
5442 # all ancestors of branch heads - all ancestors of parent = new csets
5465 # all ancestors of branch heads - all ancestors of parent = new csets
5443 new = [0] * len(repo)
5466 new = [0] * len(repo)
5444 cl = repo.changelog
5467 cl = repo.changelog
5445 for a in [cl.rev(n) for n in bheads]:
5468 for a in [cl.rev(n) for n in bheads]:
5446 new[a] = 1
5469 new[a] = 1
5447 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5470 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5448 new[a] = 1
5471 new[a] = 1
5449 for a in [p.rev() for p in parents]:
5472 for a in [p.rev() for p in parents]:
5450 if a >= 0:
5473 if a >= 0:
5451 new[a] = 0
5474 new[a] = 0
5452 for a in cl.ancestors([p.rev() for p in parents]):
5475 for a in cl.ancestors([p.rev() for p in parents]):
5453 new[a] = 0
5476 new[a] = 0
5454 new = sum(new)
5477 new = sum(new)
5455
5478
5456 if new == 0:
5479 if new == 0:
5457 ui.status(_('update: (current)\n'))
5480 ui.status(_('update: (current)\n'))
5458 elif pnode not in bheads:
5481 elif pnode not in bheads:
5459 ui.write(_('update: %d new changesets (update)\n') % new)
5482 ui.write(_('update: %d new changesets (update)\n') % new)
5460 else:
5483 else:
5461 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5484 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5462 (new, len(bheads)))
5485 (new, len(bheads)))
5463
5486
5464 if opts.get('remote'):
5487 if opts.get('remote'):
5465 t = []
5488 t = []
5466 source, branches = hg.parseurl(ui.expandpath('default'))
5489 source, branches = hg.parseurl(ui.expandpath('default'))
5467 other = hg.peer(repo, {}, source)
5490 other = hg.peer(repo, {}, source)
5468 revs, checkout = hg.addbranchrevs(repo, other, branches,
5491 revs, checkout = hg.addbranchrevs(repo, other, branches,
5469 opts.get('rev'))
5492 opts.get('rev'))
5470 ui.debug('comparing with %s\n' % util.hidepassword(source))
5493 ui.debug('comparing with %s\n' % util.hidepassword(source))
5471 repo.ui.pushbuffer()
5494 repo.ui.pushbuffer()
5472 commoninc = discovery.findcommonincoming(repo, other)
5495 commoninc = discovery.findcommonincoming(repo, other)
5473 _common, incoming, _rheads = commoninc
5496 _common, incoming, _rheads = commoninc
5474 repo.ui.popbuffer()
5497 repo.ui.popbuffer()
5475 if incoming:
5498 if incoming:
5476 t.append(_('1 or more incoming'))
5499 t.append(_('1 or more incoming'))
5477
5500
5478 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5501 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5479 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5502 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5480 if source != dest:
5503 if source != dest:
5481 other = hg.peer(repo, {}, dest)
5504 other = hg.peer(repo, {}, dest)
5482 commoninc = None
5505 commoninc = None
5483 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5506 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5484 repo.ui.pushbuffer()
5507 repo.ui.pushbuffer()
5485 outgoing = discovery.findcommonoutgoing(repo, other,
5508 outgoing = discovery.findcommonoutgoing(repo, other,
5486 commoninc=commoninc)
5509 commoninc=commoninc)
5487 repo.ui.popbuffer()
5510 repo.ui.popbuffer()
5488 o = outgoing.missing
5511 o = outgoing.missing
5489 if o:
5512 if o:
5490 t.append(_('%d outgoing') % len(o))
5513 t.append(_('%d outgoing') % len(o))
5491 if 'bookmarks' in other.listkeys('namespaces'):
5514 if 'bookmarks' in other.listkeys('namespaces'):
5492 lmarks = repo.listkeys('bookmarks')
5515 lmarks = repo.listkeys('bookmarks')
5493 rmarks = other.listkeys('bookmarks')
5516 rmarks = other.listkeys('bookmarks')
5494 diff = set(rmarks) - set(lmarks)
5517 diff = set(rmarks) - set(lmarks)
5495 if len(diff) > 0:
5518 if len(diff) > 0:
5496 t.append(_('%d incoming bookmarks') % len(diff))
5519 t.append(_('%d incoming bookmarks') % len(diff))
5497 diff = set(lmarks) - set(rmarks)
5520 diff = set(lmarks) - set(rmarks)
5498 if len(diff) > 0:
5521 if len(diff) > 0:
5499 t.append(_('%d outgoing bookmarks') % len(diff))
5522 t.append(_('%d outgoing bookmarks') % len(diff))
5500
5523
5501 if t:
5524 if t:
5502 ui.write(_('remote: %s\n') % (', '.join(t)))
5525 ui.write(_('remote: %s\n') % (', '.join(t)))
5503 else:
5526 else:
5504 ui.status(_('remote: (synced)\n'))
5527 ui.status(_('remote: (synced)\n'))
5505
5528
5506 @command('tag',
5529 @command('tag',
5507 [('f', 'force', None, _('force tag')),
5530 [('f', 'force', None, _('force tag')),
5508 ('l', 'local', None, _('make the tag local')),
5531 ('l', 'local', None, _('make the tag local')),
5509 ('r', 'rev', '', _('revision to tag'), _('REV')),
5532 ('r', 'rev', '', _('revision to tag'), _('REV')),
5510 ('', 'remove', None, _('remove a tag')),
5533 ('', 'remove', None, _('remove a tag')),
5511 # -l/--local is already there, commitopts cannot be used
5534 # -l/--local is already there, commitopts cannot be used
5512 ('e', 'edit', None, _('edit commit message')),
5535 ('e', 'edit', None, _('edit commit message')),
5513 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5536 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5514 ] + commitopts2,
5537 ] + commitopts2,
5515 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5538 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5516 def tag(ui, repo, name1, *names, **opts):
5539 def tag(ui, repo, name1, *names, **opts):
5517 """add one or more tags for the current or given revision
5540 """add one or more tags for the current or given revision
5518
5541
5519 Name a particular revision using <name>.
5542 Name a particular revision using <name>.
5520
5543
5521 Tags are used to name particular revisions of the repository and are
5544 Tags are used to name particular revisions of the repository and are
5522 very useful to compare different revisions, to go back to significant
5545 very useful to compare different revisions, to go back to significant
5523 earlier versions or to mark branch points as releases, etc. Changing
5546 earlier versions or to mark branch points as releases, etc. Changing
5524 an existing tag is normally disallowed; use -f/--force to override.
5547 an existing tag is normally disallowed; use -f/--force to override.
5525
5548
5526 If no revision is given, the parent of the working directory is
5549 If no revision is given, the parent of the working directory is
5527 used, or tip if no revision is checked out.
5550 used, or tip if no revision is checked out.
5528
5551
5529 To facilitate version control, distribution, and merging of tags,
5552 To facilitate version control, distribution, and merging of tags,
5530 they are stored as a file named ".hgtags" which is managed similarly
5553 they are stored as a file named ".hgtags" which is managed similarly
5531 to other project files and can be hand-edited if necessary. This
5554 to other project files and can be hand-edited if necessary. This
5532 also means that tagging creates a new commit. The file
5555 also means that tagging creates a new commit. The file
5533 ".hg/localtags" is used for local tags (not shared among
5556 ".hg/localtags" is used for local tags (not shared among
5534 repositories).
5557 repositories).
5535
5558
5536 Tag commits are usually made at the head of a branch. If the parent
5559 Tag commits are usually made at the head of a branch. If the parent
5537 of the working directory is not a branch head, :hg:`tag` aborts; use
5560 of the working directory is not a branch head, :hg:`tag` aborts; use
5538 -f/--force to force the tag commit to be based on a non-head
5561 -f/--force to force the tag commit to be based on a non-head
5539 changeset.
5562 changeset.
5540
5563
5541 See :hg:`help dates` for a list of formats valid for -d/--date.
5564 See :hg:`help dates` for a list of formats valid for -d/--date.
5542
5565
5543 Since tag names have priority over branch names during revision
5566 Since tag names have priority over branch names during revision
5544 lookup, using an existing branch name as a tag name is discouraged.
5567 lookup, using an existing branch name as a tag name is discouraged.
5545
5568
5546 Returns 0 on success.
5569 Returns 0 on success.
5547 """
5570 """
5548 wlock = lock = None
5571 wlock = lock = None
5549 try:
5572 try:
5550 wlock = repo.wlock()
5573 wlock = repo.wlock()
5551 lock = repo.lock()
5574 lock = repo.lock()
5552 rev_ = "."
5575 rev_ = "."
5553 names = [t.strip() for t in (name1,) + names]
5576 names = [t.strip() for t in (name1,) + names]
5554 if len(names) != len(set(names)):
5577 if len(names) != len(set(names)):
5555 raise util.Abort(_('tag names must be unique'))
5578 raise util.Abort(_('tag names must be unique'))
5556 for n in names:
5579 for n in names:
5557 if n in ['tip', '.', 'null']:
5580 if n in ['tip', '.', 'null']:
5558 raise util.Abort(_("the name '%s' is reserved") % n)
5581 raise util.Abort(_("the name '%s' is reserved") % n)
5559 if not n:
5582 if not n:
5560 raise util.Abort(_('tag names cannot consist entirely of '
5583 raise util.Abort(_('tag names cannot consist entirely of '
5561 'whitespace'))
5584 'whitespace'))
5562 if opts.get('rev') and opts.get('remove'):
5585 if opts.get('rev') and opts.get('remove'):
5563 raise util.Abort(_("--rev and --remove are incompatible"))
5586 raise util.Abort(_("--rev and --remove are incompatible"))
5564 if opts.get('rev'):
5587 if opts.get('rev'):
5565 rev_ = opts['rev']
5588 rev_ = opts['rev']
5566 message = opts.get('message')
5589 message = opts.get('message')
5567 if opts.get('remove'):
5590 if opts.get('remove'):
5568 expectedtype = opts.get('local') and 'local' or 'global'
5591 expectedtype = opts.get('local') and 'local' or 'global'
5569 for n in names:
5592 for n in names:
5570 if not repo.tagtype(n):
5593 if not repo.tagtype(n):
5571 raise util.Abort(_("tag '%s' does not exist") % n)
5594 raise util.Abort(_("tag '%s' does not exist") % n)
5572 if repo.tagtype(n) != expectedtype:
5595 if repo.tagtype(n) != expectedtype:
5573 if expectedtype == 'global':
5596 if expectedtype == 'global':
5574 raise util.Abort(_("tag '%s' is not a global tag") % n)
5597 raise util.Abort(_("tag '%s' is not a global tag") % n)
5575 else:
5598 else:
5576 raise util.Abort(_("tag '%s' is not a local tag") % n)
5599 raise util.Abort(_("tag '%s' is not a local tag") % n)
5577 rev_ = nullid
5600 rev_ = nullid
5578 if not message:
5601 if not message:
5579 # we don't translate commit messages
5602 # we don't translate commit messages
5580 message = 'Removed tag %s' % ', '.join(names)
5603 message = 'Removed tag %s' % ', '.join(names)
5581 elif not opts.get('force'):
5604 elif not opts.get('force'):
5582 for n in names:
5605 for n in names:
5583 if n in repo.tags():
5606 if n in repo.tags():
5584 raise util.Abort(_("tag '%s' already exists "
5607 raise util.Abort(_("tag '%s' already exists "
5585 "(use -f to force)") % n)
5608 "(use -f to force)") % n)
5586 if not opts.get('local'):
5609 if not opts.get('local'):
5587 p1, p2 = repo.dirstate.parents()
5610 p1, p2 = repo.dirstate.parents()
5588 if p2 != nullid:
5611 if p2 != nullid:
5589 raise util.Abort(_('uncommitted merge'))
5612 raise util.Abort(_('uncommitted merge'))
5590 bheads = repo.branchheads()
5613 bheads = repo.branchheads()
5591 if not opts.get('force') and bheads and p1 not in bheads:
5614 if not opts.get('force') and bheads and p1 not in bheads:
5592 raise util.Abort(_('not at a branch head (use -f to force)'))
5615 raise util.Abort(_('not at a branch head (use -f to force)'))
5593 r = scmutil.revsingle(repo, rev_).node()
5616 r = scmutil.revsingle(repo, rev_).node()
5594
5617
5595 if not message:
5618 if not message:
5596 # we don't translate commit messages
5619 # we don't translate commit messages
5597 message = ('Added tag %s for changeset %s' %
5620 message = ('Added tag %s for changeset %s' %
5598 (', '.join(names), short(r)))
5621 (', '.join(names), short(r)))
5599
5622
5600 date = opts.get('date')
5623 date = opts.get('date')
5601 if date:
5624 if date:
5602 date = util.parsedate(date)
5625 date = util.parsedate(date)
5603
5626
5604 if opts.get('edit'):
5627 if opts.get('edit'):
5605 message = ui.edit(message, ui.username())
5628 message = ui.edit(message, ui.username())
5606
5629
5607 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5630 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5608 finally:
5631 finally:
5609 release(lock, wlock)
5632 release(lock, wlock)
5610
5633
5611 @command('tags', [], '')
5634 @command('tags', [], '')
5612 def tags(ui, repo):
5635 def tags(ui, repo):
5613 """list repository tags
5636 """list repository tags
5614
5637
5615 This lists both regular and local tags. When the -v/--verbose
5638 This lists both regular and local tags. When the -v/--verbose
5616 switch is used, a third column "local" is printed for local tags.
5639 switch is used, a third column "local" is printed for local tags.
5617
5640
5618 Returns 0 on success.
5641 Returns 0 on success.
5619 """
5642 """
5620
5643
5621 hexfunc = ui.debugflag and hex or short
5644 hexfunc = ui.debugflag and hex or short
5622 tagtype = ""
5645 tagtype = ""
5623
5646
5624 for t, n in reversed(repo.tagslist()):
5647 for t, n in reversed(repo.tagslist()):
5625 if ui.quiet:
5648 if ui.quiet:
5626 ui.write("%s\n" % t, label='tags.normal')
5649 ui.write("%s\n" % t, label='tags.normal')
5627 continue
5650 continue
5628
5651
5629 hn = hexfunc(n)
5652 hn = hexfunc(n)
5630 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5653 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5631 rev = ui.label(r, 'log.changeset')
5654 rev = ui.label(r, 'log.changeset')
5632 spaces = " " * (30 - encoding.colwidth(t))
5655 spaces = " " * (30 - encoding.colwidth(t))
5633
5656
5634 tag = ui.label(t, 'tags.normal')
5657 tag = ui.label(t, 'tags.normal')
5635 if ui.verbose:
5658 if ui.verbose:
5636 if repo.tagtype(t) == 'local':
5659 if repo.tagtype(t) == 'local':
5637 tagtype = " local"
5660 tagtype = " local"
5638 tag = ui.label(t, 'tags.local')
5661 tag = ui.label(t, 'tags.local')
5639 else:
5662 else:
5640 tagtype = ""
5663 tagtype = ""
5641 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5664 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5642
5665
5643 @command('tip',
5666 @command('tip',
5644 [('p', 'patch', None, _('show patch')),
5667 [('p', 'patch', None, _('show patch')),
5645 ('g', 'git', None, _('use git extended diff format')),
5668 ('g', 'git', None, _('use git extended diff format')),
5646 ] + templateopts,
5669 ] + templateopts,
5647 _('[-p] [-g]'))
5670 _('[-p] [-g]'))
5648 def tip(ui, repo, **opts):
5671 def tip(ui, repo, **opts):
5649 """show the tip revision
5672 """show the tip revision
5650
5673
5651 The tip revision (usually just called the tip) is the changeset
5674 The tip revision (usually just called the tip) is the changeset
5652 most recently added to the repository (and therefore the most
5675 most recently added to the repository (and therefore the most
5653 recently changed head).
5676 recently changed head).
5654
5677
5655 If you have just made a commit, that commit will be the tip. If
5678 If you have just made a commit, that commit will be the tip. If
5656 you have just pulled changes from another repository, the tip of
5679 you have just pulled changes from another repository, the tip of
5657 that repository becomes the current tip. The "tip" tag is special
5680 that repository becomes the current tip. The "tip" tag is special
5658 and cannot be renamed or assigned to a different changeset.
5681 and cannot be renamed or assigned to a different changeset.
5659
5682
5660 Returns 0 on success.
5683 Returns 0 on success.
5661 """
5684 """
5662 displayer = cmdutil.show_changeset(ui, repo, opts)
5685 displayer = cmdutil.show_changeset(ui, repo, opts)
5663 displayer.show(repo[len(repo) - 1])
5686 displayer.show(repo[len(repo) - 1])
5664 displayer.close()
5687 displayer.close()
5665
5688
5666 @command('unbundle',
5689 @command('unbundle',
5667 [('u', 'update', None,
5690 [('u', 'update', None,
5668 _('update to new branch head if changesets were unbundled'))],
5691 _('update to new branch head if changesets were unbundled'))],
5669 _('[-u] FILE...'))
5692 _('[-u] FILE...'))
5670 def unbundle(ui, repo, fname1, *fnames, **opts):
5693 def unbundle(ui, repo, fname1, *fnames, **opts):
5671 """apply one or more changegroup files
5694 """apply one or more changegroup files
5672
5695
5673 Apply one or more compressed changegroup files generated by the
5696 Apply one or more compressed changegroup files generated by the
5674 bundle command.
5697 bundle command.
5675
5698
5676 Returns 0 on success, 1 if an update has unresolved files.
5699 Returns 0 on success, 1 if an update has unresolved files.
5677 """
5700 """
5678 fnames = (fname1,) + fnames
5701 fnames = (fname1,) + fnames
5679
5702
5680 lock = repo.lock()
5703 lock = repo.lock()
5681 wc = repo['.']
5704 wc = repo['.']
5682 try:
5705 try:
5683 for fname in fnames:
5706 for fname in fnames:
5684 f = url.open(ui, fname)
5707 f = url.open(ui, fname)
5685 gen = changegroup.readbundle(f, fname)
5708 gen = changegroup.readbundle(f, fname)
5686 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5709 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5687 finally:
5710 finally:
5688 lock.release()
5711 lock.release()
5689 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5712 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5690 return postincoming(ui, repo, modheads, opts.get('update'), None)
5713 return postincoming(ui, repo, modheads, opts.get('update'), None)
5691
5714
5692 @command('^update|up|checkout|co',
5715 @command('^update|up|checkout|co',
5693 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5716 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5694 ('c', 'check', None,
5717 ('c', 'check', None,
5695 _('update across branches if no uncommitted changes')),
5718 _('update across branches if no uncommitted changes')),
5696 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5719 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5697 ('r', 'rev', '', _('revision'), _('REV'))],
5720 ('r', 'rev', '', _('revision'), _('REV'))],
5698 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5721 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5699 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5722 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5700 """update working directory (or switch revisions)
5723 """update working directory (or switch revisions)
5701
5724
5702 Update the repository's working directory to the specified
5725 Update the repository's working directory to the specified
5703 changeset. If no changeset is specified, update to the tip of the
5726 changeset. If no changeset is specified, update to the tip of the
5704 current named branch and move the current bookmark (see :hg:`help
5727 current named branch and move the current bookmark (see :hg:`help
5705 bookmarks`).
5728 bookmarks`).
5706
5729
5707 Update sets the working directory's parent revison to the specified
5730 Update sets the working directory's parent revison to the specified
5708 changeset (see :hg:`help parents`).
5731 changeset (see :hg:`help parents`).
5709
5732
5710 If the changeset is not a descendant or ancestor of the working
5733 If the changeset is not a descendant or ancestor of the working
5711 directory's parent, the update is aborted. With the -c/--check
5734 directory's parent, the update is aborted. With the -c/--check
5712 option, the working directory is checked for uncommitted changes; if
5735 option, the working directory is checked for uncommitted changes; if
5713 none are found, the working directory is updated to the specified
5736 none are found, the working directory is updated to the specified
5714 changeset.
5737 changeset.
5715
5738
5716 The following rules apply when the working directory contains
5739 The following rules apply when the working directory contains
5717 uncommitted changes:
5740 uncommitted changes:
5718
5741
5719 1. If neither -c/--check nor -C/--clean is specified, and if
5742 1. If neither -c/--check nor -C/--clean is specified, and if
5720 the requested changeset is an ancestor or descendant of
5743 the requested changeset is an ancestor or descendant of
5721 the working directory's parent, the uncommitted changes
5744 the working directory's parent, the uncommitted changes
5722 are merged into the requested changeset and the merged
5745 are merged into the requested changeset and the merged
5723 result is left uncommitted. If the requested changeset is
5746 result is left uncommitted. If the requested changeset is
5724 not an ancestor or descendant (that is, it is on another
5747 not an ancestor or descendant (that is, it is on another
5725 branch), the update is aborted and the uncommitted changes
5748 branch), the update is aborted and the uncommitted changes
5726 are preserved.
5749 are preserved.
5727
5750
5728 2. With the -c/--check option, the update is aborted and the
5751 2. With the -c/--check option, the update is aborted and the
5729 uncommitted changes are preserved.
5752 uncommitted changes are preserved.
5730
5753
5731 3. With the -C/--clean option, uncommitted changes are discarded and
5754 3. With the -C/--clean option, uncommitted changes are discarded and
5732 the working directory is updated to the requested changeset.
5755 the working directory is updated to the requested changeset.
5733
5756
5734 To cancel an uncommitted merge (and lose your changes), use
5757 To cancel an uncommitted merge (and lose your changes), use
5735 :hg:`update --clean .`.
5758 :hg:`update --clean .`.
5736
5759
5737 Use null as the changeset to remove the working directory (like
5760 Use null as the changeset to remove the working directory (like
5738 :hg:`clone -U`).
5761 :hg:`clone -U`).
5739
5762
5740 If you want to revert just one file to an older revision, use
5763 If you want to revert just one file to an older revision, use
5741 :hg:`revert [-r REV] NAME`.
5764 :hg:`revert [-r REV] NAME`.
5742
5765
5743 See :hg:`help dates` for a list of formats valid for -d/--date.
5766 See :hg:`help dates` for a list of formats valid for -d/--date.
5744
5767
5745 Returns 0 on success, 1 if there are unresolved files.
5768 Returns 0 on success, 1 if there are unresolved files.
5746 """
5769 """
5747 if rev and node:
5770 if rev and node:
5748 raise util.Abort(_("please specify just one revision"))
5771 raise util.Abort(_("please specify just one revision"))
5749
5772
5750 if rev is None or rev == '':
5773 if rev is None or rev == '':
5751 rev = node
5774 rev = node
5752
5775
5753 # with no argument, we also move the current bookmark, if any
5776 # with no argument, we also move the current bookmark, if any
5754 movemarkfrom = None
5777 movemarkfrom = None
5755 if rev is None or node == '':
5778 if rev is None or node == '':
5756 movemarkfrom = repo['.'].node()
5779 movemarkfrom = repo['.'].node()
5757
5780
5758 # if we defined a bookmark, we have to remember the original bookmark name
5781 # if we defined a bookmark, we have to remember the original bookmark name
5759 brev = rev
5782 brev = rev
5760 rev = scmutil.revsingle(repo, rev, rev).rev()
5783 rev = scmutil.revsingle(repo, rev, rev).rev()
5761
5784
5762 if check and clean:
5785 if check and clean:
5763 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5786 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5764
5787
5765 if date:
5788 if date:
5766 if rev is not None:
5789 if rev is not None:
5767 raise util.Abort(_("you can't specify a revision and a date"))
5790 raise util.Abort(_("you can't specify a revision and a date"))
5768 rev = cmdutil.finddate(ui, repo, date)
5791 rev = cmdutil.finddate(ui, repo, date)
5769
5792
5770 if check:
5793 if check:
5771 c = repo[None]
5794 c = repo[None]
5772 if c.dirty(merge=False, branch=False):
5795 if c.dirty(merge=False, branch=False):
5773 raise util.Abort(_("uncommitted local changes"))
5796 raise util.Abort(_("uncommitted local changes"))
5774 if rev is None:
5797 if rev is None:
5775 rev = repo[repo[None].branch()].rev()
5798 rev = repo[repo[None].branch()].rev()
5776 mergemod._checkunknown(repo, repo[None], repo[rev])
5799 mergemod._checkunknown(repo, repo[None], repo[rev])
5777
5800
5778 if clean:
5801 if clean:
5779 ret = hg.clean(repo, rev)
5802 ret = hg.clean(repo, rev)
5780 else:
5803 else:
5781 ret = hg.update(repo, rev)
5804 ret = hg.update(repo, rev)
5782
5805
5783 if not ret and movemarkfrom:
5806 if not ret and movemarkfrom:
5784 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5807 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5785 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5808 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5786 elif brev in repo._bookmarks:
5809 elif brev in repo._bookmarks:
5787 bookmarks.setcurrent(repo, brev)
5810 bookmarks.setcurrent(repo, brev)
5788 elif brev:
5811 elif brev:
5789 bookmarks.unsetcurrent(repo)
5812 bookmarks.unsetcurrent(repo)
5790
5813
5791 return ret
5814 return ret
5792
5815
5793 @command('verify', [])
5816 @command('verify', [])
5794 def verify(ui, repo):
5817 def verify(ui, repo):
5795 """verify the integrity of the repository
5818 """verify the integrity of the repository
5796
5819
5797 Verify the integrity of the current repository.
5820 Verify the integrity of the current repository.
5798
5821
5799 This will perform an extensive check of the repository's
5822 This will perform an extensive check of the repository's
5800 integrity, validating the hashes and checksums of each entry in
5823 integrity, validating the hashes and checksums of each entry in
5801 the changelog, manifest, and tracked files, as well as the
5824 the changelog, manifest, and tracked files, as well as the
5802 integrity of their crosslinks and indices.
5825 integrity of their crosslinks and indices.
5803
5826
5804 Returns 0 on success, 1 if errors are encountered.
5827 Returns 0 on success, 1 if errors are encountered.
5805 """
5828 """
5806 return hg.verify(repo)
5829 return hg.verify(repo)
5807
5830
5808 @command('version', [])
5831 @command('version', [])
5809 def version_(ui):
5832 def version_(ui):
5810 """output version and copyright information"""
5833 """output version and copyright information"""
5811 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5834 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5812 % util.version())
5835 % util.version())
5813 ui.status(_(
5836 ui.status(_(
5814 "(see http://mercurial.selenic.com for more information)\n"
5837 "(see http://mercurial.selenic.com for more information)\n"
5815 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5838 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5816 "This is free software; see the source for copying conditions. "
5839 "This is free software; see the source for copying conditions. "
5817 "There is NO\nwarranty; "
5840 "There is NO\nwarranty; "
5818 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5841 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5819 ))
5842 ))
5820
5843
5821 norepo = ("clone init version help debugcommands debugcomplete"
5844 norepo = ("clone init version help debugcommands debugcomplete"
5822 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5845 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5823 " debugknown debuggetbundle debugbundle")
5846 " debugknown debuggetbundle debugbundle")
5824 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5847 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5825 " debugdata debugindex debugindexdot debugrevlog")
5848 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,276 +1,276 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 copy
16 copy
17 diff
17 diff
18 export
18 export
19 forget
19 forget
20 graft
20 graft
21 grep
21 grep
22 heads
22 heads
23 help
23 help
24 identify
24 identify
25 import
25 import
26 incoming
26 incoming
27 init
27 init
28 locate
28 locate
29 log
29 log
30 manifest
30 manifest
31 merge
31 merge
32 outgoing
32 outgoing
33 parents
33 parents
34 paths
34 paths
35 phase
35 phase
36 pull
36 pull
37 push
37 push
38 recover
38 recover
39 remove
39 remove
40 rename
40 rename
41 resolve
41 resolve
42 revert
42 revert
43 rollback
43 rollback
44 root
44 root
45 serve
45 serve
46 showconfig
46 showconfig
47 status
47 status
48 summary
48 summary
49 tag
49 tag
50 tags
50 tags
51 tip
51 tip
52 unbundle
52 unbundle
53 update
53 update
54 verify
54 verify
55 version
55 version
56
56
57 Show all commands that start with "a"
57 Show all commands that start with "a"
58 $ hg debugcomplete a
58 $ hg debugcomplete a
59 add
59 add
60 addremove
60 addremove
61 annotate
61 annotate
62 archive
62 archive
63
63
64 Do not show debug commands if there are other candidates
64 Do not show debug commands if there are other candidates
65 $ hg debugcomplete d
65 $ hg debugcomplete d
66 diff
66 diff
67
67
68 Show debug commands if there are no other candidates
68 Show debug commands if there are no other candidates
69 $ hg debugcomplete debug
69 $ hg debugcomplete debug
70 debugancestor
70 debugancestor
71 debugbuilddag
71 debugbuilddag
72 debugbundle
72 debugbundle
73 debugcheckstate
73 debugcheckstate
74 debugcommands
74 debugcommands
75 debugcomplete
75 debugcomplete
76 debugconfig
76 debugconfig
77 debugdag
77 debugdag
78 debugdata
78 debugdata
79 debugdate
79 debugdate
80 debugdiscovery
80 debugdiscovery
81 debugfileset
81 debugfileset
82 debugfsinfo
82 debugfsinfo
83 debuggetbundle
83 debuggetbundle
84 debugignore
84 debugignore
85 debugindex
85 debugindex
86 debugindexdot
86 debugindexdot
87 debuginstall
87 debuginstall
88 debugknown
88 debugknown
89 debugobsolete
89 debugobsolete
90 debugpushkey
90 debugpushkey
91 debugpvec
91 debugpvec
92 debugrebuildstate
92 debugrebuildstate
93 debugrename
93 debugrename
94 debugrevlog
94 debugrevlog
95 debugrevspec
95 debugrevspec
96 debugsetparents
96 debugsetparents
97 debugstate
97 debugstate
98 debugsub
98 debugsub
99 debugwalk
99 debugwalk
100 debugwireargs
100 debugwireargs
101
101
102 Do not show the alias of a debug command if there are other candidates
102 Do not show the alias of a debug command if there are other candidates
103 (this should hide rawcommit)
103 (this should hide rawcommit)
104 $ hg debugcomplete r
104 $ hg debugcomplete r
105 recover
105 recover
106 remove
106 remove
107 rename
107 rename
108 resolve
108 resolve
109 revert
109 revert
110 rollback
110 rollback
111 root
111 root
112 Show the alias of a debug command if there are no other candidates
112 Show the alias of a debug command if there are no other candidates
113 $ hg debugcomplete rawc
113 $ hg debugcomplete rawc
114
114
115
115
116 Show the global options
116 Show the global options
117 $ hg debugcomplete --options | sort
117 $ hg debugcomplete --options | sort
118 --config
118 --config
119 --cwd
119 --cwd
120 --debug
120 --debug
121 --debugger
121 --debugger
122 --encoding
122 --encoding
123 --encodingmode
123 --encodingmode
124 --help
124 --help
125 --noninteractive
125 --noninteractive
126 --profile
126 --profile
127 --quiet
127 --quiet
128 --repository
128 --repository
129 --time
129 --time
130 --traceback
130 --traceback
131 --verbose
131 --verbose
132 --version
132 --version
133 -R
133 -R
134 -h
134 -h
135 -q
135 -q
136 -v
136 -v
137 -y
137 -y
138
138
139 Show the options for the "serve" command
139 Show the options for the "serve" command
140 $ hg debugcomplete --options serve | sort
140 $ hg debugcomplete --options serve | sort
141 --accesslog
141 --accesslog
142 --address
142 --address
143 --certificate
143 --certificate
144 --cmdserver
144 --cmdserver
145 --config
145 --config
146 --cwd
146 --cwd
147 --daemon
147 --daemon
148 --daemon-pipefds
148 --daemon-pipefds
149 --debug
149 --debug
150 --debugger
150 --debugger
151 --encoding
151 --encoding
152 --encodingmode
152 --encodingmode
153 --errorlog
153 --errorlog
154 --help
154 --help
155 --ipv6
155 --ipv6
156 --name
156 --name
157 --noninteractive
157 --noninteractive
158 --pid-file
158 --pid-file
159 --port
159 --port
160 --prefix
160 --prefix
161 --profile
161 --profile
162 --quiet
162 --quiet
163 --repository
163 --repository
164 --stdio
164 --stdio
165 --style
165 --style
166 --templates
166 --templates
167 --time
167 --time
168 --traceback
168 --traceback
169 --verbose
169 --verbose
170 --version
170 --version
171 --web-conf
171 --web-conf
172 -6
172 -6
173 -A
173 -A
174 -E
174 -E
175 -R
175 -R
176 -a
176 -a
177 -d
177 -d
178 -h
178 -h
179 -n
179 -n
180 -p
180 -p
181 -q
181 -q
182 -t
182 -t
183 -v
183 -v
184 -y
184 -y
185
185
186 Show an error if we use --options with an ambiguous abbreviation
186 Show an error if we use --options with an ambiguous abbreviation
187 $ hg debugcomplete --options s
187 $ hg debugcomplete --options s
188 hg: command 's' is ambiguous:
188 hg: command 's' is ambiguous:
189 serve showconfig status summary
189 serve showconfig status summary
190 [255]
190 [255]
191
191
192 Show all commands + options
192 Show all commands + options
193 $ hg debugcommands
193 $ hg debugcommands
194 add: include, exclude, subrepos, dry-run
194 add: include, exclude, subrepos, dry-run
195 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
195 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
196 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
196 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
197 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
197 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
198 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
198 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
199 export: output, switch-parent, rev, text, git, nodates
199 export: output, switch-parent, rev, text, git, nodates
200 forget: include, exclude
200 forget: include, exclude
201 init: ssh, remotecmd, insecure
201 init: ssh, remotecmd, insecure
202 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, graph, patch, git, limit, no-merges, stat, style, template, include, exclude
202 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
203 merge: force, rev, preview, tool
203 merge: force, rev, preview, tool
204 phase: public, draft, secret, force, rev
204 phase: public, draft, secret, force, rev
205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
207 remove: after, force, include, exclude
207 remove: after, force, include, exclude
208 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
208 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
209 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
209 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
210 summary: remote
210 summary: remote
211 update: clean, check, date, rev
211 update: clean, check, date, rev
212 addremove: similarity, include, exclude, dry-run
212 addremove: similarity, include, exclude, dry-run
213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
215 bisect: reset, good, bad, skip, extend, command, noupdate
215 bisect: reset, good, bad, skip, extend, command, noupdate
216 bookmarks: force, rev, delete, rename, inactive
216 bookmarks: force, rev, delete, rename, inactive
217 branch: force, clean
217 branch: force, clean
218 branches: active, closed
218 branches: active, closed
219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
220 cat: output, rev, decode, include, exclude
220 cat: output, rev, decode, include, exclude
221 copy: after, force, include, exclude, dry-run
221 copy: after, force, include, exclude, dry-run
222 debugancestor:
222 debugancestor:
223 debugbuilddag: mergeable-file, overwritten-file, new-file
223 debugbuilddag: mergeable-file, overwritten-file, new-file
224 debugbundle: all
224 debugbundle: all
225 debugcheckstate:
225 debugcheckstate:
226 debugcommands:
226 debugcommands:
227 debugcomplete: options
227 debugcomplete: options
228 debugdag: tags, branches, dots, spaces
228 debugdag: tags, branches, dots, spaces
229 debugdata: changelog, manifest
229 debugdata: changelog, manifest
230 debugdate: extended
230 debugdate: extended
231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
232 debugfileset:
232 debugfileset:
233 debugfsinfo:
233 debugfsinfo:
234 debuggetbundle: head, common, type
234 debuggetbundle: head, common, type
235 debugignore:
235 debugignore:
236 debugindex: changelog, manifest, format
236 debugindex: changelog, manifest, format
237 debugindexdot:
237 debugindexdot:
238 debuginstall:
238 debuginstall:
239 debugknown:
239 debugknown:
240 debugobsolete: date, user
240 debugobsolete: date, user
241 debugpushkey:
241 debugpushkey:
242 debugpvec:
242 debugpvec:
243 debugrebuildstate: rev
243 debugrebuildstate: rev
244 debugrename: rev
244 debugrename: rev
245 debugrevlog: changelog, manifest, dump
245 debugrevlog: changelog, manifest, dump
246 debugrevspec:
246 debugrevspec:
247 debugsetparents:
247 debugsetparents:
248 debugstate: nodates, datesort
248 debugstate: nodates, datesort
249 debugsub: rev
249 debugsub: rev
250 debugwalk: include, exclude
250 debugwalk: include, exclude
251 debugwireargs: three, four, five, ssh, remotecmd, insecure
251 debugwireargs: three, four, five, ssh, remotecmd, insecure
252 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
252 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
253 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
253 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
254 heads: rev, topo, active, closed, style, template
254 heads: rev, topo, active, closed, style, template
255 help: extension, command, keyword
255 help: extension, command, keyword
256 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
256 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
257 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
257 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
258 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
258 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
259 locate: rev, print0, fullpath, include, exclude
259 locate: rev, print0, fullpath, include, exclude
260 manifest: rev, all
260 manifest: rev, all
261 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
261 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
262 parents: rev, style, template
262 parents: rev, style, template
263 paths:
263 paths:
264 recover:
264 recover:
265 rename: after, force, include, exclude, dry-run
265 rename: after, force, include, exclude, dry-run
266 resolve: all, list, mark, unmark, no-status, tool, include, exclude
266 resolve: all, list, mark, unmark, no-status, tool, include, exclude
267 revert: all, date, rev, no-backup, include, exclude, dry-run
267 revert: all, date, rev, no-backup, include, exclude, dry-run
268 rollback: dry-run, force
268 rollback: dry-run, force
269 root:
269 root:
270 showconfig: untrusted
270 showconfig: untrusted
271 tag: force, local, rev, remove, edit, message, date, user
271 tag: force, local, rev, remove, edit, message, date, user
272 tags:
272 tags:
273 tip: patch, git, style, template
273 tip: patch, git, style, template
274 unbundle: update
274 unbundle: update
275 verify:
275 verify:
276 version:
276 version:
General Comments 0
You need to be logged in to leave comments. Login now