##// END OF EJS Templates
clfilter: enforce hidden changeset globally...
Pierre-Yves David -
r18267:5bb610f8 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,56 +1,55 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.i18n import _
15 from mercurial.i18n import _
16 from mercurial import cmdutil, commands
16 from mercurial import cmdutil, commands
17
17
18 cmdtable = {}
18 cmdtable = {}
19 command = cmdutil.command(cmdtable)
19 command = cmdutil.command(cmdtable)
20 testedwith = 'internal'
20 testedwith = 'internal'
21
21
22 @command('glog',
22 @command('glog',
23 [('f', 'follow', None,
23 [('f', 'follow', None,
24 _('follow changeset history, or file history across copies and renames')),
24 _('follow changeset history, or file history across copies and renames')),
25 ('', 'follow-first', None,
25 ('', 'follow-first', None,
26 _('only follow the first parent of merge changesets (DEPRECATED)')),
26 _('only follow the first parent of merge changesets (DEPRECATED)')),
27 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
27 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
28 ('C', 'copies', None, _('show copied files')),
28 ('C', 'copies', None, _('show copied files')),
29 ('k', 'keyword', [],
29 ('k', 'keyword', [],
30 _('do case-insensitive search for a given text'), _('TEXT')),
30 _('do case-insensitive search for a given text'), _('TEXT')),
31 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
31 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
32 ('', 'removed', None, _('include revisions where files were removed')),
32 ('', 'removed', None, _('include revisions where files were removed')),
33 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
33 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
34 ('u', 'user', [], _('revisions committed by user'), _('USER')),
34 ('u', 'user', [], _('revisions committed by user'), _('USER')),
35 ('', 'only-branch', [],
35 ('', 'only-branch', [],
36 _('show only changesets within the given named branch (DEPRECATED)'),
36 _('show only changesets within the given named branch (DEPRECATED)'),
37 _('BRANCH')),
37 _('BRANCH')),
38 ('b', 'branch', [],
38 ('b', 'branch', [],
39 _('show changesets within the given named branch'), _('BRANCH')),
39 _('show changesets within the given named branch'), _('BRANCH')),
40 ('P', 'prune', [],
40 ('P', 'prune', [],
41 _('do not display revision or any of its ancestors'), _('REV')),
41 _('do not display revision or any of its ancestors'), _('REV')),
42 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
43 ] + commands.logopts + commands.walkopts,
42 ] + commands.logopts + commands.walkopts,
44 _('[OPTION]... [FILE]'))
43 _('[OPTION]... [FILE]'))
45 def graphlog(ui, repo, *pats, **opts):
44 def graphlog(ui, repo, *pats, **opts):
46 """show revision history alongside an ASCII revision graph
45 """show revision history alongside an ASCII revision graph
47
46
48 Print a revision history alongside a revision graph drawn with
47 Print a revision history alongside a revision graph drawn with
49 ASCII characters.
48 ASCII characters.
50
49
51 Nodes printed as an @ character are parents of the working
50 Nodes printed as an @ character are parents of the working
52 directory.
51 directory.
53 """
52 """
54 return cmdutil.graphlog(ui, repo, *pats, **opts)
53 return cmdutil.graphlog(ui, repo, *pats, **opts)
55
54
56 commands.inferrepo += " glog"
55 commands.inferrepo += " glog"
@@ -1,2011 +1,2009 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, graphmod, revset, phases, obsolete
13 import subrepo, context, repair, graphmod, revset, phases, obsolete
14 import changelog
14 import changelog
15 import lock as lockmod
15 import lock as lockmod
16
16
17 def parsealiases(cmd):
17 def parsealiases(cmd):
18 return cmd.lstrip("^").split("|")
18 return cmd.lstrip("^").split("|")
19
19
20 def findpossible(cmd, table, strict=False):
20 def findpossible(cmd, table, strict=False):
21 """
21 """
22 Return cmd -> (aliases, command table entry)
22 Return cmd -> (aliases, command table entry)
23 for each matching command.
23 for each matching command.
24 Return debug commands (or their aliases) only if no normal command matches.
24 Return debug commands (or their aliases) only if no normal command matches.
25 """
25 """
26 choice = {}
26 choice = {}
27 debugchoice = {}
27 debugchoice = {}
28
28
29 if cmd in table:
29 if cmd in table:
30 # short-circuit exact matches, "log" alias beats "^log|history"
30 # short-circuit exact matches, "log" alias beats "^log|history"
31 keys = [cmd]
31 keys = [cmd]
32 else:
32 else:
33 keys = table.keys()
33 keys = table.keys()
34
34
35 for e in keys:
35 for e in keys:
36 aliases = parsealiases(e)
36 aliases = parsealiases(e)
37 found = None
37 found = None
38 if cmd in aliases:
38 if cmd in aliases:
39 found = cmd
39 found = cmd
40 elif not strict:
40 elif not strict:
41 for a in aliases:
41 for a in aliases:
42 if a.startswith(cmd):
42 if a.startswith(cmd):
43 found = a
43 found = a
44 break
44 break
45 if found is not None:
45 if found is not None:
46 if aliases[0].startswith("debug") or found.startswith("debug"):
46 if aliases[0].startswith("debug") or found.startswith("debug"):
47 debugchoice[found] = (aliases, table[e])
47 debugchoice[found] = (aliases, table[e])
48 else:
48 else:
49 choice[found] = (aliases, table[e])
49 choice[found] = (aliases, table[e])
50
50
51 if not choice and debugchoice:
51 if not choice and debugchoice:
52 choice = debugchoice
52 choice = debugchoice
53
53
54 return choice
54 return choice
55
55
56 def findcmd(cmd, table, strict=True):
56 def findcmd(cmd, table, strict=True):
57 """Return (aliases, command table entry) for command string."""
57 """Return (aliases, command table entry) for command string."""
58 choice = findpossible(cmd, table, strict)
58 choice = findpossible(cmd, table, strict)
59
59
60 if cmd in choice:
60 if cmd in choice:
61 return choice[cmd]
61 return choice[cmd]
62
62
63 if len(choice) > 1:
63 if len(choice) > 1:
64 clist = choice.keys()
64 clist = choice.keys()
65 clist.sort()
65 clist.sort()
66 raise error.AmbiguousCommand(cmd, clist)
66 raise error.AmbiguousCommand(cmd, clist)
67
67
68 if choice:
68 if choice:
69 return choice.values()[0]
69 return choice.values()[0]
70
70
71 raise error.UnknownCommand(cmd)
71 raise error.UnknownCommand(cmd)
72
72
73 def findrepo(p):
73 def findrepo(p):
74 while not os.path.isdir(os.path.join(p, ".hg")):
74 while not os.path.isdir(os.path.join(p, ".hg")):
75 oldp, p = p, os.path.dirname(p)
75 oldp, p = p, os.path.dirname(p)
76 if p == oldp:
76 if p == oldp:
77 return None
77 return None
78
78
79 return p
79 return p
80
80
81 def bailifchanged(repo):
81 def bailifchanged(repo):
82 if repo.dirstate.p2() != nullid:
82 if repo.dirstate.p2() != nullid:
83 raise util.Abort(_('outstanding uncommitted merge'))
83 raise util.Abort(_('outstanding uncommitted merge'))
84 modified, added, removed, deleted = repo.status()[:4]
84 modified, added, removed, deleted = repo.status()[:4]
85 if modified or added or removed or deleted:
85 if modified or added or removed or deleted:
86 raise util.Abort(_("outstanding uncommitted changes"))
86 raise util.Abort(_("outstanding uncommitted changes"))
87 ctx = repo[None]
87 ctx = repo[None]
88 for s in ctx.substate:
88 for s in ctx.substate:
89 if ctx.sub(s).dirty():
89 if ctx.sub(s).dirty():
90 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
90 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
91
91
92 def logmessage(ui, opts):
92 def logmessage(ui, opts):
93 """ get the log message according to -m and -l option """
93 """ get the log message according to -m and -l option """
94 message = opts.get('message')
94 message = opts.get('message')
95 logfile = opts.get('logfile')
95 logfile = opts.get('logfile')
96
96
97 if message and logfile:
97 if message and logfile:
98 raise util.Abort(_('options --message and --logfile are mutually '
98 raise util.Abort(_('options --message and --logfile are mutually '
99 'exclusive'))
99 'exclusive'))
100 if not message and logfile:
100 if not message and logfile:
101 try:
101 try:
102 if logfile == '-':
102 if logfile == '-':
103 message = ui.fin.read()
103 message = ui.fin.read()
104 else:
104 else:
105 message = '\n'.join(util.readfile(logfile).splitlines())
105 message = '\n'.join(util.readfile(logfile).splitlines())
106 except IOError, inst:
106 except IOError, inst:
107 raise util.Abort(_("can't read commit message '%s': %s") %
107 raise util.Abort(_("can't read commit message '%s': %s") %
108 (logfile, inst.strerror))
108 (logfile, inst.strerror))
109 return message
109 return message
110
110
111 def loglimit(opts):
111 def loglimit(opts):
112 """get the log limit according to option -l/--limit"""
112 """get the log limit according to option -l/--limit"""
113 limit = opts.get('limit')
113 limit = opts.get('limit')
114 if limit:
114 if limit:
115 try:
115 try:
116 limit = int(limit)
116 limit = int(limit)
117 except ValueError:
117 except ValueError:
118 raise util.Abort(_('limit must be a positive integer'))
118 raise util.Abort(_('limit must be a positive integer'))
119 if limit <= 0:
119 if limit <= 0:
120 raise util.Abort(_('limit must be positive'))
120 raise util.Abort(_('limit must be positive'))
121 else:
121 else:
122 limit = None
122 limit = None
123 return limit
123 return limit
124
124
125 def makefilename(repo, pat, node, desc=None,
125 def makefilename(repo, pat, node, desc=None,
126 total=None, seqno=None, revwidth=None, pathname=None):
126 total=None, seqno=None, revwidth=None, pathname=None):
127 node_expander = {
127 node_expander = {
128 'H': lambda: hex(node),
128 'H': lambda: hex(node),
129 'R': lambda: str(repo.changelog.rev(node)),
129 'R': lambda: str(repo.changelog.rev(node)),
130 'h': lambda: short(node),
130 'h': lambda: short(node),
131 'm': lambda: re.sub('[^\w]', '_', str(desc))
131 'm': lambda: re.sub('[^\w]', '_', str(desc))
132 }
132 }
133 expander = {
133 expander = {
134 '%': lambda: '%',
134 '%': lambda: '%',
135 'b': lambda: os.path.basename(repo.root),
135 'b': lambda: os.path.basename(repo.root),
136 }
136 }
137
137
138 try:
138 try:
139 if node:
139 if node:
140 expander.update(node_expander)
140 expander.update(node_expander)
141 if node:
141 if node:
142 expander['r'] = (lambda:
142 expander['r'] = (lambda:
143 str(repo.changelog.rev(node)).zfill(revwidth or 0))
143 str(repo.changelog.rev(node)).zfill(revwidth or 0))
144 if total is not None:
144 if total is not None:
145 expander['N'] = lambda: str(total)
145 expander['N'] = lambda: str(total)
146 if seqno is not None:
146 if seqno is not None:
147 expander['n'] = lambda: str(seqno)
147 expander['n'] = lambda: str(seqno)
148 if total is not None and seqno is not None:
148 if total is not None and seqno is not None:
149 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
149 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
150 if pathname is not None:
150 if pathname is not None:
151 expander['s'] = lambda: os.path.basename(pathname)
151 expander['s'] = lambda: os.path.basename(pathname)
152 expander['d'] = lambda: os.path.dirname(pathname) or '.'
152 expander['d'] = lambda: os.path.dirname(pathname) or '.'
153 expander['p'] = lambda: pathname
153 expander['p'] = lambda: pathname
154
154
155 newname = []
155 newname = []
156 patlen = len(pat)
156 patlen = len(pat)
157 i = 0
157 i = 0
158 while i < patlen:
158 while i < patlen:
159 c = pat[i]
159 c = pat[i]
160 if c == '%':
160 if c == '%':
161 i += 1
161 i += 1
162 c = pat[i]
162 c = pat[i]
163 c = expander[c]()
163 c = expander[c]()
164 newname.append(c)
164 newname.append(c)
165 i += 1
165 i += 1
166 return ''.join(newname)
166 return ''.join(newname)
167 except KeyError, inst:
167 except KeyError, inst:
168 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
168 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
169 inst.args[0])
169 inst.args[0])
170
170
171 def makefileobj(repo, pat, node=None, desc=None, total=None,
171 def makefileobj(repo, pat, node=None, desc=None, total=None,
172 seqno=None, revwidth=None, mode='wb', pathname=None):
172 seqno=None, revwidth=None, mode='wb', pathname=None):
173
173
174 writable = mode not in ('r', 'rb')
174 writable = mode not in ('r', 'rb')
175
175
176 if not pat or pat == '-':
176 if not pat or pat == '-':
177 fp = writable and repo.ui.fout or repo.ui.fin
177 fp = writable and repo.ui.fout or repo.ui.fin
178 if util.safehasattr(fp, 'fileno'):
178 if util.safehasattr(fp, 'fileno'):
179 return os.fdopen(os.dup(fp.fileno()), mode)
179 return os.fdopen(os.dup(fp.fileno()), mode)
180 else:
180 else:
181 # if this fp can't be duped properly, return
181 # if this fp can't be duped properly, return
182 # a dummy object that can be closed
182 # a dummy object that can be closed
183 class wrappedfileobj(object):
183 class wrappedfileobj(object):
184 noop = lambda x: None
184 noop = lambda x: None
185 def __init__(self, f):
185 def __init__(self, f):
186 self.f = f
186 self.f = f
187 def __getattr__(self, attr):
187 def __getattr__(self, attr):
188 if attr == 'close':
188 if attr == 'close':
189 return self.noop
189 return self.noop
190 else:
190 else:
191 return getattr(self.f, attr)
191 return getattr(self.f, attr)
192
192
193 return wrappedfileobj(fp)
193 return wrappedfileobj(fp)
194 if util.safehasattr(pat, 'write') and writable:
194 if util.safehasattr(pat, 'write') and writable:
195 return pat
195 return pat
196 if util.safehasattr(pat, 'read') and 'r' in mode:
196 if util.safehasattr(pat, 'read') and 'r' in mode:
197 return pat
197 return pat
198 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
198 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
199 pathname),
199 pathname),
200 mode)
200 mode)
201
201
202 def openrevlog(repo, cmd, file_, opts):
202 def openrevlog(repo, cmd, file_, opts):
203 """opens the changelog, manifest, a filelog or a given revlog"""
203 """opens the changelog, manifest, a filelog or a given revlog"""
204 cl = opts['changelog']
204 cl = opts['changelog']
205 mf = opts['manifest']
205 mf = opts['manifest']
206 msg = None
206 msg = None
207 if cl and mf:
207 if cl and mf:
208 msg = _('cannot specify --changelog and --manifest at the same time')
208 msg = _('cannot specify --changelog and --manifest at the same time')
209 elif cl or mf:
209 elif cl or mf:
210 if file_:
210 if file_:
211 msg = _('cannot specify filename with --changelog or --manifest')
211 msg = _('cannot specify filename with --changelog or --manifest')
212 elif not repo:
212 elif not repo:
213 msg = _('cannot specify --changelog or --manifest '
213 msg = _('cannot specify --changelog or --manifest '
214 'without a repository')
214 'without a repository')
215 if msg:
215 if msg:
216 raise util.Abort(msg)
216 raise util.Abort(msg)
217
217
218 r = None
218 r = None
219 if repo:
219 if repo:
220 if cl:
220 if cl:
221 r = repo.changelog
221 r = repo.changelog
222 elif mf:
222 elif mf:
223 r = repo.manifest
223 r = repo.manifest
224 elif file_:
224 elif file_:
225 filelog = repo.file(file_)
225 filelog = repo.file(file_)
226 if len(filelog):
226 if len(filelog):
227 r = filelog
227 r = filelog
228 if not r:
228 if not r:
229 if not file_:
229 if not file_:
230 raise error.CommandError(cmd, _('invalid arguments'))
230 raise error.CommandError(cmd, _('invalid arguments'))
231 if not os.path.isfile(file_):
231 if not os.path.isfile(file_):
232 raise util.Abort(_("revlog '%s' not found") % file_)
232 raise util.Abort(_("revlog '%s' not found") % file_)
233 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
233 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
234 file_[:-2] + ".i")
234 file_[:-2] + ".i")
235 return r
235 return r
236
236
237 def copy(ui, repo, pats, opts, rename=False):
237 def copy(ui, repo, pats, opts, rename=False):
238 # called with the repo lock held
238 # called with the repo lock held
239 #
239 #
240 # hgsep => pathname that uses "/" to separate directories
240 # hgsep => pathname that uses "/" to separate directories
241 # ossep => pathname that uses os.sep to separate directories
241 # ossep => pathname that uses os.sep to separate directories
242 cwd = repo.getcwd()
242 cwd = repo.getcwd()
243 targets = {}
243 targets = {}
244 after = opts.get("after")
244 after = opts.get("after")
245 dryrun = opts.get("dry_run")
245 dryrun = opts.get("dry_run")
246 wctx = repo[None]
246 wctx = repo[None]
247
247
248 def walkpat(pat):
248 def walkpat(pat):
249 srcs = []
249 srcs = []
250 badstates = after and '?' or '?r'
250 badstates = after and '?' or '?r'
251 m = scmutil.match(repo[None], [pat], opts, globbed=True)
251 m = scmutil.match(repo[None], [pat], opts, globbed=True)
252 for abs in repo.walk(m):
252 for abs in repo.walk(m):
253 state = repo.dirstate[abs]
253 state = repo.dirstate[abs]
254 rel = m.rel(abs)
254 rel = m.rel(abs)
255 exact = m.exact(abs)
255 exact = m.exact(abs)
256 if state in badstates:
256 if state in badstates:
257 if exact and state == '?':
257 if exact and state == '?':
258 ui.warn(_('%s: not copying - file is not managed\n') % rel)
258 ui.warn(_('%s: not copying - file is not managed\n') % rel)
259 if exact and state == 'r':
259 if exact and state == 'r':
260 ui.warn(_('%s: not copying - file has been marked for'
260 ui.warn(_('%s: not copying - file has been marked for'
261 ' remove\n') % rel)
261 ' remove\n') % rel)
262 continue
262 continue
263 # abs: hgsep
263 # abs: hgsep
264 # rel: ossep
264 # rel: ossep
265 srcs.append((abs, rel, exact))
265 srcs.append((abs, rel, exact))
266 return srcs
266 return srcs
267
267
268 # abssrc: hgsep
268 # abssrc: hgsep
269 # relsrc: ossep
269 # relsrc: ossep
270 # otarget: ossep
270 # otarget: ossep
271 def copyfile(abssrc, relsrc, otarget, exact):
271 def copyfile(abssrc, relsrc, otarget, exact):
272 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
272 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
273 if '/' in abstarget:
273 if '/' in abstarget:
274 # We cannot normalize abstarget itself, this would prevent
274 # We cannot normalize abstarget itself, this would prevent
275 # case only renames, like a => A.
275 # case only renames, like a => A.
276 abspath, absname = abstarget.rsplit('/', 1)
276 abspath, absname = abstarget.rsplit('/', 1)
277 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
277 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
278 reltarget = repo.pathto(abstarget, cwd)
278 reltarget = repo.pathto(abstarget, cwd)
279 target = repo.wjoin(abstarget)
279 target = repo.wjoin(abstarget)
280 src = repo.wjoin(abssrc)
280 src = repo.wjoin(abssrc)
281 state = repo.dirstate[abstarget]
281 state = repo.dirstate[abstarget]
282
282
283 scmutil.checkportable(ui, abstarget)
283 scmutil.checkportable(ui, abstarget)
284
284
285 # check for collisions
285 # check for collisions
286 prevsrc = targets.get(abstarget)
286 prevsrc = targets.get(abstarget)
287 if prevsrc is not None:
287 if prevsrc is not None:
288 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
288 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
289 (reltarget, repo.pathto(abssrc, cwd),
289 (reltarget, repo.pathto(abssrc, cwd),
290 repo.pathto(prevsrc, cwd)))
290 repo.pathto(prevsrc, cwd)))
291 return
291 return
292
292
293 # check for overwrites
293 # check for overwrites
294 exists = os.path.lexists(target)
294 exists = os.path.lexists(target)
295 samefile = False
295 samefile = False
296 if exists and abssrc != abstarget:
296 if exists and abssrc != abstarget:
297 if (repo.dirstate.normalize(abssrc) ==
297 if (repo.dirstate.normalize(abssrc) ==
298 repo.dirstate.normalize(abstarget)):
298 repo.dirstate.normalize(abstarget)):
299 if not rename:
299 if not rename:
300 ui.warn(_("%s: can't copy - same file\n") % reltarget)
300 ui.warn(_("%s: can't copy - same file\n") % reltarget)
301 return
301 return
302 exists = False
302 exists = False
303 samefile = True
303 samefile = True
304
304
305 if not after and exists or after and state in 'mn':
305 if not after and exists or after and state in 'mn':
306 if not opts['force']:
306 if not opts['force']:
307 ui.warn(_('%s: not overwriting - file exists\n') %
307 ui.warn(_('%s: not overwriting - file exists\n') %
308 reltarget)
308 reltarget)
309 return
309 return
310
310
311 if after:
311 if after:
312 if not exists:
312 if not exists:
313 if rename:
313 if rename:
314 ui.warn(_('%s: not recording move - %s does not exist\n') %
314 ui.warn(_('%s: not recording move - %s does not exist\n') %
315 (relsrc, reltarget))
315 (relsrc, reltarget))
316 else:
316 else:
317 ui.warn(_('%s: not recording copy - %s does not exist\n') %
317 ui.warn(_('%s: not recording copy - %s does not exist\n') %
318 (relsrc, reltarget))
318 (relsrc, reltarget))
319 return
319 return
320 elif not dryrun:
320 elif not dryrun:
321 try:
321 try:
322 if exists:
322 if exists:
323 os.unlink(target)
323 os.unlink(target)
324 targetdir = os.path.dirname(target) or '.'
324 targetdir = os.path.dirname(target) or '.'
325 if not os.path.isdir(targetdir):
325 if not os.path.isdir(targetdir):
326 os.makedirs(targetdir)
326 os.makedirs(targetdir)
327 if samefile:
327 if samefile:
328 tmp = target + "~hgrename"
328 tmp = target + "~hgrename"
329 os.rename(src, tmp)
329 os.rename(src, tmp)
330 os.rename(tmp, target)
330 os.rename(tmp, target)
331 else:
331 else:
332 util.copyfile(src, target)
332 util.copyfile(src, target)
333 srcexists = True
333 srcexists = True
334 except IOError, inst:
334 except IOError, inst:
335 if inst.errno == errno.ENOENT:
335 if inst.errno == errno.ENOENT:
336 ui.warn(_('%s: deleted in working copy\n') % relsrc)
336 ui.warn(_('%s: deleted in working copy\n') % relsrc)
337 srcexists = False
337 srcexists = False
338 else:
338 else:
339 ui.warn(_('%s: cannot copy - %s\n') %
339 ui.warn(_('%s: cannot copy - %s\n') %
340 (relsrc, inst.strerror))
340 (relsrc, inst.strerror))
341 return True # report a failure
341 return True # report a failure
342
342
343 if ui.verbose or not exact:
343 if ui.verbose or not exact:
344 if rename:
344 if rename:
345 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
345 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
346 else:
346 else:
347 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
347 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
348
348
349 targets[abstarget] = abssrc
349 targets[abstarget] = abssrc
350
350
351 # fix up dirstate
351 # fix up dirstate
352 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
352 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
353 dryrun=dryrun, cwd=cwd)
353 dryrun=dryrun, cwd=cwd)
354 if rename and not dryrun:
354 if rename and not dryrun:
355 if not after and srcexists and not samefile:
355 if not after and srcexists and not samefile:
356 util.unlinkpath(repo.wjoin(abssrc))
356 util.unlinkpath(repo.wjoin(abssrc))
357 wctx.forget([abssrc])
357 wctx.forget([abssrc])
358
358
359 # pat: ossep
359 # pat: ossep
360 # dest ossep
360 # dest ossep
361 # srcs: list of (hgsep, hgsep, ossep, bool)
361 # srcs: list of (hgsep, hgsep, ossep, bool)
362 # return: function that takes hgsep and returns ossep
362 # return: function that takes hgsep and returns ossep
363 def targetpathfn(pat, dest, srcs):
363 def targetpathfn(pat, dest, srcs):
364 if os.path.isdir(pat):
364 if os.path.isdir(pat):
365 abspfx = scmutil.canonpath(repo.root, cwd, pat)
365 abspfx = scmutil.canonpath(repo.root, cwd, pat)
366 abspfx = util.localpath(abspfx)
366 abspfx = util.localpath(abspfx)
367 if destdirexists:
367 if destdirexists:
368 striplen = len(os.path.split(abspfx)[0])
368 striplen = len(os.path.split(abspfx)[0])
369 else:
369 else:
370 striplen = len(abspfx)
370 striplen = len(abspfx)
371 if striplen:
371 if striplen:
372 striplen += len(os.sep)
372 striplen += len(os.sep)
373 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
373 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
374 elif destdirexists:
374 elif destdirexists:
375 res = lambda p: os.path.join(dest,
375 res = lambda p: os.path.join(dest,
376 os.path.basename(util.localpath(p)))
376 os.path.basename(util.localpath(p)))
377 else:
377 else:
378 res = lambda p: dest
378 res = lambda p: dest
379 return res
379 return res
380
380
381 # pat: ossep
381 # pat: ossep
382 # dest ossep
382 # dest ossep
383 # srcs: list of (hgsep, hgsep, ossep, bool)
383 # srcs: list of (hgsep, hgsep, ossep, bool)
384 # return: function that takes hgsep and returns ossep
384 # return: function that takes hgsep and returns ossep
385 def targetpathafterfn(pat, dest, srcs):
385 def targetpathafterfn(pat, dest, srcs):
386 if matchmod.patkind(pat):
386 if matchmod.patkind(pat):
387 # a mercurial pattern
387 # a mercurial pattern
388 res = lambda p: os.path.join(dest,
388 res = lambda p: os.path.join(dest,
389 os.path.basename(util.localpath(p)))
389 os.path.basename(util.localpath(p)))
390 else:
390 else:
391 abspfx = scmutil.canonpath(repo.root, cwd, pat)
391 abspfx = scmutil.canonpath(repo.root, cwd, pat)
392 if len(abspfx) < len(srcs[0][0]):
392 if len(abspfx) < len(srcs[0][0]):
393 # A directory. Either the target path contains the last
393 # A directory. Either the target path contains the last
394 # component of the source path or it does not.
394 # component of the source path or it does not.
395 def evalpath(striplen):
395 def evalpath(striplen):
396 score = 0
396 score = 0
397 for s in srcs:
397 for s in srcs:
398 t = os.path.join(dest, util.localpath(s[0])[striplen:])
398 t = os.path.join(dest, util.localpath(s[0])[striplen:])
399 if os.path.lexists(t):
399 if os.path.lexists(t):
400 score += 1
400 score += 1
401 return score
401 return score
402
402
403 abspfx = util.localpath(abspfx)
403 abspfx = util.localpath(abspfx)
404 striplen = len(abspfx)
404 striplen = len(abspfx)
405 if striplen:
405 if striplen:
406 striplen += len(os.sep)
406 striplen += len(os.sep)
407 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
407 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
408 score = evalpath(striplen)
408 score = evalpath(striplen)
409 striplen1 = len(os.path.split(abspfx)[0])
409 striplen1 = len(os.path.split(abspfx)[0])
410 if striplen1:
410 if striplen1:
411 striplen1 += len(os.sep)
411 striplen1 += len(os.sep)
412 if evalpath(striplen1) > score:
412 if evalpath(striplen1) > score:
413 striplen = striplen1
413 striplen = striplen1
414 res = lambda p: os.path.join(dest,
414 res = lambda p: os.path.join(dest,
415 util.localpath(p)[striplen:])
415 util.localpath(p)[striplen:])
416 else:
416 else:
417 # a file
417 # a file
418 if destdirexists:
418 if destdirexists:
419 res = lambda p: os.path.join(dest,
419 res = lambda p: os.path.join(dest,
420 os.path.basename(util.localpath(p)))
420 os.path.basename(util.localpath(p)))
421 else:
421 else:
422 res = lambda p: dest
422 res = lambda p: dest
423 return res
423 return res
424
424
425
425
426 pats = scmutil.expandpats(pats)
426 pats = scmutil.expandpats(pats)
427 if not pats:
427 if not pats:
428 raise util.Abort(_('no source or destination specified'))
428 raise util.Abort(_('no source or destination specified'))
429 if len(pats) == 1:
429 if len(pats) == 1:
430 raise util.Abort(_('no destination specified'))
430 raise util.Abort(_('no destination specified'))
431 dest = pats.pop()
431 dest = pats.pop()
432 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
432 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
433 if not destdirexists:
433 if not destdirexists:
434 if len(pats) > 1 or matchmod.patkind(pats[0]):
434 if len(pats) > 1 or matchmod.patkind(pats[0]):
435 raise util.Abort(_('with multiple sources, destination must be an '
435 raise util.Abort(_('with multiple sources, destination must be an '
436 'existing directory'))
436 'existing directory'))
437 if util.endswithsep(dest):
437 if util.endswithsep(dest):
438 raise util.Abort(_('destination %s is not a directory') % dest)
438 raise util.Abort(_('destination %s is not a directory') % dest)
439
439
440 tfn = targetpathfn
440 tfn = targetpathfn
441 if after:
441 if after:
442 tfn = targetpathafterfn
442 tfn = targetpathafterfn
443 copylist = []
443 copylist = []
444 for pat in pats:
444 for pat in pats:
445 srcs = walkpat(pat)
445 srcs = walkpat(pat)
446 if not srcs:
446 if not srcs:
447 continue
447 continue
448 copylist.append((tfn(pat, dest, srcs), srcs))
448 copylist.append((tfn(pat, dest, srcs), srcs))
449 if not copylist:
449 if not copylist:
450 raise util.Abort(_('no files to copy'))
450 raise util.Abort(_('no files to copy'))
451
451
452 errors = 0
452 errors = 0
453 for targetpath, srcs in copylist:
453 for targetpath, srcs in copylist:
454 for abssrc, relsrc, exact in srcs:
454 for abssrc, relsrc, exact in srcs:
455 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
455 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
456 errors += 1
456 errors += 1
457
457
458 if errors:
458 if errors:
459 ui.warn(_('(consider using --after)\n'))
459 ui.warn(_('(consider using --after)\n'))
460
460
461 return errors != 0
461 return errors != 0
462
462
463 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
463 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
464 runargs=None, appendpid=False):
464 runargs=None, appendpid=False):
465 '''Run a command as a service.'''
465 '''Run a command as a service.'''
466
466
467 if opts['daemon'] and not opts['daemon_pipefds']:
467 if opts['daemon'] and not opts['daemon_pipefds']:
468 # Signal child process startup with file removal
468 # Signal child process startup with file removal
469 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
469 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
470 os.close(lockfd)
470 os.close(lockfd)
471 try:
471 try:
472 if not runargs:
472 if not runargs:
473 runargs = util.hgcmd() + sys.argv[1:]
473 runargs = util.hgcmd() + sys.argv[1:]
474 runargs.append('--daemon-pipefds=%s' % lockpath)
474 runargs.append('--daemon-pipefds=%s' % lockpath)
475 # Don't pass --cwd to the child process, because we've already
475 # Don't pass --cwd to the child process, because we've already
476 # changed directory.
476 # changed directory.
477 for i in xrange(1, len(runargs)):
477 for i in xrange(1, len(runargs)):
478 if runargs[i].startswith('--cwd='):
478 if runargs[i].startswith('--cwd='):
479 del runargs[i]
479 del runargs[i]
480 break
480 break
481 elif runargs[i].startswith('--cwd'):
481 elif runargs[i].startswith('--cwd'):
482 del runargs[i:i + 2]
482 del runargs[i:i + 2]
483 break
483 break
484 def condfn():
484 def condfn():
485 return not os.path.exists(lockpath)
485 return not os.path.exists(lockpath)
486 pid = util.rundetached(runargs, condfn)
486 pid = util.rundetached(runargs, condfn)
487 if pid < 0:
487 if pid < 0:
488 raise util.Abort(_('child process failed to start'))
488 raise util.Abort(_('child process failed to start'))
489 finally:
489 finally:
490 try:
490 try:
491 os.unlink(lockpath)
491 os.unlink(lockpath)
492 except OSError, e:
492 except OSError, e:
493 if e.errno != errno.ENOENT:
493 if e.errno != errno.ENOENT:
494 raise
494 raise
495 if parentfn:
495 if parentfn:
496 return parentfn(pid)
496 return parentfn(pid)
497 else:
497 else:
498 return
498 return
499
499
500 if initfn:
500 if initfn:
501 initfn()
501 initfn()
502
502
503 if opts['pid_file']:
503 if opts['pid_file']:
504 mode = appendpid and 'a' or 'w'
504 mode = appendpid and 'a' or 'w'
505 fp = open(opts['pid_file'], mode)
505 fp = open(opts['pid_file'], mode)
506 fp.write(str(os.getpid()) + '\n')
506 fp.write(str(os.getpid()) + '\n')
507 fp.close()
507 fp.close()
508
508
509 if opts['daemon_pipefds']:
509 if opts['daemon_pipefds']:
510 lockpath = opts['daemon_pipefds']
510 lockpath = opts['daemon_pipefds']
511 try:
511 try:
512 os.setsid()
512 os.setsid()
513 except AttributeError:
513 except AttributeError:
514 pass
514 pass
515 os.unlink(lockpath)
515 os.unlink(lockpath)
516 util.hidewindow()
516 util.hidewindow()
517 sys.stdout.flush()
517 sys.stdout.flush()
518 sys.stderr.flush()
518 sys.stderr.flush()
519
519
520 nullfd = os.open(os.devnull, os.O_RDWR)
520 nullfd = os.open(os.devnull, os.O_RDWR)
521 logfilefd = nullfd
521 logfilefd = nullfd
522 if logfile:
522 if logfile:
523 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
523 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
524 os.dup2(nullfd, 0)
524 os.dup2(nullfd, 0)
525 os.dup2(logfilefd, 1)
525 os.dup2(logfilefd, 1)
526 os.dup2(logfilefd, 2)
526 os.dup2(logfilefd, 2)
527 if nullfd not in (0, 1, 2):
527 if nullfd not in (0, 1, 2):
528 os.close(nullfd)
528 os.close(nullfd)
529 if logfile and logfilefd not in (0, 1, 2):
529 if logfile and logfilefd not in (0, 1, 2):
530 os.close(logfilefd)
530 os.close(logfilefd)
531
531
532 if runfn:
532 if runfn:
533 return runfn()
533 return runfn()
534
534
535 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
535 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
536 opts=None):
536 opts=None):
537 '''export changesets as hg patches.'''
537 '''export changesets as hg patches.'''
538
538
539 total = len(revs)
539 total = len(revs)
540 revwidth = max([len(str(rev)) for rev in revs])
540 revwidth = max([len(str(rev)) for rev in revs])
541
541
542 def single(rev, seqno, fp):
542 def single(rev, seqno, fp):
543 ctx = repo[rev]
543 ctx = repo[rev]
544 node = ctx.node()
544 node = ctx.node()
545 parents = [p.node() for p in ctx.parents() if p]
545 parents = [p.node() for p in ctx.parents() if p]
546 branch = ctx.branch()
546 branch = ctx.branch()
547 if switch_parent:
547 if switch_parent:
548 parents.reverse()
548 parents.reverse()
549 prev = (parents and parents[0]) or nullid
549 prev = (parents and parents[0]) or nullid
550
550
551 shouldclose = False
551 shouldclose = False
552 if not fp and len(template) > 0:
552 if not fp and len(template) > 0:
553 desc_lines = ctx.description().rstrip().split('\n')
553 desc_lines = ctx.description().rstrip().split('\n')
554 desc = desc_lines[0] #Commit always has a first line.
554 desc = desc_lines[0] #Commit always has a first line.
555 fp = makefileobj(repo, template, node, desc=desc, total=total,
555 fp = makefileobj(repo, template, node, desc=desc, total=total,
556 seqno=seqno, revwidth=revwidth, mode='ab')
556 seqno=seqno, revwidth=revwidth, mode='ab')
557 if fp != template:
557 if fp != template:
558 shouldclose = True
558 shouldclose = True
559 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
559 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
560 repo.ui.note("%s\n" % fp.name)
560 repo.ui.note("%s\n" % fp.name)
561
561
562 if not fp:
562 if not fp:
563 write = repo.ui.write
563 write = repo.ui.write
564 else:
564 else:
565 def write(s, **kw):
565 def write(s, **kw):
566 fp.write(s)
566 fp.write(s)
567
567
568
568
569 write("# HG changeset patch\n")
569 write("# HG changeset patch\n")
570 write("# User %s\n" % ctx.user())
570 write("# User %s\n" % ctx.user())
571 write("# Date %d %d\n" % ctx.date())
571 write("# Date %d %d\n" % ctx.date())
572 if branch and branch != 'default':
572 if branch and branch != 'default':
573 write("# Branch %s\n" % branch)
573 write("# Branch %s\n" % branch)
574 write("# Node ID %s\n" % hex(node))
574 write("# Node ID %s\n" % hex(node))
575 write("# Parent %s\n" % hex(prev))
575 write("# Parent %s\n" % hex(prev))
576 if len(parents) > 1:
576 if len(parents) > 1:
577 write("# Parent %s\n" % hex(parents[1]))
577 write("# Parent %s\n" % hex(parents[1]))
578 write(ctx.description().rstrip())
578 write(ctx.description().rstrip())
579 write("\n\n")
579 write("\n\n")
580
580
581 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
581 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
582 write(chunk, label=label)
582 write(chunk, label=label)
583
583
584 if shouldclose:
584 if shouldclose:
585 fp.close()
585 fp.close()
586
586
587 for seqno, rev in enumerate(revs):
587 for seqno, rev in enumerate(revs):
588 single(rev, seqno + 1, fp)
588 single(rev, seqno + 1, fp)
589
589
590 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
590 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
591 changes=None, stat=False, fp=None, prefix='',
591 changes=None, stat=False, fp=None, prefix='',
592 listsubrepos=False):
592 listsubrepos=False):
593 '''show diff or diffstat.'''
593 '''show diff or diffstat.'''
594 if fp is None:
594 if fp is None:
595 write = ui.write
595 write = ui.write
596 else:
596 else:
597 def write(s, **kw):
597 def write(s, **kw):
598 fp.write(s)
598 fp.write(s)
599
599
600 if stat:
600 if stat:
601 diffopts = diffopts.copy(context=0)
601 diffopts = diffopts.copy(context=0)
602 width = 80
602 width = 80
603 if not ui.plain():
603 if not ui.plain():
604 width = ui.termwidth()
604 width = ui.termwidth()
605 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
605 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
606 prefix=prefix)
606 prefix=prefix)
607 for chunk, label in patch.diffstatui(util.iterlines(chunks),
607 for chunk, label in patch.diffstatui(util.iterlines(chunks),
608 width=width,
608 width=width,
609 git=diffopts.git):
609 git=diffopts.git):
610 write(chunk, label=label)
610 write(chunk, label=label)
611 else:
611 else:
612 for chunk, label in patch.diffui(repo, node1, node2, match,
612 for chunk, label in patch.diffui(repo, node1, node2, match,
613 changes, diffopts, prefix=prefix):
613 changes, diffopts, prefix=prefix):
614 write(chunk, label=label)
614 write(chunk, label=label)
615
615
616 if listsubrepos:
616 if listsubrepos:
617 ctx1 = repo[node1]
617 ctx1 = repo[node1]
618 ctx2 = repo[node2]
618 ctx2 = repo[node2]
619 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
619 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
620 tempnode2 = node2
620 tempnode2 = node2
621 try:
621 try:
622 if node2 is not None:
622 if node2 is not None:
623 tempnode2 = ctx2.substate[subpath][1]
623 tempnode2 = ctx2.substate[subpath][1]
624 except KeyError:
624 except KeyError:
625 # A subrepo that existed in node1 was deleted between node1 and
625 # A subrepo that existed in node1 was deleted between node1 and
626 # node2 (inclusive). Thus, ctx2's substate won't contain that
626 # node2 (inclusive). Thus, ctx2's substate won't contain that
627 # subpath. The best we can do is to ignore it.
627 # subpath. The best we can do is to ignore it.
628 tempnode2 = None
628 tempnode2 = None
629 submatch = matchmod.narrowmatcher(subpath, match)
629 submatch = matchmod.narrowmatcher(subpath, match)
630 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
630 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
631 stat=stat, fp=fp, prefix=prefix)
631 stat=stat, fp=fp, prefix=prefix)
632
632
633 class changeset_printer(object):
633 class changeset_printer(object):
634 '''show changeset information when templating not requested.'''
634 '''show changeset information when templating not requested.'''
635
635
636 def __init__(self, ui, repo, patch, diffopts, buffered):
636 def __init__(self, ui, repo, patch, diffopts, buffered):
637 self.ui = ui
637 self.ui = ui
638 self.repo = repo
638 self.repo = repo
639 self.buffered = buffered
639 self.buffered = buffered
640 self.patch = patch
640 self.patch = patch
641 self.diffopts = diffopts
641 self.diffopts = diffopts
642 self.header = {}
642 self.header = {}
643 self.hunk = {}
643 self.hunk = {}
644 self.lastheader = None
644 self.lastheader = None
645 self.footer = None
645 self.footer = None
646
646
647 def flush(self, rev):
647 def flush(self, rev):
648 if rev in self.header:
648 if rev in self.header:
649 h = self.header[rev]
649 h = self.header[rev]
650 if h != self.lastheader:
650 if h != self.lastheader:
651 self.lastheader = h
651 self.lastheader = h
652 self.ui.write(h)
652 self.ui.write(h)
653 del self.header[rev]
653 del self.header[rev]
654 if rev in self.hunk:
654 if rev in self.hunk:
655 self.ui.write(self.hunk[rev])
655 self.ui.write(self.hunk[rev])
656 del self.hunk[rev]
656 del self.hunk[rev]
657 return 1
657 return 1
658 return 0
658 return 0
659
659
660 def close(self):
660 def close(self):
661 if self.footer:
661 if self.footer:
662 self.ui.write(self.footer)
662 self.ui.write(self.footer)
663
663
664 def show(self, ctx, copies=None, matchfn=None, **props):
664 def show(self, ctx, copies=None, matchfn=None, **props):
665 if self.buffered:
665 if self.buffered:
666 self.ui.pushbuffer()
666 self.ui.pushbuffer()
667 self._show(ctx, copies, matchfn, props)
667 self._show(ctx, copies, matchfn, props)
668 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
668 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
669 else:
669 else:
670 self._show(ctx, copies, matchfn, props)
670 self._show(ctx, copies, matchfn, props)
671
671
672 def _show(self, ctx, copies, matchfn, props):
672 def _show(self, ctx, copies, matchfn, props):
673 '''show a single changeset or file revision'''
673 '''show a single changeset or file revision'''
674 changenode = ctx.node()
674 changenode = ctx.node()
675 rev = ctx.rev()
675 rev = ctx.rev()
676
676
677 if self.ui.quiet:
677 if self.ui.quiet:
678 self.ui.write("%d:%s\n" % (rev, short(changenode)),
678 self.ui.write("%d:%s\n" % (rev, short(changenode)),
679 label='log.node')
679 label='log.node')
680 return
680 return
681
681
682 log = self.repo.changelog
682 log = self.repo.changelog
683 date = util.datestr(ctx.date())
683 date = util.datestr(ctx.date())
684
684
685 hexfunc = self.ui.debugflag and hex or short
685 hexfunc = self.ui.debugflag and hex or short
686
686
687 parents = [(p, hexfunc(log.node(p)))
687 parents = [(p, hexfunc(log.node(p)))
688 for p in self._meaningful_parentrevs(log, rev)]
688 for p in self._meaningful_parentrevs(log, rev)]
689
689
690 # i18n: column positioning for "hg log"
690 # i18n: column positioning for "hg log"
691 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
691 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
692 label='log.changeset changeset.%s' % ctx.phasestr())
692 label='log.changeset changeset.%s' % ctx.phasestr())
693
693
694 branch = ctx.branch()
694 branch = ctx.branch()
695 # don't show the default branch name
695 # don't show the default branch name
696 if branch != 'default':
696 if branch != 'default':
697 # i18n: column positioning for "hg log"
697 # i18n: column positioning for "hg log"
698 self.ui.write(_("branch: %s\n") % branch,
698 self.ui.write(_("branch: %s\n") % branch,
699 label='log.branch')
699 label='log.branch')
700 for bookmark in self.repo.nodebookmarks(changenode):
700 for bookmark in self.repo.nodebookmarks(changenode):
701 # i18n: column positioning for "hg log"
701 # i18n: column positioning for "hg log"
702 self.ui.write(_("bookmark: %s\n") % bookmark,
702 self.ui.write(_("bookmark: %s\n") % bookmark,
703 label='log.bookmark')
703 label='log.bookmark')
704 for tag in self.repo.nodetags(changenode):
704 for tag in self.repo.nodetags(changenode):
705 # i18n: column positioning for "hg log"
705 # i18n: column positioning for "hg log"
706 self.ui.write(_("tag: %s\n") % tag,
706 self.ui.write(_("tag: %s\n") % tag,
707 label='log.tag')
707 label='log.tag')
708 if self.ui.debugflag and ctx.phase():
708 if self.ui.debugflag and ctx.phase():
709 # i18n: column positioning for "hg log"
709 # i18n: column positioning for "hg log"
710 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
710 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
711 label='log.phase')
711 label='log.phase')
712 for parent in parents:
712 for parent in parents:
713 # i18n: column positioning for "hg log"
713 # i18n: column positioning for "hg log"
714 self.ui.write(_("parent: %d:%s\n") % parent,
714 self.ui.write(_("parent: %d:%s\n") % parent,
715 label='log.parent changeset.%s' % ctx.phasestr())
715 label='log.parent changeset.%s' % ctx.phasestr())
716
716
717 if self.ui.debugflag:
717 if self.ui.debugflag:
718 mnode = ctx.manifestnode()
718 mnode = ctx.manifestnode()
719 # i18n: column positioning for "hg log"
719 # i18n: column positioning for "hg log"
720 self.ui.write(_("manifest: %d:%s\n") %
720 self.ui.write(_("manifest: %d:%s\n") %
721 (self.repo.manifest.rev(mnode), hex(mnode)),
721 (self.repo.manifest.rev(mnode), hex(mnode)),
722 label='ui.debug log.manifest')
722 label='ui.debug log.manifest')
723 # i18n: column positioning for "hg log"
723 # i18n: column positioning for "hg log"
724 self.ui.write(_("user: %s\n") % ctx.user(),
724 self.ui.write(_("user: %s\n") % ctx.user(),
725 label='log.user')
725 label='log.user')
726 # i18n: column positioning for "hg log"
726 # i18n: column positioning for "hg log"
727 self.ui.write(_("date: %s\n") % date,
727 self.ui.write(_("date: %s\n") % date,
728 label='log.date')
728 label='log.date')
729
729
730 if self.ui.debugflag:
730 if self.ui.debugflag:
731 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
731 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
732 for key, value in zip([# i18n: column positioning for "hg log"
732 for key, value in zip([# i18n: column positioning for "hg log"
733 _("files:"),
733 _("files:"),
734 # i18n: column positioning for "hg log"
734 # i18n: column positioning for "hg log"
735 _("files+:"),
735 _("files+:"),
736 # i18n: column positioning for "hg log"
736 # i18n: column positioning for "hg log"
737 _("files-:")], files):
737 _("files-:")], files):
738 if value:
738 if value:
739 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
739 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
740 label='ui.debug log.files')
740 label='ui.debug log.files')
741 elif ctx.files() and self.ui.verbose:
741 elif ctx.files() and self.ui.verbose:
742 # i18n: column positioning for "hg log"
742 # i18n: column positioning for "hg log"
743 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
743 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
744 label='ui.note log.files')
744 label='ui.note log.files')
745 if copies and self.ui.verbose:
745 if copies and self.ui.verbose:
746 copies = ['%s (%s)' % c for c in copies]
746 copies = ['%s (%s)' % c for c in copies]
747 # i18n: column positioning for "hg log"
747 # i18n: column positioning for "hg log"
748 self.ui.write(_("copies: %s\n") % ' '.join(copies),
748 self.ui.write(_("copies: %s\n") % ' '.join(copies),
749 label='ui.note log.copies')
749 label='ui.note log.copies')
750
750
751 extra = ctx.extra()
751 extra = ctx.extra()
752 if extra and self.ui.debugflag:
752 if extra and self.ui.debugflag:
753 for key, value in sorted(extra.items()):
753 for key, value in sorted(extra.items()):
754 # i18n: column positioning for "hg log"
754 # i18n: column positioning for "hg log"
755 self.ui.write(_("extra: %s=%s\n")
755 self.ui.write(_("extra: %s=%s\n")
756 % (key, value.encode('string_escape')),
756 % (key, value.encode('string_escape')),
757 label='ui.debug log.extra')
757 label='ui.debug log.extra')
758
758
759 description = ctx.description().strip()
759 description = ctx.description().strip()
760 if description:
760 if description:
761 if self.ui.verbose:
761 if self.ui.verbose:
762 self.ui.write(_("description:\n"),
762 self.ui.write(_("description:\n"),
763 label='ui.note log.description')
763 label='ui.note log.description')
764 self.ui.write(description,
764 self.ui.write(description,
765 label='ui.note log.description')
765 label='ui.note log.description')
766 self.ui.write("\n\n")
766 self.ui.write("\n\n")
767 else:
767 else:
768 # i18n: column positioning for "hg log"
768 # i18n: column positioning for "hg log"
769 self.ui.write(_("summary: %s\n") %
769 self.ui.write(_("summary: %s\n") %
770 description.splitlines()[0],
770 description.splitlines()[0],
771 label='log.summary')
771 label='log.summary')
772 self.ui.write("\n")
772 self.ui.write("\n")
773
773
774 self.showpatch(changenode, matchfn)
774 self.showpatch(changenode, matchfn)
775
775
776 def showpatch(self, node, matchfn):
776 def showpatch(self, node, matchfn):
777 if not matchfn:
777 if not matchfn:
778 matchfn = self.patch
778 matchfn = self.patch
779 if matchfn:
779 if matchfn:
780 stat = self.diffopts.get('stat')
780 stat = self.diffopts.get('stat')
781 diff = self.diffopts.get('patch')
781 diff = self.diffopts.get('patch')
782 diffopts = patch.diffopts(self.ui, self.diffopts)
782 diffopts = patch.diffopts(self.ui, self.diffopts)
783 prev = self.repo.changelog.parents(node)[0]
783 prev = self.repo.changelog.parents(node)[0]
784 if stat:
784 if stat:
785 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
785 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
786 match=matchfn, stat=True)
786 match=matchfn, stat=True)
787 if diff:
787 if diff:
788 if stat:
788 if stat:
789 self.ui.write("\n")
789 self.ui.write("\n")
790 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
790 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
791 match=matchfn, stat=False)
791 match=matchfn, stat=False)
792 self.ui.write("\n")
792 self.ui.write("\n")
793
793
794 def _meaningful_parentrevs(self, log, rev):
794 def _meaningful_parentrevs(self, log, rev):
795 """Return list of meaningful (or all if debug) parentrevs for rev.
795 """Return list of meaningful (or all if debug) parentrevs for rev.
796
796
797 For merges (two non-nullrev revisions) both parents are meaningful.
797 For merges (two non-nullrev revisions) both parents are meaningful.
798 Otherwise the first parent revision is considered meaningful if it
798 Otherwise the first parent revision is considered meaningful if it
799 is not the preceding revision.
799 is not the preceding revision.
800 """
800 """
801 parents = log.parentrevs(rev)
801 parents = log.parentrevs(rev)
802 if not self.ui.debugflag and parents[1] == nullrev:
802 if not self.ui.debugflag and parents[1] == nullrev:
803 if parents[0] >= rev - 1:
803 if parents[0] >= rev - 1:
804 parents = []
804 parents = []
805 else:
805 else:
806 parents = [parents[0]]
806 parents = [parents[0]]
807 return parents
807 return parents
808
808
809
809
810 class changeset_templater(changeset_printer):
810 class changeset_templater(changeset_printer):
811 '''format changeset information.'''
811 '''format changeset information.'''
812
812
813 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
813 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
814 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
814 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
815 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
815 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
816 defaulttempl = {
816 defaulttempl = {
817 'parent': '{rev}:{node|formatnode} ',
817 'parent': '{rev}:{node|formatnode} ',
818 'manifest': '{rev}:{node|formatnode}',
818 'manifest': '{rev}:{node|formatnode}',
819 'file_copy': '{name} ({source})',
819 'file_copy': '{name} ({source})',
820 'extra': '{key}={value|stringescape}'
820 'extra': '{key}={value|stringescape}'
821 }
821 }
822 # filecopy is preserved for compatibility reasons
822 # filecopy is preserved for compatibility reasons
823 defaulttempl['filecopy'] = defaulttempl['file_copy']
823 defaulttempl['filecopy'] = defaulttempl['file_copy']
824 self.t = templater.templater(mapfile, {'formatnode': formatnode},
824 self.t = templater.templater(mapfile, {'formatnode': formatnode},
825 cache=defaulttempl)
825 cache=defaulttempl)
826 self.cache = {}
826 self.cache = {}
827
827
828 def use_template(self, t):
828 def use_template(self, t):
829 '''set template string to use'''
829 '''set template string to use'''
830 self.t.cache['changeset'] = t
830 self.t.cache['changeset'] = t
831
831
832 def _meaningful_parentrevs(self, ctx):
832 def _meaningful_parentrevs(self, ctx):
833 """Return list of meaningful (or all if debug) parentrevs for rev.
833 """Return list of meaningful (or all if debug) parentrevs for rev.
834 """
834 """
835 parents = ctx.parents()
835 parents = ctx.parents()
836 if len(parents) > 1:
836 if len(parents) > 1:
837 return parents
837 return parents
838 if self.ui.debugflag:
838 if self.ui.debugflag:
839 return [parents[0], self.repo['null']]
839 return [parents[0], self.repo['null']]
840 if parents[0].rev() >= ctx.rev() - 1:
840 if parents[0].rev() >= ctx.rev() - 1:
841 return []
841 return []
842 return parents
842 return parents
843
843
844 def _show(self, ctx, copies, matchfn, props):
844 def _show(self, ctx, copies, matchfn, props):
845 '''show a single changeset or file revision'''
845 '''show a single changeset or file revision'''
846
846
847 showlist = templatekw.showlist
847 showlist = templatekw.showlist
848
848
849 # showparents() behaviour depends on ui trace level which
849 # showparents() behaviour depends on ui trace level which
850 # causes unexpected behaviours at templating level and makes
850 # causes unexpected behaviours at templating level and makes
851 # it harder to extract it in a standalone function. Its
851 # it harder to extract it in a standalone function. Its
852 # behaviour cannot be changed so leave it here for now.
852 # behaviour cannot be changed so leave it here for now.
853 def showparents(**args):
853 def showparents(**args):
854 ctx = args['ctx']
854 ctx = args['ctx']
855 parents = [[('rev', p.rev()), ('node', p.hex())]
855 parents = [[('rev', p.rev()), ('node', p.hex())]
856 for p in self._meaningful_parentrevs(ctx)]
856 for p in self._meaningful_parentrevs(ctx)]
857 return showlist('parent', parents, **args)
857 return showlist('parent', parents, **args)
858
858
859 props = props.copy()
859 props = props.copy()
860 props.update(templatekw.keywords)
860 props.update(templatekw.keywords)
861 props['parents'] = showparents
861 props['parents'] = showparents
862 props['templ'] = self.t
862 props['templ'] = self.t
863 props['ctx'] = ctx
863 props['ctx'] = ctx
864 props['repo'] = self.repo
864 props['repo'] = self.repo
865 props['revcache'] = {'copies': copies}
865 props['revcache'] = {'copies': copies}
866 props['cache'] = self.cache
866 props['cache'] = self.cache
867
867
868 # find correct templates for current mode
868 # find correct templates for current mode
869
869
870 tmplmodes = [
870 tmplmodes = [
871 (True, None),
871 (True, None),
872 (self.ui.verbose, 'verbose'),
872 (self.ui.verbose, 'verbose'),
873 (self.ui.quiet, 'quiet'),
873 (self.ui.quiet, 'quiet'),
874 (self.ui.debugflag, 'debug'),
874 (self.ui.debugflag, 'debug'),
875 ]
875 ]
876
876
877 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
877 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
878 for mode, postfix in tmplmodes:
878 for mode, postfix in tmplmodes:
879 for type in types:
879 for type in types:
880 cur = postfix and ('%s_%s' % (type, postfix)) or type
880 cur = postfix and ('%s_%s' % (type, postfix)) or type
881 if mode and cur in self.t:
881 if mode and cur in self.t:
882 types[type] = cur
882 types[type] = cur
883
883
884 try:
884 try:
885
885
886 # write header
886 # write header
887 if types['header']:
887 if types['header']:
888 h = templater.stringify(self.t(types['header'], **props))
888 h = templater.stringify(self.t(types['header'], **props))
889 if self.buffered:
889 if self.buffered:
890 self.header[ctx.rev()] = h
890 self.header[ctx.rev()] = h
891 else:
891 else:
892 if self.lastheader != h:
892 if self.lastheader != h:
893 self.lastheader = h
893 self.lastheader = h
894 self.ui.write(h)
894 self.ui.write(h)
895
895
896 # write changeset metadata, then patch if requested
896 # write changeset metadata, then patch if requested
897 key = types['changeset']
897 key = types['changeset']
898 self.ui.write(templater.stringify(self.t(key, **props)))
898 self.ui.write(templater.stringify(self.t(key, **props)))
899 self.showpatch(ctx.node(), matchfn)
899 self.showpatch(ctx.node(), matchfn)
900
900
901 if types['footer']:
901 if types['footer']:
902 if not self.footer:
902 if not self.footer:
903 self.footer = templater.stringify(self.t(types['footer'],
903 self.footer = templater.stringify(self.t(types['footer'],
904 **props))
904 **props))
905
905
906 except KeyError, inst:
906 except KeyError, inst:
907 msg = _("%s: no key named '%s'")
907 msg = _("%s: no key named '%s'")
908 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
908 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
909 except SyntaxError, inst:
909 except SyntaxError, inst:
910 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
910 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
911
911
912 def show_changeset(ui, repo, opts, buffered=False):
912 def show_changeset(ui, repo, opts, buffered=False):
913 """show one changeset using template or regular display.
913 """show one changeset using template or regular display.
914
914
915 Display format will be the first non-empty hit of:
915 Display format will be the first non-empty hit of:
916 1. option 'template'
916 1. option 'template'
917 2. option 'style'
917 2. option 'style'
918 3. [ui] setting 'logtemplate'
918 3. [ui] setting 'logtemplate'
919 4. [ui] setting 'style'
919 4. [ui] setting 'style'
920 If all of these values are either the unset or the empty string,
920 If all of these values are either the unset or the empty string,
921 regular display via changeset_printer() is done.
921 regular display via changeset_printer() is done.
922 """
922 """
923 # options
923 # options
924 patch = False
924 patch = False
925 if opts.get('patch') or opts.get('stat'):
925 if opts.get('patch') or opts.get('stat'):
926 patch = scmutil.matchall(repo)
926 patch = scmutil.matchall(repo)
927
927
928 tmpl = opts.get('template')
928 tmpl = opts.get('template')
929 style = None
929 style = None
930 if tmpl:
930 if tmpl:
931 tmpl = templater.parsestring(tmpl, quoted=False)
931 tmpl = templater.parsestring(tmpl, quoted=False)
932 else:
932 else:
933 style = opts.get('style')
933 style = opts.get('style')
934
934
935 # ui settings
935 # ui settings
936 if not (tmpl or style):
936 if not (tmpl or style):
937 tmpl = ui.config('ui', 'logtemplate')
937 tmpl = ui.config('ui', 'logtemplate')
938 if tmpl:
938 if tmpl:
939 try:
939 try:
940 tmpl = templater.parsestring(tmpl)
940 tmpl = templater.parsestring(tmpl)
941 except SyntaxError:
941 except SyntaxError:
942 tmpl = templater.parsestring(tmpl, quoted=False)
942 tmpl = templater.parsestring(tmpl, quoted=False)
943 else:
943 else:
944 style = util.expandpath(ui.config('ui', 'style', ''))
944 style = util.expandpath(ui.config('ui', 'style', ''))
945
945
946 if not (tmpl or style):
946 if not (tmpl or style):
947 return changeset_printer(ui, repo, patch, opts, buffered)
947 return changeset_printer(ui, repo, patch, opts, buffered)
948
948
949 mapfile = None
949 mapfile = None
950 if style and not tmpl:
950 if style and not tmpl:
951 mapfile = style
951 mapfile = style
952 if not os.path.split(mapfile)[0]:
952 if not os.path.split(mapfile)[0]:
953 mapname = (templater.templatepath('map-cmdline.' + mapfile)
953 mapname = (templater.templatepath('map-cmdline.' + mapfile)
954 or templater.templatepath(mapfile))
954 or templater.templatepath(mapfile))
955 if mapname:
955 if mapname:
956 mapfile = mapname
956 mapfile = mapname
957
957
958 try:
958 try:
959 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
959 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
960 except SyntaxError, inst:
960 except SyntaxError, inst:
961 raise util.Abort(inst.args[0])
961 raise util.Abort(inst.args[0])
962 if tmpl:
962 if tmpl:
963 t.use_template(tmpl)
963 t.use_template(tmpl)
964 return t
964 return t
965
965
966 def finddate(ui, repo, date):
966 def finddate(ui, repo, date):
967 """Find the tipmost changeset that matches the given date spec"""
967 """Find the tipmost changeset that matches the given date spec"""
968
968
969 df = util.matchdate(date)
969 df = util.matchdate(date)
970 m = scmutil.matchall(repo)
970 m = scmutil.matchall(repo)
971 results = {}
971 results = {}
972
972
973 def prep(ctx, fns):
973 def prep(ctx, fns):
974 d = ctx.date()
974 d = ctx.date()
975 if df(d[0]):
975 if df(d[0]):
976 results[ctx.rev()] = d
976 results[ctx.rev()] = d
977
977
978 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
978 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
979 rev = ctx.rev()
979 rev = ctx.rev()
980 if rev in results:
980 if rev in results:
981 ui.status(_("found revision %s from %s\n") %
981 ui.status(_("found revision %s from %s\n") %
982 (rev, util.datestr(results[rev])))
982 (rev, util.datestr(results[rev])))
983 return str(rev)
983 return str(rev)
984
984
985 raise util.Abort(_("revision matching date not found"))
985 raise util.Abort(_("revision matching date not found"))
986
986
987 def increasingwindows(start, end, windowsize=8, sizelimit=512):
987 def increasingwindows(start, end, windowsize=8, sizelimit=512):
988 if start < end:
988 if start < end:
989 while start < end:
989 while start < end:
990 yield start, min(windowsize, end - start)
990 yield start, min(windowsize, end - start)
991 start += windowsize
991 start += windowsize
992 if windowsize < sizelimit:
992 if windowsize < sizelimit:
993 windowsize *= 2
993 windowsize *= 2
994 else:
994 else:
995 while start > end:
995 while start > end:
996 yield start, min(windowsize, start - end - 1)
996 yield start, min(windowsize, start - end - 1)
997 start -= windowsize
997 start -= windowsize
998 if windowsize < sizelimit:
998 if windowsize < sizelimit:
999 windowsize *= 2
999 windowsize *= 2
1000
1000
1001 def walkchangerevs(repo, match, opts, prepare):
1001 def walkchangerevs(repo, match, opts, prepare):
1002 '''Iterate over files and the revs in which they changed.
1002 '''Iterate over files and the revs in which they changed.
1003
1003
1004 Callers most commonly need to iterate backwards over the history
1004 Callers most commonly need to iterate backwards over the history
1005 in which they are interested. Doing so has awful (quadratic-looking)
1005 in which they are interested. Doing so has awful (quadratic-looking)
1006 performance, so we use iterators in a "windowed" way.
1006 performance, so we use iterators in a "windowed" way.
1007
1007
1008 We walk a window of revisions in the desired order. Within the
1008 We walk a window of revisions in the desired order. Within the
1009 window, we first walk forwards to gather data, then in the desired
1009 window, we first walk forwards to gather data, then in the desired
1010 order (usually backwards) to display it.
1010 order (usually backwards) to display it.
1011
1011
1012 This function returns an iterator yielding contexts. Before
1012 This function returns an iterator yielding contexts. Before
1013 yielding each context, the iterator will first call the prepare
1013 yielding each context, the iterator will first call the prepare
1014 function on each context in the window in forward order.'''
1014 function on each context in the window in forward order.'''
1015
1015
1016 follow = opts.get('follow') or opts.get('follow_first')
1016 follow = opts.get('follow') or opts.get('follow_first')
1017
1017
1018 if not len(repo):
1018 if not len(repo):
1019 return []
1019 return []
1020 if opts.get('rev'):
1020 if opts.get('rev'):
1021 revs = scmutil.revrange(repo, opts.get('rev'))
1021 revs = scmutil.revrange(repo, opts.get('rev'))
1022 elif follow:
1022 elif follow:
1023 revs = repo.revs('reverse(:.)')
1023 revs = repo.revs('reverse(:.)')
1024 else:
1024 else:
1025 revs = list(repo)
1025 revs = list(repo)
1026 revs.reverse()
1026 revs.reverse()
1027 if not revs:
1027 if not revs:
1028 return []
1028 return []
1029 wanted = set()
1029 wanted = set()
1030 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1030 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1031 fncache = {}
1031 fncache = {}
1032 change = repo.changectx
1032 change = repo.changectx
1033
1033
1034 # First step is to fill wanted, the set of revisions that we want to yield.
1034 # First step is to fill wanted, the set of revisions that we want to yield.
1035 # When it does not induce extra cost, we also fill fncache for revisions in
1035 # When it does not induce extra cost, we also fill fncache for revisions in
1036 # wanted: a cache of filenames that were changed (ctx.files()) and that
1036 # wanted: a cache of filenames that were changed (ctx.files()) and that
1037 # match the file filtering conditions.
1037 # match the file filtering conditions.
1038
1038
1039 if not slowpath and not match.files():
1039 if not slowpath and not match.files():
1040 # No files, no patterns. Display all revs.
1040 # No files, no patterns. Display all revs.
1041 wanted = set(revs)
1041 wanted = set(revs)
1042 copies = []
1042 copies = []
1043
1043
1044 if not slowpath and match.files():
1044 if not slowpath and match.files():
1045 # We only have to read through the filelog to find wanted revisions
1045 # We only have to read through the filelog to find wanted revisions
1046
1046
1047 minrev, maxrev = min(revs), max(revs)
1047 minrev, maxrev = min(revs), max(revs)
1048 def filerevgen(filelog, last):
1048 def filerevgen(filelog, last):
1049 """
1049 """
1050 Only files, no patterns. Check the history of each file.
1050 Only files, no patterns. Check the history of each file.
1051
1051
1052 Examines filelog entries within minrev, maxrev linkrev range
1052 Examines filelog entries within minrev, maxrev linkrev range
1053 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1053 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1054 tuples in backwards order
1054 tuples in backwards order
1055 """
1055 """
1056 cl_count = len(repo)
1056 cl_count = len(repo)
1057 revs = []
1057 revs = []
1058 for j in xrange(0, last + 1):
1058 for j in xrange(0, last + 1):
1059 linkrev = filelog.linkrev(j)
1059 linkrev = filelog.linkrev(j)
1060 if linkrev < minrev:
1060 if linkrev < minrev:
1061 continue
1061 continue
1062 # only yield rev for which we have the changelog, it can
1062 # only yield rev for which we have the changelog, it can
1063 # happen while doing "hg log" during a pull or commit
1063 # happen while doing "hg log" during a pull or commit
1064 if linkrev >= cl_count:
1064 if linkrev >= cl_count:
1065 break
1065 break
1066
1066
1067 parentlinkrevs = []
1067 parentlinkrevs = []
1068 for p in filelog.parentrevs(j):
1068 for p in filelog.parentrevs(j):
1069 if p != nullrev:
1069 if p != nullrev:
1070 parentlinkrevs.append(filelog.linkrev(p))
1070 parentlinkrevs.append(filelog.linkrev(p))
1071 n = filelog.node(j)
1071 n = filelog.node(j)
1072 revs.append((linkrev, parentlinkrevs,
1072 revs.append((linkrev, parentlinkrevs,
1073 follow and filelog.renamed(n)))
1073 follow and filelog.renamed(n)))
1074
1074
1075 return reversed(revs)
1075 return reversed(revs)
1076 def iterfiles():
1076 def iterfiles():
1077 pctx = repo['.']
1077 pctx = repo['.']
1078 for filename in match.files():
1078 for filename in match.files():
1079 if follow:
1079 if follow:
1080 if filename not in pctx:
1080 if filename not in pctx:
1081 raise util.Abort(_('cannot follow file not in parent '
1081 raise util.Abort(_('cannot follow file not in parent '
1082 'revision: "%s"') % filename)
1082 'revision: "%s"') % filename)
1083 yield filename, pctx[filename].filenode()
1083 yield filename, pctx[filename].filenode()
1084 else:
1084 else:
1085 yield filename, None
1085 yield filename, None
1086 for filename_node in copies:
1086 for filename_node in copies:
1087 yield filename_node
1087 yield filename_node
1088 for file_, node in iterfiles():
1088 for file_, node in iterfiles():
1089 filelog = repo.file(file_)
1089 filelog = repo.file(file_)
1090 if not len(filelog):
1090 if not len(filelog):
1091 if node is None:
1091 if node is None:
1092 # A zero count may be a directory or deleted file, so
1092 # A zero count may be a directory or deleted file, so
1093 # try to find matching entries on the slow path.
1093 # try to find matching entries on the slow path.
1094 if follow:
1094 if follow:
1095 raise util.Abort(
1095 raise util.Abort(
1096 _('cannot follow nonexistent file: "%s"') % file_)
1096 _('cannot follow nonexistent file: "%s"') % file_)
1097 slowpath = True
1097 slowpath = True
1098 break
1098 break
1099 else:
1099 else:
1100 continue
1100 continue
1101
1101
1102 if node is None:
1102 if node is None:
1103 last = len(filelog) - 1
1103 last = len(filelog) - 1
1104 else:
1104 else:
1105 last = filelog.rev(node)
1105 last = filelog.rev(node)
1106
1106
1107
1107
1108 # keep track of all ancestors of the file
1108 # keep track of all ancestors of the file
1109 ancestors = set([filelog.linkrev(last)])
1109 ancestors = set([filelog.linkrev(last)])
1110
1110
1111 # iterate from latest to oldest revision
1111 # iterate from latest to oldest revision
1112 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1112 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1113 if not follow:
1113 if not follow:
1114 if rev > maxrev:
1114 if rev > maxrev:
1115 continue
1115 continue
1116 else:
1116 else:
1117 # Note that last might not be the first interesting
1117 # Note that last might not be the first interesting
1118 # rev to us:
1118 # rev to us:
1119 # if the file has been changed after maxrev, we'll
1119 # if the file has been changed after maxrev, we'll
1120 # have linkrev(last) > maxrev, and we still need
1120 # have linkrev(last) > maxrev, and we still need
1121 # to explore the file graph
1121 # to explore the file graph
1122 if rev not in ancestors:
1122 if rev not in ancestors:
1123 continue
1123 continue
1124 # XXX insert 1327 fix here
1124 # XXX insert 1327 fix here
1125 if flparentlinkrevs:
1125 if flparentlinkrevs:
1126 ancestors.update(flparentlinkrevs)
1126 ancestors.update(flparentlinkrevs)
1127
1127
1128 fncache.setdefault(rev, []).append(file_)
1128 fncache.setdefault(rev, []).append(file_)
1129 wanted.add(rev)
1129 wanted.add(rev)
1130 if copied:
1130 if copied:
1131 copies.append(copied)
1131 copies.append(copied)
1132
1132
1133 # We decided to fall back to the slowpath because at least one
1133 # We decided to fall back to the slowpath because at least one
1134 # of the paths was not a file. Check to see if at least one of them
1134 # of the paths was not a file. Check to see if at least one of them
1135 # existed in history, otherwise simply return
1135 # existed in history, otherwise simply return
1136 if slowpath:
1136 if slowpath:
1137 for path in match.files():
1137 for path in match.files():
1138 if path == '.' or path in repo.store:
1138 if path == '.' or path in repo.store:
1139 break
1139 break
1140 else:
1140 else:
1141 return []
1141 return []
1142
1142
1143 if slowpath:
1143 if slowpath:
1144 # We have to read the changelog to match filenames against
1144 # We have to read the changelog to match filenames against
1145 # changed files
1145 # changed files
1146
1146
1147 if follow:
1147 if follow:
1148 raise util.Abort(_('can only follow copies/renames for explicit '
1148 raise util.Abort(_('can only follow copies/renames for explicit '
1149 'filenames'))
1149 'filenames'))
1150
1150
1151 # The slow path checks files modified in every changeset.
1151 # The slow path checks files modified in every changeset.
1152 for i in sorted(revs):
1152 for i in sorted(revs):
1153 ctx = change(i)
1153 ctx = change(i)
1154 matches = filter(match, ctx.files())
1154 matches = filter(match, ctx.files())
1155 if matches:
1155 if matches:
1156 fncache[i] = matches
1156 fncache[i] = matches
1157 wanted.add(i)
1157 wanted.add(i)
1158
1158
1159 class followfilter(object):
1159 class followfilter(object):
1160 def __init__(self, onlyfirst=False):
1160 def __init__(self, onlyfirst=False):
1161 self.startrev = nullrev
1161 self.startrev = nullrev
1162 self.roots = set()
1162 self.roots = set()
1163 self.onlyfirst = onlyfirst
1163 self.onlyfirst = onlyfirst
1164
1164
1165 def match(self, rev):
1165 def match(self, rev):
1166 def realparents(rev):
1166 def realparents(rev):
1167 if self.onlyfirst:
1167 if self.onlyfirst:
1168 return repo.changelog.parentrevs(rev)[0:1]
1168 return repo.changelog.parentrevs(rev)[0:1]
1169 else:
1169 else:
1170 return filter(lambda x: x != nullrev,
1170 return filter(lambda x: x != nullrev,
1171 repo.changelog.parentrevs(rev))
1171 repo.changelog.parentrevs(rev))
1172
1172
1173 if self.startrev == nullrev:
1173 if self.startrev == nullrev:
1174 self.startrev = rev
1174 self.startrev = rev
1175 return True
1175 return True
1176
1176
1177 if rev > self.startrev:
1177 if rev > self.startrev:
1178 # forward: all descendants
1178 # forward: all descendants
1179 if not self.roots:
1179 if not self.roots:
1180 self.roots.add(self.startrev)
1180 self.roots.add(self.startrev)
1181 for parent in realparents(rev):
1181 for parent in realparents(rev):
1182 if parent in self.roots:
1182 if parent in self.roots:
1183 self.roots.add(rev)
1183 self.roots.add(rev)
1184 return True
1184 return True
1185 else:
1185 else:
1186 # backwards: all parents
1186 # backwards: all parents
1187 if not self.roots:
1187 if not self.roots:
1188 self.roots.update(realparents(self.startrev))
1188 self.roots.update(realparents(self.startrev))
1189 if rev in self.roots:
1189 if rev in self.roots:
1190 self.roots.remove(rev)
1190 self.roots.remove(rev)
1191 self.roots.update(realparents(rev))
1191 self.roots.update(realparents(rev))
1192 return True
1192 return True
1193
1193
1194 return False
1194 return False
1195
1195
1196 # it might be worthwhile to do this in the iterator if the rev range
1196 # it might be worthwhile to do this in the iterator if the rev range
1197 # is descending and the prune args are all within that range
1197 # is descending and the prune args are all within that range
1198 for rev in opts.get('prune', ()):
1198 for rev in opts.get('prune', ()):
1199 rev = repo[rev].rev()
1199 rev = repo[rev].rev()
1200 ff = followfilter()
1200 ff = followfilter()
1201 stop = min(revs[0], revs[-1])
1201 stop = min(revs[0], revs[-1])
1202 for x in xrange(rev, stop - 1, -1):
1202 for x in xrange(rev, stop - 1, -1):
1203 if ff.match(x):
1203 if ff.match(x):
1204 wanted.discard(x)
1204 wanted.discard(x)
1205
1205
1206 # Now that wanted is correctly initialized, we can iterate over the
1206 # Now that wanted is correctly initialized, we can iterate over the
1207 # revision range, yielding only revisions in wanted.
1207 # revision range, yielding only revisions in wanted.
1208 def iterate():
1208 def iterate():
1209 if follow and not match.files():
1209 if follow and not match.files():
1210 ff = followfilter(onlyfirst=opts.get('follow_first'))
1210 ff = followfilter(onlyfirst=opts.get('follow_first'))
1211 def want(rev):
1211 def want(rev):
1212 return ff.match(rev) and rev in wanted
1212 return ff.match(rev) and rev in wanted
1213 else:
1213 else:
1214 def want(rev):
1214 def want(rev):
1215 return rev in wanted
1215 return rev in wanted
1216
1216
1217 for i, window in increasingwindows(0, len(revs)):
1217 for i, window in increasingwindows(0, len(revs)):
1218 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1218 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1219 for rev in sorted(nrevs):
1219 for rev in sorted(nrevs):
1220 fns = fncache.get(rev)
1220 fns = fncache.get(rev)
1221 ctx = change(rev)
1221 ctx = change(rev)
1222 if not fns:
1222 if not fns:
1223 def fns_generator():
1223 def fns_generator():
1224 for f in ctx.files():
1224 for f in ctx.files():
1225 if match(f):
1225 if match(f):
1226 yield f
1226 yield f
1227 fns = fns_generator()
1227 fns = fns_generator()
1228 prepare(ctx, fns)
1228 prepare(ctx, fns)
1229 for rev in nrevs:
1229 for rev in nrevs:
1230 yield change(rev)
1230 yield change(rev)
1231 return iterate()
1231 return iterate()
1232
1232
1233 def _makegraphfilematcher(repo, pats, followfirst):
1233 def _makegraphfilematcher(repo, pats, followfirst):
1234 # When displaying a revision with --patch --follow FILE, we have
1234 # When displaying a revision with --patch --follow FILE, we have
1235 # to know which file of the revision must be diffed. With
1235 # to know which file of the revision must be diffed. With
1236 # --follow, we want the names of the ancestors of FILE in the
1236 # --follow, we want the names of the ancestors of FILE in the
1237 # revision, stored in "fcache". "fcache" is populated by
1237 # revision, stored in "fcache". "fcache" is populated by
1238 # reproducing the graph traversal already done by --follow revset
1238 # reproducing the graph traversal already done by --follow revset
1239 # and relating linkrevs to file names (which is not "correct" but
1239 # and relating linkrevs to file names (which is not "correct" but
1240 # good enough).
1240 # good enough).
1241 fcache = {}
1241 fcache = {}
1242 fcacheready = [False]
1242 fcacheready = [False]
1243 pctx = repo['.']
1243 pctx = repo['.']
1244 wctx = repo[None]
1244 wctx = repo[None]
1245
1245
1246 def populate():
1246 def populate():
1247 for fn in pats:
1247 for fn in pats:
1248 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1248 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1249 for c in i:
1249 for c in i:
1250 fcache.setdefault(c.linkrev(), set()).add(c.path())
1250 fcache.setdefault(c.linkrev(), set()).add(c.path())
1251
1251
1252 def filematcher(rev):
1252 def filematcher(rev):
1253 if not fcacheready[0]:
1253 if not fcacheready[0]:
1254 # Lazy initialization
1254 # Lazy initialization
1255 fcacheready[0] = True
1255 fcacheready[0] = True
1256 populate()
1256 populate()
1257 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1257 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1258
1258
1259 return filematcher
1259 return filematcher
1260
1260
1261 def _makegraphlogrevset(repo, pats, opts, revs):
1261 def _makegraphlogrevset(repo, pats, opts, revs):
1262 """Return (expr, filematcher) where expr is a revset string built
1262 """Return (expr, filematcher) where expr is a revset string built
1263 from log options and file patterns or None. If --stat or --patch
1263 from log options and file patterns or None. If --stat or --patch
1264 are not passed filematcher is None. Otherwise it is a callable
1264 are not passed filematcher is None. Otherwise it is a callable
1265 taking a revision number and returning a match objects filtering
1265 taking a revision number and returning a match objects filtering
1266 the files to be detailed when displaying the revision.
1266 the files to be detailed when displaying the revision.
1267 """
1267 """
1268 opt2revset = {
1268 opt2revset = {
1269 'no_merges': ('not merge()', None),
1269 'no_merges': ('not merge()', None),
1270 'only_merges': ('merge()', None),
1270 'only_merges': ('merge()', None),
1271 '_ancestors': ('ancestors(%(val)s)', None),
1271 '_ancestors': ('ancestors(%(val)s)', None),
1272 '_fancestors': ('_firstancestors(%(val)s)', None),
1272 '_fancestors': ('_firstancestors(%(val)s)', None),
1273 '_descendants': ('descendants(%(val)s)', None),
1273 '_descendants': ('descendants(%(val)s)', None),
1274 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1274 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1275 '_matchfiles': ('_matchfiles(%(val)s)', None),
1275 '_matchfiles': ('_matchfiles(%(val)s)', None),
1276 'date': ('date(%(val)r)', None),
1276 'date': ('date(%(val)r)', None),
1277 'branch': ('branch(%(val)r)', ' or '),
1277 'branch': ('branch(%(val)r)', ' or '),
1278 '_patslog': ('filelog(%(val)r)', ' or '),
1278 '_patslog': ('filelog(%(val)r)', ' or '),
1279 '_patsfollow': ('follow(%(val)r)', ' or '),
1279 '_patsfollow': ('follow(%(val)r)', ' or '),
1280 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1280 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1281 'keyword': ('keyword(%(val)r)', ' or '),
1281 'keyword': ('keyword(%(val)r)', ' or '),
1282 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1282 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1283 'user': ('user(%(val)r)', ' or '),
1283 'user': ('user(%(val)r)', ' or '),
1284 }
1284 }
1285
1285
1286 opts = dict(opts)
1286 opts = dict(opts)
1287 # follow or not follow?
1287 # follow or not follow?
1288 follow = opts.get('follow') or opts.get('follow_first')
1288 follow = opts.get('follow') or opts.get('follow_first')
1289 followfirst = opts.get('follow_first') and 1 or 0
1289 followfirst = opts.get('follow_first') and 1 or 0
1290 # --follow with FILE behaviour depends on revs...
1290 # --follow with FILE behaviour depends on revs...
1291 startrev = revs[0]
1291 startrev = revs[0]
1292 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1292 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1293
1293
1294 # branch and only_branch are really aliases and must be handled at
1294 # branch and only_branch are really aliases and must be handled at
1295 # the same time
1295 # the same time
1296 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1296 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1297 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1297 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1298 # pats/include/exclude are passed to match.match() directly in
1298 # pats/include/exclude are passed to match.match() directly in
1299 # _matchfiles() revset but walkchangerevs() builds its matcher with
1299 # _matchfiles() revset but walkchangerevs() builds its matcher with
1300 # scmutil.match(). The difference is input pats are globbed on
1300 # scmutil.match(). The difference is input pats are globbed on
1301 # platforms without shell expansion (windows).
1301 # platforms without shell expansion (windows).
1302 pctx = repo[None]
1302 pctx = repo[None]
1303 match, pats = scmutil.matchandpats(pctx, pats, opts)
1303 match, pats = scmutil.matchandpats(pctx, pats, opts)
1304 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1304 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1305 if not slowpath:
1305 if not slowpath:
1306 for f in match.files():
1306 for f in match.files():
1307 if follow and f not in pctx:
1307 if follow and f not in pctx:
1308 raise util.Abort(_('cannot follow file not in parent '
1308 raise util.Abort(_('cannot follow file not in parent '
1309 'revision: "%s"') % f)
1309 'revision: "%s"') % f)
1310 filelog = repo.file(f)
1310 filelog = repo.file(f)
1311 if not len(filelog):
1311 if not len(filelog):
1312 # A zero count may be a directory or deleted file, so
1312 # A zero count may be a directory or deleted file, so
1313 # try to find matching entries on the slow path.
1313 # try to find matching entries on the slow path.
1314 if follow:
1314 if follow:
1315 raise util.Abort(
1315 raise util.Abort(
1316 _('cannot follow nonexistent file: "%s"') % f)
1316 _('cannot follow nonexistent file: "%s"') % f)
1317 slowpath = True
1317 slowpath = True
1318
1318
1319 # We decided to fall back to the slowpath because at least one
1319 # We decided to fall back to the slowpath because at least one
1320 # of the paths was not a file. Check to see if at least one of them
1320 # of the paths was not a file. Check to see if at least one of them
1321 # existed in history - in that case, we'll continue down the
1321 # existed in history - in that case, we'll continue down the
1322 # slowpath; otherwise, we can turn off the slowpath
1322 # slowpath; otherwise, we can turn off the slowpath
1323 if slowpath:
1323 if slowpath:
1324 for path in match.files():
1324 for path in match.files():
1325 if path == '.' or path in repo.store:
1325 if path == '.' or path in repo.store:
1326 break
1326 break
1327 else:
1327 else:
1328 slowpath = False
1328 slowpath = False
1329
1329
1330 if slowpath:
1330 if slowpath:
1331 # See walkchangerevs() slow path.
1331 # See walkchangerevs() slow path.
1332 #
1332 #
1333 if follow:
1333 if follow:
1334 raise util.Abort(_('can only follow copies/renames for explicit '
1334 raise util.Abort(_('can only follow copies/renames for explicit '
1335 'filenames'))
1335 'filenames'))
1336 # pats/include/exclude cannot be represented as separate
1336 # pats/include/exclude cannot be represented as separate
1337 # revset expressions as their filtering logic applies at file
1337 # revset expressions as their filtering logic applies at file
1338 # level. For instance "-I a -X a" matches a revision touching
1338 # level. For instance "-I a -X a" matches a revision touching
1339 # "a" and "b" while "file(a) and not file(b)" does
1339 # "a" and "b" while "file(a) and not file(b)" does
1340 # not. Besides, filesets are evaluated against the working
1340 # not. Besides, filesets are evaluated against the working
1341 # directory.
1341 # directory.
1342 matchargs = ['r:', 'd:relpath']
1342 matchargs = ['r:', 'd:relpath']
1343 for p in pats:
1343 for p in pats:
1344 matchargs.append('p:' + p)
1344 matchargs.append('p:' + p)
1345 for p in opts.get('include', []):
1345 for p in opts.get('include', []):
1346 matchargs.append('i:' + p)
1346 matchargs.append('i:' + p)
1347 for p in opts.get('exclude', []):
1347 for p in opts.get('exclude', []):
1348 matchargs.append('x:' + p)
1348 matchargs.append('x:' + p)
1349 matchargs = ','.join(('%r' % p) for p in matchargs)
1349 matchargs = ','.join(('%r' % p) for p in matchargs)
1350 opts['_matchfiles'] = matchargs
1350 opts['_matchfiles'] = matchargs
1351 else:
1351 else:
1352 if follow:
1352 if follow:
1353 fpats = ('_patsfollow', '_patsfollowfirst')
1353 fpats = ('_patsfollow', '_patsfollowfirst')
1354 fnopats = (('_ancestors', '_fancestors'),
1354 fnopats = (('_ancestors', '_fancestors'),
1355 ('_descendants', '_fdescendants'))
1355 ('_descendants', '_fdescendants'))
1356 if pats:
1356 if pats:
1357 # follow() revset interprets its file argument as a
1357 # follow() revset interprets its file argument as a
1358 # manifest entry, so use match.files(), not pats.
1358 # manifest entry, so use match.files(), not pats.
1359 opts[fpats[followfirst]] = list(match.files())
1359 opts[fpats[followfirst]] = list(match.files())
1360 else:
1360 else:
1361 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1361 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1362 else:
1362 else:
1363 opts['_patslog'] = list(pats)
1363 opts['_patslog'] = list(pats)
1364
1364
1365 filematcher = None
1365 filematcher = None
1366 if opts.get('patch') or opts.get('stat'):
1366 if opts.get('patch') or opts.get('stat'):
1367 if follow:
1367 if follow:
1368 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1368 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1369 else:
1369 else:
1370 filematcher = lambda rev: match
1370 filematcher = lambda rev: match
1371
1371
1372 expr = []
1372 expr = []
1373 for op, val in opts.iteritems():
1373 for op, val in opts.iteritems():
1374 if not val:
1374 if not val:
1375 continue
1375 continue
1376 if op not in opt2revset:
1376 if op not in opt2revset:
1377 continue
1377 continue
1378 revop, andor = opt2revset[op]
1378 revop, andor = opt2revset[op]
1379 if '%(val)' not in revop:
1379 if '%(val)' not in revop:
1380 expr.append(revop)
1380 expr.append(revop)
1381 else:
1381 else:
1382 if not isinstance(val, list):
1382 if not isinstance(val, list):
1383 e = revop % {'val': val}
1383 e = revop % {'val': val}
1384 else:
1384 else:
1385 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1385 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1386 expr.append(e)
1386 expr.append(e)
1387
1387
1388 if expr:
1388 if expr:
1389 expr = '(' + ' and '.join(expr) + ')'
1389 expr = '(' + ' and '.join(expr) + ')'
1390 else:
1390 else:
1391 expr = None
1391 expr = None
1392 return expr, filematcher
1392 return expr, filematcher
1393
1393
1394 def getgraphlogrevs(repo, pats, opts):
1394 def getgraphlogrevs(repo, pats, opts):
1395 """Return (revs, expr, filematcher) where revs is an iterable of
1395 """Return (revs, expr, filematcher) where revs is an iterable of
1396 revision numbers, expr is a revset string built from log options
1396 revision numbers, expr is a revset string built from log options
1397 and file patterns or None, and used to filter 'revs'. If --stat or
1397 and file patterns or None, and used to filter 'revs'. If --stat or
1398 --patch are not passed filematcher is None. Otherwise it is a
1398 --patch are not passed filematcher is None. Otherwise it is a
1399 callable taking a revision number and returning a match objects
1399 callable taking a revision number and returning a match objects
1400 filtering the files to be detailed when displaying the revision.
1400 filtering the files to be detailed when displaying the revision.
1401 """
1401 """
1402 if not len(repo):
1402 if not len(repo):
1403 return [], None, None
1403 return [], None, None
1404 limit = loglimit(opts)
1404 limit = loglimit(opts)
1405 # Default --rev value depends on --follow but --follow behaviour
1405 # Default --rev value depends on --follow but --follow behaviour
1406 # depends on revisions resolved from --rev...
1406 # depends on revisions resolved from --rev...
1407 follow = opts.get('follow') or opts.get('follow_first')
1407 follow = opts.get('follow') or opts.get('follow_first')
1408 possiblyunsorted = False # whether revs might need sorting
1408 possiblyunsorted = False # whether revs might need sorting
1409 if not opts.get('hidden'):
1410 repo = repo.filtered('hidden')
1411 if opts.get('rev'):
1409 if opts.get('rev'):
1412 revs = scmutil.revrange(repo, opts['rev'])
1410 revs = scmutil.revrange(repo, opts['rev'])
1413 # Don't sort here because _makegraphlogrevset might depend on the
1411 # Don't sort here because _makegraphlogrevset might depend on the
1414 # order of revs
1412 # order of revs
1415 possiblyunsorted = True
1413 possiblyunsorted = True
1416 else:
1414 else:
1417 if follow and len(repo) > 0:
1415 if follow and len(repo) > 0:
1418 revs = repo.revs('reverse(:.)')
1416 revs = repo.revs('reverse(:.)')
1419 else:
1417 else:
1420 revs = list(repo.changelog)
1418 revs = list(repo.changelog)
1421 revs.reverse()
1419 revs.reverse()
1422 if not revs:
1420 if not revs:
1423 return [], None, None
1421 return [], None, None
1424 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1422 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1425 if possiblyunsorted:
1423 if possiblyunsorted:
1426 revs.sort(reverse=True)
1424 revs.sort(reverse=True)
1427 if expr:
1425 if expr:
1428 # Revset matchers often operate faster on revisions in changelog
1426 # Revset matchers often operate faster on revisions in changelog
1429 # order, because most filters deal with the changelog.
1427 # order, because most filters deal with the changelog.
1430 revs.reverse()
1428 revs.reverse()
1431 matcher = revset.match(repo.ui, expr)
1429 matcher = revset.match(repo.ui, expr)
1432 # Revset matches can reorder revisions. "A or B" typically returns
1430 # Revset matches can reorder revisions. "A or B" typically returns
1433 # returns the revision matching A then the revision matching B. Sort
1431 # returns the revision matching A then the revision matching B. Sort
1434 # again to fix that.
1432 # again to fix that.
1435 revs = matcher(repo, revs)
1433 revs = matcher(repo, revs)
1436 revs.sort(reverse=True)
1434 revs.sort(reverse=True)
1437 if limit is not None:
1435 if limit is not None:
1438 revs = revs[:limit]
1436 revs = revs[:limit]
1439
1437
1440 return revs, expr, filematcher
1438 return revs, expr, filematcher
1441
1439
1442 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1440 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1443 filematcher=None):
1441 filematcher=None):
1444 seen, state = [], graphmod.asciistate()
1442 seen, state = [], graphmod.asciistate()
1445 for rev, type, ctx, parents in dag:
1443 for rev, type, ctx, parents in dag:
1446 char = 'o'
1444 char = 'o'
1447 if ctx.node() in showparents:
1445 if ctx.node() in showparents:
1448 char = '@'
1446 char = '@'
1449 elif ctx.obsolete():
1447 elif ctx.obsolete():
1450 char = 'x'
1448 char = 'x'
1451 copies = None
1449 copies = None
1452 if getrenamed and ctx.rev():
1450 if getrenamed and ctx.rev():
1453 copies = []
1451 copies = []
1454 for fn in ctx.files():
1452 for fn in ctx.files():
1455 rename = getrenamed(fn, ctx.rev())
1453 rename = getrenamed(fn, ctx.rev())
1456 if rename:
1454 if rename:
1457 copies.append((fn, rename[0]))
1455 copies.append((fn, rename[0]))
1458 revmatchfn = None
1456 revmatchfn = None
1459 if filematcher is not None:
1457 if filematcher is not None:
1460 revmatchfn = filematcher(ctx.rev())
1458 revmatchfn = filematcher(ctx.rev())
1461 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1459 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1462 lines = displayer.hunk.pop(rev).split('\n')
1460 lines = displayer.hunk.pop(rev).split('\n')
1463 if not lines[-1]:
1461 if not lines[-1]:
1464 del lines[-1]
1462 del lines[-1]
1465 displayer.flush(rev)
1463 displayer.flush(rev)
1466 edges = edgefn(type, char, lines, seen, rev, parents)
1464 edges = edgefn(type, char, lines, seen, rev, parents)
1467 for type, char, lines, coldata in edges:
1465 for type, char, lines, coldata in edges:
1468 graphmod.ascii(ui, state, type, char, lines, coldata)
1466 graphmod.ascii(ui, state, type, char, lines, coldata)
1469 displayer.close()
1467 displayer.close()
1470
1468
1471 def graphlog(ui, repo, *pats, **opts):
1469 def graphlog(ui, repo, *pats, **opts):
1472 # Parameters are identical to log command ones
1470 # Parameters are identical to log command ones
1473 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1471 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1474 revdag = graphmod.dagwalker(repo, revs)
1472 revdag = graphmod.dagwalker(repo, revs)
1475
1473
1476 getrenamed = None
1474 getrenamed = None
1477 if opts.get('copies'):
1475 if opts.get('copies'):
1478 endrev = None
1476 endrev = None
1479 if opts.get('rev'):
1477 if opts.get('rev'):
1480 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1478 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1481 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1479 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1482 displayer = show_changeset(ui, repo, opts, buffered=True)
1480 displayer = show_changeset(ui, repo, opts, buffered=True)
1483 showparents = [ctx.node() for ctx in repo[None].parents()]
1481 showparents = [ctx.node() for ctx in repo[None].parents()]
1484 displaygraph(ui, revdag, displayer, showparents,
1482 displaygraph(ui, revdag, displayer, showparents,
1485 graphmod.asciiedges, getrenamed, filematcher)
1483 graphmod.asciiedges, getrenamed, filematcher)
1486
1484
1487 def checkunsupportedgraphflags(pats, opts):
1485 def checkunsupportedgraphflags(pats, opts):
1488 for op in ["newest_first"]:
1486 for op in ["newest_first"]:
1489 if op in opts and opts[op]:
1487 if op in opts and opts[op]:
1490 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1488 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1491 % op.replace("_", "-"))
1489 % op.replace("_", "-"))
1492
1490
1493 def graphrevs(repo, nodes, opts):
1491 def graphrevs(repo, nodes, opts):
1494 limit = loglimit(opts)
1492 limit = loglimit(opts)
1495 nodes.reverse()
1493 nodes.reverse()
1496 if limit is not None:
1494 if limit is not None:
1497 nodes = nodes[:limit]
1495 nodes = nodes[:limit]
1498 return graphmod.nodes(repo, nodes)
1496 return graphmod.nodes(repo, nodes)
1499
1497
1500 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1498 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1501 join = lambda f: os.path.join(prefix, f)
1499 join = lambda f: os.path.join(prefix, f)
1502 bad = []
1500 bad = []
1503 oldbad = match.bad
1501 oldbad = match.bad
1504 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1502 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1505 names = []
1503 names = []
1506 wctx = repo[None]
1504 wctx = repo[None]
1507 cca = None
1505 cca = None
1508 abort, warn = scmutil.checkportabilityalert(ui)
1506 abort, warn = scmutil.checkportabilityalert(ui)
1509 if abort or warn:
1507 if abort or warn:
1510 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1508 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1511 for f in repo.walk(match):
1509 for f in repo.walk(match):
1512 exact = match.exact(f)
1510 exact = match.exact(f)
1513 if exact or not explicitonly and f not in repo.dirstate:
1511 if exact or not explicitonly and f not in repo.dirstate:
1514 if cca:
1512 if cca:
1515 cca(f)
1513 cca(f)
1516 names.append(f)
1514 names.append(f)
1517 if ui.verbose or not exact:
1515 if ui.verbose or not exact:
1518 ui.status(_('adding %s\n') % match.rel(join(f)))
1516 ui.status(_('adding %s\n') % match.rel(join(f)))
1519
1517
1520 for subpath in wctx.substate:
1518 for subpath in wctx.substate:
1521 sub = wctx.sub(subpath)
1519 sub = wctx.sub(subpath)
1522 try:
1520 try:
1523 submatch = matchmod.narrowmatcher(subpath, match)
1521 submatch = matchmod.narrowmatcher(subpath, match)
1524 if listsubrepos:
1522 if listsubrepos:
1525 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1523 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1526 False))
1524 False))
1527 else:
1525 else:
1528 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1526 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1529 True))
1527 True))
1530 except error.LookupError:
1528 except error.LookupError:
1531 ui.status(_("skipping missing subrepository: %s\n")
1529 ui.status(_("skipping missing subrepository: %s\n")
1532 % join(subpath))
1530 % join(subpath))
1533
1531
1534 if not dryrun:
1532 if not dryrun:
1535 rejected = wctx.add(names, prefix)
1533 rejected = wctx.add(names, prefix)
1536 bad.extend(f for f in rejected if f in match.files())
1534 bad.extend(f for f in rejected if f in match.files())
1537 return bad
1535 return bad
1538
1536
1539 def forget(ui, repo, match, prefix, explicitonly):
1537 def forget(ui, repo, match, prefix, explicitonly):
1540 join = lambda f: os.path.join(prefix, f)
1538 join = lambda f: os.path.join(prefix, f)
1541 bad = []
1539 bad = []
1542 oldbad = match.bad
1540 oldbad = match.bad
1543 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1541 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1544 wctx = repo[None]
1542 wctx = repo[None]
1545 forgot = []
1543 forgot = []
1546 s = repo.status(match=match, clean=True)
1544 s = repo.status(match=match, clean=True)
1547 forget = sorted(s[0] + s[1] + s[3] + s[6])
1545 forget = sorted(s[0] + s[1] + s[3] + s[6])
1548 if explicitonly:
1546 if explicitonly:
1549 forget = [f for f in forget if match.exact(f)]
1547 forget = [f for f in forget if match.exact(f)]
1550
1548
1551 for subpath in wctx.substate:
1549 for subpath in wctx.substate:
1552 sub = wctx.sub(subpath)
1550 sub = wctx.sub(subpath)
1553 try:
1551 try:
1554 submatch = matchmod.narrowmatcher(subpath, match)
1552 submatch = matchmod.narrowmatcher(subpath, match)
1555 subbad, subforgot = sub.forget(ui, submatch, prefix)
1553 subbad, subforgot = sub.forget(ui, submatch, prefix)
1556 bad.extend([subpath + '/' + f for f in subbad])
1554 bad.extend([subpath + '/' + f for f in subbad])
1557 forgot.extend([subpath + '/' + f for f in subforgot])
1555 forgot.extend([subpath + '/' + f for f in subforgot])
1558 except error.LookupError:
1556 except error.LookupError:
1559 ui.status(_("skipping missing subrepository: %s\n")
1557 ui.status(_("skipping missing subrepository: %s\n")
1560 % join(subpath))
1558 % join(subpath))
1561
1559
1562 if not explicitonly:
1560 if not explicitonly:
1563 for f in match.files():
1561 for f in match.files():
1564 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1562 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1565 if f not in forgot:
1563 if f not in forgot:
1566 if os.path.exists(match.rel(join(f))):
1564 if os.path.exists(match.rel(join(f))):
1567 ui.warn(_('not removing %s: '
1565 ui.warn(_('not removing %s: '
1568 'file is already untracked\n')
1566 'file is already untracked\n')
1569 % match.rel(join(f)))
1567 % match.rel(join(f)))
1570 bad.append(f)
1568 bad.append(f)
1571
1569
1572 for f in forget:
1570 for f in forget:
1573 if ui.verbose or not match.exact(f):
1571 if ui.verbose or not match.exact(f):
1574 ui.status(_('removing %s\n') % match.rel(join(f)))
1572 ui.status(_('removing %s\n') % match.rel(join(f)))
1575
1573
1576 rejected = wctx.forget(forget, prefix)
1574 rejected = wctx.forget(forget, prefix)
1577 bad.extend(f for f in rejected if f in match.files())
1575 bad.extend(f for f in rejected if f in match.files())
1578 forgot.extend(forget)
1576 forgot.extend(forget)
1579 return bad, forgot
1577 return bad, forgot
1580
1578
1581 def duplicatecopies(repo, rev, p1):
1579 def duplicatecopies(repo, rev, p1):
1582 "Reproduce copies found in the source revision in the dirstate for grafts"
1580 "Reproduce copies found in the source revision in the dirstate for grafts"
1583 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1581 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1584 repo.dirstate.copy(src, dst)
1582 repo.dirstate.copy(src, dst)
1585
1583
1586 def commit(ui, repo, commitfunc, pats, opts):
1584 def commit(ui, repo, commitfunc, pats, opts):
1587 '''commit the specified files or all outstanding changes'''
1585 '''commit the specified files or all outstanding changes'''
1588 date = opts.get('date')
1586 date = opts.get('date')
1589 if date:
1587 if date:
1590 opts['date'] = util.parsedate(date)
1588 opts['date'] = util.parsedate(date)
1591 message = logmessage(ui, opts)
1589 message = logmessage(ui, opts)
1592
1590
1593 # extract addremove carefully -- this function can be called from a command
1591 # extract addremove carefully -- this function can be called from a command
1594 # that doesn't support addremove
1592 # that doesn't support addremove
1595 if opts.get('addremove'):
1593 if opts.get('addremove'):
1596 scmutil.addremove(repo, pats, opts)
1594 scmutil.addremove(repo, pats, opts)
1597
1595
1598 return commitfunc(ui, repo, message,
1596 return commitfunc(ui, repo, message,
1599 scmutil.match(repo[None], pats, opts), opts)
1597 scmutil.match(repo[None], pats, opts), opts)
1600
1598
1601 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1599 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1602 ui.note(_('amending changeset %s\n') % old)
1600 ui.note(_('amending changeset %s\n') % old)
1603 base = old.p1()
1601 base = old.p1()
1604
1602
1605 wlock = lock = newid = None
1603 wlock = lock = newid = None
1606 try:
1604 try:
1607 wlock = repo.wlock()
1605 wlock = repo.wlock()
1608 lock = repo.lock()
1606 lock = repo.lock()
1609 tr = repo.transaction('amend')
1607 tr = repo.transaction('amend')
1610 try:
1608 try:
1611 # See if we got a message from -m or -l, if not, open the editor
1609 # See if we got a message from -m or -l, if not, open the editor
1612 # with the message of the changeset to amend
1610 # with the message of the changeset to amend
1613 message = logmessage(ui, opts)
1611 message = logmessage(ui, opts)
1614 # ensure logfile does not conflict with later enforcement of the
1612 # ensure logfile does not conflict with later enforcement of the
1615 # message. potential logfile content has been processed by
1613 # message. potential logfile content has been processed by
1616 # `logmessage` anyway.
1614 # `logmessage` anyway.
1617 opts.pop('logfile')
1615 opts.pop('logfile')
1618 # First, do a regular commit to record all changes in the working
1616 # First, do a regular commit to record all changes in the working
1619 # directory (if there are any)
1617 # directory (if there are any)
1620 ui.callhooks = False
1618 ui.callhooks = False
1621 currentbookmark = repo._bookmarkcurrent
1619 currentbookmark = repo._bookmarkcurrent
1622 try:
1620 try:
1623 repo._bookmarkcurrent = None
1621 repo._bookmarkcurrent = None
1624 opts['message'] = 'temporary amend commit for %s' % old
1622 opts['message'] = 'temporary amend commit for %s' % old
1625 node = commit(ui, repo, commitfunc, pats, opts)
1623 node = commit(ui, repo, commitfunc, pats, opts)
1626 finally:
1624 finally:
1627 repo._bookmarkcurrent = currentbookmark
1625 repo._bookmarkcurrent = currentbookmark
1628 ui.callhooks = True
1626 ui.callhooks = True
1629 ctx = repo[node]
1627 ctx = repo[node]
1630
1628
1631 # Participating changesets:
1629 # Participating changesets:
1632 #
1630 #
1633 # node/ctx o - new (intermediate) commit that contains changes
1631 # node/ctx o - new (intermediate) commit that contains changes
1634 # | from working dir to go into amending commit
1632 # | from working dir to go into amending commit
1635 # | (or a workingctx if there were no changes)
1633 # | (or a workingctx if there were no changes)
1636 # |
1634 # |
1637 # old o - changeset to amend
1635 # old o - changeset to amend
1638 # |
1636 # |
1639 # base o - parent of amending changeset
1637 # base o - parent of amending changeset
1640
1638
1641 # Update extra dict from amended commit (e.g. to preserve graft
1639 # Update extra dict from amended commit (e.g. to preserve graft
1642 # source)
1640 # source)
1643 extra.update(old.extra())
1641 extra.update(old.extra())
1644
1642
1645 # Also update it from the intermediate commit or from the wctx
1643 # Also update it from the intermediate commit or from the wctx
1646 extra.update(ctx.extra())
1644 extra.update(ctx.extra())
1647
1645
1648 files = set(old.files())
1646 files = set(old.files())
1649
1647
1650 # Second, we use either the commit we just did, or if there were no
1648 # Second, we use either the commit we just did, or if there were no
1651 # changes the parent of the working directory as the version of the
1649 # changes the parent of the working directory as the version of the
1652 # files in the final amend commit
1650 # files in the final amend commit
1653 if node:
1651 if node:
1654 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1652 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1655
1653
1656 user = ctx.user()
1654 user = ctx.user()
1657 date = ctx.date()
1655 date = ctx.date()
1658 # Recompute copies (avoid recording a -> b -> a)
1656 # Recompute copies (avoid recording a -> b -> a)
1659 copied = copies.pathcopies(base, ctx)
1657 copied = copies.pathcopies(base, ctx)
1660
1658
1661 # Prune files which were reverted by the updates: if old
1659 # Prune files which were reverted by the updates: if old
1662 # introduced file X and our intermediate commit, node,
1660 # introduced file X and our intermediate commit, node,
1663 # renamed that file, then those two files are the same and
1661 # renamed that file, then those two files are the same and
1664 # we can discard X from our list of files. Likewise if X
1662 # we can discard X from our list of files. Likewise if X
1665 # was deleted, it's no longer relevant
1663 # was deleted, it's no longer relevant
1666 files.update(ctx.files())
1664 files.update(ctx.files())
1667
1665
1668 def samefile(f):
1666 def samefile(f):
1669 if f in ctx.manifest():
1667 if f in ctx.manifest():
1670 a = ctx.filectx(f)
1668 a = ctx.filectx(f)
1671 if f in base.manifest():
1669 if f in base.manifest():
1672 b = base.filectx(f)
1670 b = base.filectx(f)
1673 return (not a.cmp(b)
1671 return (not a.cmp(b)
1674 and a.flags() == b.flags())
1672 and a.flags() == b.flags())
1675 else:
1673 else:
1676 return False
1674 return False
1677 else:
1675 else:
1678 return f not in base.manifest()
1676 return f not in base.manifest()
1679 files = [f for f in files if not samefile(f)]
1677 files = [f for f in files if not samefile(f)]
1680
1678
1681 def filectxfn(repo, ctx_, path):
1679 def filectxfn(repo, ctx_, path):
1682 try:
1680 try:
1683 fctx = ctx[path]
1681 fctx = ctx[path]
1684 flags = fctx.flags()
1682 flags = fctx.flags()
1685 mctx = context.memfilectx(fctx.path(), fctx.data(),
1683 mctx = context.memfilectx(fctx.path(), fctx.data(),
1686 islink='l' in flags,
1684 islink='l' in flags,
1687 isexec='x' in flags,
1685 isexec='x' in flags,
1688 copied=copied.get(path))
1686 copied=copied.get(path))
1689 return mctx
1687 return mctx
1690 except KeyError:
1688 except KeyError:
1691 raise IOError
1689 raise IOError
1692 else:
1690 else:
1693 ui.note(_('copying changeset %s to %s\n') % (old, base))
1691 ui.note(_('copying changeset %s to %s\n') % (old, base))
1694
1692
1695 # Use version of files as in the old cset
1693 # Use version of files as in the old cset
1696 def filectxfn(repo, ctx_, path):
1694 def filectxfn(repo, ctx_, path):
1697 try:
1695 try:
1698 return old.filectx(path)
1696 return old.filectx(path)
1699 except KeyError:
1697 except KeyError:
1700 raise IOError
1698 raise IOError
1701
1699
1702 user = opts.get('user') or old.user()
1700 user = opts.get('user') or old.user()
1703 date = opts.get('date') or old.date()
1701 date = opts.get('date') or old.date()
1704 editmsg = False
1702 editmsg = False
1705 if not message:
1703 if not message:
1706 editmsg = True
1704 editmsg = True
1707 message = old.description()
1705 message = old.description()
1708
1706
1709 pureextra = extra.copy()
1707 pureextra = extra.copy()
1710 extra['amend_source'] = old.hex()
1708 extra['amend_source'] = old.hex()
1711
1709
1712 new = context.memctx(repo,
1710 new = context.memctx(repo,
1713 parents=[base.node(), nullid],
1711 parents=[base.node(), nullid],
1714 text=message,
1712 text=message,
1715 files=files,
1713 files=files,
1716 filectxfn=filectxfn,
1714 filectxfn=filectxfn,
1717 user=user,
1715 user=user,
1718 date=date,
1716 date=date,
1719 extra=extra)
1717 extra=extra)
1720 if editmsg:
1718 if editmsg:
1721 new._text = commitforceeditor(repo, new, [])
1719 new._text = commitforceeditor(repo, new, [])
1722
1720
1723 newdesc = changelog.stripdesc(new.description())
1721 newdesc = changelog.stripdesc(new.description())
1724 if ((not node)
1722 if ((not node)
1725 and newdesc == old.description()
1723 and newdesc == old.description()
1726 and user == old.user()
1724 and user == old.user()
1727 and date == old.date()
1725 and date == old.date()
1728 and pureextra == old.extra()):
1726 and pureextra == old.extra()):
1729 # nothing changed. continuing here would create a new node
1727 # nothing changed. continuing here would create a new node
1730 # anyway because of the amend_source noise.
1728 # anyway because of the amend_source noise.
1731 #
1729 #
1732 # This not what we expect from amend.
1730 # This not what we expect from amend.
1733 return old.node()
1731 return old.node()
1734
1732
1735 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1733 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1736 try:
1734 try:
1737 repo.ui.setconfig('phases', 'new-commit', old.phase())
1735 repo.ui.setconfig('phases', 'new-commit', old.phase())
1738 newid = repo.commitctx(new)
1736 newid = repo.commitctx(new)
1739 finally:
1737 finally:
1740 repo.ui.setconfig('phases', 'new-commit', ph)
1738 repo.ui.setconfig('phases', 'new-commit', ph)
1741 if newid != old.node():
1739 if newid != old.node():
1742 # Reroute the working copy parent to the new changeset
1740 # Reroute the working copy parent to the new changeset
1743 repo.setparents(newid, nullid)
1741 repo.setparents(newid, nullid)
1744
1742
1745 # Move bookmarks from old parent to amend commit
1743 # Move bookmarks from old parent to amend commit
1746 bms = repo.nodebookmarks(old.node())
1744 bms = repo.nodebookmarks(old.node())
1747 if bms:
1745 if bms:
1748 marks = repo._bookmarks
1746 marks = repo._bookmarks
1749 for bm in bms:
1747 for bm in bms:
1750 marks[bm] = newid
1748 marks[bm] = newid
1751 marks.write()
1749 marks.write()
1752 #commit the whole amend process
1750 #commit the whole amend process
1753 if obsolete._enabled and newid != old.node():
1751 if obsolete._enabled and newid != old.node():
1754 # mark the new changeset as successor of the rewritten one
1752 # mark the new changeset as successor of the rewritten one
1755 new = repo[newid]
1753 new = repo[newid]
1756 obs = [(old, (new,))]
1754 obs = [(old, (new,))]
1757 if node:
1755 if node:
1758 obs.append((ctx, ()))
1756 obs.append((ctx, ()))
1759
1757
1760 obsolete.createmarkers(repo, obs)
1758 obsolete.createmarkers(repo, obs)
1761 tr.close()
1759 tr.close()
1762 finally:
1760 finally:
1763 tr.release()
1761 tr.release()
1764 if (not obsolete._enabled) and newid != old.node():
1762 if (not obsolete._enabled) and newid != old.node():
1765 # Strip the intermediate commit (if there was one) and the amended
1763 # Strip the intermediate commit (if there was one) and the amended
1766 # commit
1764 # commit
1767 if node:
1765 if node:
1768 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1766 ui.note(_('stripping intermediate changeset %s\n') % ctx)
1769 ui.note(_('stripping amended changeset %s\n') % old)
1767 ui.note(_('stripping amended changeset %s\n') % old)
1770 repair.strip(ui, repo, old.node(), topic='amend-backup')
1768 repair.strip(ui, repo, old.node(), topic='amend-backup')
1771 finally:
1769 finally:
1772 if newid is None:
1770 if newid is None:
1773 repo.dirstate.invalidate()
1771 repo.dirstate.invalidate()
1774 lockmod.release(wlock, lock)
1772 lockmod.release(wlock, lock)
1775 return newid
1773 return newid
1776
1774
1777 def commiteditor(repo, ctx, subs):
1775 def commiteditor(repo, ctx, subs):
1778 if ctx.description():
1776 if ctx.description():
1779 return ctx.description()
1777 return ctx.description()
1780 return commitforceeditor(repo, ctx, subs)
1778 return commitforceeditor(repo, ctx, subs)
1781
1779
1782 def commitforceeditor(repo, ctx, subs):
1780 def commitforceeditor(repo, ctx, subs):
1783 edittext = []
1781 edittext = []
1784 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1782 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1785 if ctx.description():
1783 if ctx.description():
1786 edittext.append(ctx.description())
1784 edittext.append(ctx.description())
1787 edittext.append("")
1785 edittext.append("")
1788 edittext.append("") # Empty line between message and comments.
1786 edittext.append("") # Empty line between message and comments.
1789 edittext.append(_("HG: Enter commit message."
1787 edittext.append(_("HG: Enter commit message."
1790 " Lines beginning with 'HG:' are removed."))
1788 " Lines beginning with 'HG:' are removed."))
1791 edittext.append(_("HG: Leave message empty to abort commit."))
1789 edittext.append(_("HG: Leave message empty to abort commit."))
1792 edittext.append("HG: --")
1790 edittext.append("HG: --")
1793 edittext.append(_("HG: user: %s") % ctx.user())
1791 edittext.append(_("HG: user: %s") % ctx.user())
1794 if ctx.p2():
1792 if ctx.p2():
1795 edittext.append(_("HG: branch merge"))
1793 edittext.append(_("HG: branch merge"))
1796 if ctx.branch():
1794 if ctx.branch():
1797 edittext.append(_("HG: branch '%s'") % ctx.branch())
1795 edittext.append(_("HG: branch '%s'") % ctx.branch())
1798 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1796 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1799 edittext.extend([_("HG: added %s") % f for f in added])
1797 edittext.extend([_("HG: added %s") % f for f in added])
1800 edittext.extend([_("HG: changed %s") % f for f in modified])
1798 edittext.extend([_("HG: changed %s") % f for f in modified])
1801 edittext.extend([_("HG: removed %s") % f for f in removed])
1799 edittext.extend([_("HG: removed %s") % f for f in removed])
1802 if not added and not modified and not removed:
1800 if not added and not modified and not removed:
1803 edittext.append(_("HG: no files changed"))
1801 edittext.append(_("HG: no files changed"))
1804 edittext.append("")
1802 edittext.append("")
1805 # run editor in the repository root
1803 # run editor in the repository root
1806 olddir = os.getcwd()
1804 olddir = os.getcwd()
1807 os.chdir(repo.root)
1805 os.chdir(repo.root)
1808 text = repo.ui.edit("\n".join(edittext), ctx.user())
1806 text = repo.ui.edit("\n".join(edittext), ctx.user())
1809 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1807 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1810 os.chdir(olddir)
1808 os.chdir(olddir)
1811
1809
1812 if not text.strip():
1810 if not text.strip():
1813 raise util.Abort(_("empty commit message"))
1811 raise util.Abort(_("empty commit message"))
1814
1812
1815 return text
1813 return text
1816
1814
1817 def revert(ui, repo, ctx, parents, *pats, **opts):
1815 def revert(ui, repo, ctx, parents, *pats, **opts):
1818 parent, p2 = parents
1816 parent, p2 = parents
1819 node = ctx.node()
1817 node = ctx.node()
1820
1818
1821 mf = ctx.manifest()
1819 mf = ctx.manifest()
1822 if node == parent:
1820 if node == parent:
1823 pmf = mf
1821 pmf = mf
1824 else:
1822 else:
1825 pmf = None
1823 pmf = None
1826
1824
1827 # need all matching names in dirstate and manifest of target rev,
1825 # need all matching names in dirstate and manifest of target rev,
1828 # so have to walk both. do not print errors if files exist in one
1826 # so have to walk both. do not print errors if files exist in one
1829 # but not other.
1827 # but not other.
1830
1828
1831 names = {}
1829 names = {}
1832
1830
1833 wlock = repo.wlock()
1831 wlock = repo.wlock()
1834 try:
1832 try:
1835 # walk dirstate.
1833 # walk dirstate.
1836
1834
1837 m = scmutil.match(repo[None], pats, opts)
1835 m = scmutil.match(repo[None], pats, opts)
1838 m.bad = lambda x, y: False
1836 m.bad = lambda x, y: False
1839 for abs in repo.walk(m):
1837 for abs in repo.walk(m):
1840 names[abs] = m.rel(abs), m.exact(abs)
1838 names[abs] = m.rel(abs), m.exact(abs)
1841
1839
1842 # walk target manifest.
1840 # walk target manifest.
1843
1841
1844 def badfn(path, msg):
1842 def badfn(path, msg):
1845 if path in names:
1843 if path in names:
1846 return
1844 return
1847 if path in ctx.substate:
1845 if path in ctx.substate:
1848 return
1846 return
1849 path_ = path + '/'
1847 path_ = path + '/'
1850 for f in names:
1848 for f in names:
1851 if f.startswith(path_):
1849 if f.startswith(path_):
1852 return
1850 return
1853 ui.warn("%s: %s\n" % (m.rel(path), msg))
1851 ui.warn("%s: %s\n" % (m.rel(path), msg))
1854
1852
1855 m = scmutil.match(ctx, pats, opts)
1853 m = scmutil.match(ctx, pats, opts)
1856 m.bad = badfn
1854 m.bad = badfn
1857 for abs in ctx.walk(m):
1855 for abs in ctx.walk(m):
1858 if abs not in names:
1856 if abs not in names:
1859 names[abs] = m.rel(abs), m.exact(abs)
1857 names[abs] = m.rel(abs), m.exact(abs)
1860
1858
1861 # get the list of subrepos that must be reverted
1859 # get the list of subrepos that must be reverted
1862 targetsubs = [s for s in ctx.substate if m(s)]
1860 targetsubs = [s for s in ctx.substate if m(s)]
1863 m = scmutil.matchfiles(repo, names)
1861 m = scmutil.matchfiles(repo, names)
1864 changes = repo.status(match=m)[:4]
1862 changes = repo.status(match=m)[:4]
1865 modified, added, removed, deleted = map(set, changes)
1863 modified, added, removed, deleted = map(set, changes)
1866
1864
1867 # if f is a rename, also revert the source
1865 # if f is a rename, also revert the source
1868 cwd = repo.getcwd()
1866 cwd = repo.getcwd()
1869 for f in added:
1867 for f in added:
1870 src = repo.dirstate.copied(f)
1868 src = repo.dirstate.copied(f)
1871 if src and src not in names and repo.dirstate[src] == 'r':
1869 if src and src not in names and repo.dirstate[src] == 'r':
1872 removed.add(src)
1870 removed.add(src)
1873 names[src] = (repo.pathto(src, cwd), True)
1871 names[src] = (repo.pathto(src, cwd), True)
1874
1872
1875 def removeforget(abs):
1873 def removeforget(abs):
1876 if repo.dirstate[abs] == 'a':
1874 if repo.dirstate[abs] == 'a':
1877 return _('forgetting %s\n')
1875 return _('forgetting %s\n')
1878 return _('removing %s\n')
1876 return _('removing %s\n')
1879
1877
1880 revert = ([], _('reverting %s\n'))
1878 revert = ([], _('reverting %s\n'))
1881 add = ([], _('adding %s\n'))
1879 add = ([], _('adding %s\n'))
1882 remove = ([], removeforget)
1880 remove = ([], removeforget)
1883 undelete = ([], _('undeleting %s\n'))
1881 undelete = ([], _('undeleting %s\n'))
1884
1882
1885 disptable = (
1883 disptable = (
1886 # dispatch table:
1884 # dispatch table:
1887 # file state
1885 # file state
1888 # action if in target manifest
1886 # action if in target manifest
1889 # action if not in target manifest
1887 # action if not in target manifest
1890 # make backup if in target manifest
1888 # make backup if in target manifest
1891 # make backup if not in target manifest
1889 # make backup if not in target manifest
1892 (modified, revert, remove, True, True),
1890 (modified, revert, remove, True, True),
1893 (added, revert, remove, True, False),
1891 (added, revert, remove, True, False),
1894 (removed, undelete, None, False, False),
1892 (removed, undelete, None, False, False),
1895 (deleted, revert, remove, False, False),
1893 (deleted, revert, remove, False, False),
1896 )
1894 )
1897
1895
1898 for abs, (rel, exact) in sorted(names.items()):
1896 for abs, (rel, exact) in sorted(names.items()):
1899 mfentry = mf.get(abs)
1897 mfentry = mf.get(abs)
1900 target = repo.wjoin(abs)
1898 target = repo.wjoin(abs)
1901 def handle(xlist, dobackup):
1899 def handle(xlist, dobackup):
1902 xlist[0].append(abs)
1900 xlist[0].append(abs)
1903 if (dobackup and not opts.get('no_backup') and
1901 if (dobackup and not opts.get('no_backup') and
1904 os.path.lexists(target)):
1902 os.path.lexists(target)):
1905 bakname = "%s.orig" % rel
1903 bakname = "%s.orig" % rel
1906 ui.note(_('saving current version of %s as %s\n') %
1904 ui.note(_('saving current version of %s as %s\n') %
1907 (rel, bakname))
1905 (rel, bakname))
1908 if not opts.get('dry_run'):
1906 if not opts.get('dry_run'):
1909 util.rename(target, bakname)
1907 util.rename(target, bakname)
1910 if ui.verbose or not exact:
1908 if ui.verbose or not exact:
1911 msg = xlist[1]
1909 msg = xlist[1]
1912 if not isinstance(msg, basestring):
1910 if not isinstance(msg, basestring):
1913 msg = msg(abs)
1911 msg = msg(abs)
1914 ui.status(msg % rel)
1912 ui.status(msg % rel)
1915 for table, hitlist, misslist, backuphit, backupmiss in disptable:
1913 for table, hitlist, misslist, backuphit, backupmiss in disptable:
1916 if abs not in table:
1914 if abs not in table:
1917 continue
1915 continue
1918 # file has changed in dirstate
1916 # file has changed in dirstate
1919 if mfentry:
1917 if mfentry:
1920 handle(hitlist, backuphit)
1918 handle(hitlist, backuphit)
1921 elif misslist is not None:
1919 elif misslist is not None:
1922 handle(misslist, backupmiss)
1920 handle(misslist, backupmiss)
1923 break
1921 break
1924 else:
1922 else:
1925 if abs not in repo.dirstate:
1923 if abs not in repo.dirstate:
1926 if mfentry:
1924 if mfentry:
1927 handle(add, True)
1925 handle(add, True)
1928 elif exact:
1926 elif exact:
1929 ui.warn(_('file not managed: %s\n') % rel)
1927 ui.warn(_('file not managed: %s\n') % rel)
1930 continue
1928 continue
1931 # file has not changed in dirstate
1929 # file has not changed in dirstate
1932 if node == parent:
1930 if node == parent:
1933 if exact:
1931 if exact:
1934 ui.warn(_('no changes needed to %s\n') % rel)
1932 ui.warn(_('no changes needed to %s\n') % rel)
1935 continue
1933 continue
1936 if pmf is None:
1934 if pmf is None:
1937 # only need parent manifest in this unlikely case,
1935 # only need parent manifest in this unlikely case,
1938 # so do not read by default
1936 # so do not read by default
1939 pmf = repo[parent].manifest()
1937 pmf = repo[parent].manifest()
1940 if abs in pmf and mfentry:
1938 if abs in pmf and mfentry:
1941 # if version of file is same in parent and target
1939 # if version of file is same in parent and target
1942 # manifests, do nothing
1940 # manifests, do nothing
1943 if (pmf[abs] != mfentry or
1941 if (pmf[abs] != mfentry or
1944 pmf.flags(abs) != mf.flags(abs)):
1942 pmf.flags(abs) != mf.flags(abs)):
1945 handle(revert, False)
1943 handle(revert, False)
1946 else:
1944 else:
1947 handle(remove, False)
1945 handle(remove, False)
1948
1946
1949 if not opts.get('dry_run'):
1947 if not opts.get('dry_run'):
1950 def checkout(f):
1948 def checkout(f):
1951 fc = ctx[f]
1949 fc = ctx[f]
1952 repo.wwrite(f, fc.data(), fc.flags())
1950 repo.wwrite(f, fc.data(), fc.flags())
1953
1951
1954 audit_path = scmutil.pathauditor(repo.root)
1952 audit_path = scmutil.pathauditor(repo.root)
1955 for f in remove[0]:
1953 for f in remove[0]:
1956 if repo.dirstate[f] == 'a':
1954 if repo.dirstate[f] == 'a':
1957 repo.dirstate.drop(f)
1955 repo.dirstate.drop(f)
1958 continue
1956 continue
1959 audit_path(f)
1957 audit_path(f)
1960 try:
1958 try:
1961 util.unlinkpath(repo.wjoin(f))
1959 util.unlinkpath(repo.wjoin(f))
1962 except OSError:
1960 except OSError:
1963 pass
1961 pass
1964 repo.dirstate.remove(f)
1962 repo.dirstate.remove(f)
1965
1963
1966 normal = None
1964 normal = None
1967 if node == parent:
1965 if node == parent:
1968 # We're reverting to our parent. If possible, we'd like status
1966 # We're reverting to our parent. If possible, we'd like status
1969 # to report the file as clean. We have to use normallookup for
1967 # to report the file as clean. We have to use normallookup for
1970 # merges to avoid losing information about merged/dirty files.
1968 # merges to avoid losing information about merged/dirty files.
1971 if p2 != nullid:
1969 if p2 != nullid:
1972 normal = repo.dirstate.normallookup
1970 normal = repo.dirstate.normallookup
1973 else:
1971 else:
1974 normal = repo.dirstate.normal
1972 normal = repo.dirstate.normal
1975 for f in revert[0]:
1973 for f in revert[0]:
1976 checkout(f)
1974 checkout(f)
1977 if normal:
1975 if normal:
1978 normal(f)
1976 normal(f)
1979
1977
1980 for f in add[0]:
1978 for f in add[0]:
1981 checkout(f)
1979 checkout(f)
1982 repo.dirstate.add(f)
1980 repo.dirstate.add(f)
1983
1981
1984 normal = repo.dirstate.normallookup
1982 normal = repo.dirstate.normallookup
1985 if node == parent and p2 == nullid:
1983 if node == parent and p2 == nullid:
1986 normal = repo.dirstate.normal
1984 normal = repo.dirstate.normal
1987 for f in undelete[0]:
1985 for f in undelete[0]:
1988 checkout(f)
1986 checkout(f)
1989 normal(f)
1987 normal(f)
1990
1988
1991 if targetsubs:
1989 if targetsubs:
1992 # Revert the subrepos on the revert list
1990 # Revert the subrepos on the revert list
1993 for sub in targetsubs:
1991 for sub in targetsubs:
1994 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
1992 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
1995 finally:
1993 finally:
1996 wlock.release()
1994 wlock.release()
1997
1995
1998 def command(table):
1996 def command(table):
1999 '''returns a function object bound to table which can be used as
1997 '''returns a function object bound to table which can be used as
2000 a decorator for populating table as a command table'''
1998 a decorator for populating table as a command table'''
2001
1999
2002 def cmd(name, options=(), synopsis=None):
2000 def cmd(name, options=(), synopsis=None):
2003 def decorator(func):
2001 def decorator(func):
2004 if synopsis:
2002 if synopsis:
2005 table[name] = func, list(options), synopsis
2003 table[name] = func, list(options), synopsis
2006 else:
2004 else:
2007 table[name] = func, list(options)
2005 table[name] = func, list(options)
2008 return func
2006 return func
2009 return decorator
2007 return decorator
2010
2008
2011 return cmd
2009 return cmd
@@ -1,6041 +1,6039 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, encoding, templatekw, discovery
13 import patch, help, 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, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
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 ('', 'hidden', False, _('consider hidden changesets')),
52 ]
53 ]
53
54
54 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
56
57
57 remoteopts = [
58 remoteopts = [
58 ('e', 'ssh', '',
59 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
63 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
65 ]
65
66
66 walkopts = [
67 walkopts = [
67 ('I', 'include', [],
68 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
70 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
72 ]
72
73
73 commitopts = [
74 commitopts = [
74 ('m', 'message', '',
75 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
77 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
78 ]
79 ]
79
80
80 commitopts2 = [
81 commitopts2 = [
81 ('d', 'date', '',
82 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
84 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
85 ]
86 ]
86
87
87 templateopts = [
88 templateopts = [
88 ('', 'style', '',
89 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
91 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
92 ]
93 ]
93
94
94 logopts = [
95 logopts = [
95 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
98 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
103 ] + templateopts
103
104
104 diffopts = [
105 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
109 ]
109
110
110 diffwsopts = [
111 diffwsopts = [
111 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
117 ]
118 ]
118
119
119 diffopts2 = [
120 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
123 ] + diffwsopts + [
123 ('U', 'unified', '',
124 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
127 ]
127
128
128 mergetoolopts = [
129 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
130 ]
131 ]
131
132
132 similarityopts = [
133 similarityopts = [
133 ('s', 'similarity', '',
134 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
136 ]
136
137
137 subrepoopts = [
138 subrepoopts = [
138 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
140 ]
141 ]
141
142
142 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
143
144
144 @command('^add',
145 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
149 """add the specified files on the next commit
149
150
150 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
151 repository.
152 repository.
152
153
153 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
155
156
156 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
157
158
158 .. container:: verbose
159 .. container:: verbose
159
160
160 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
162 automatically by :hg:`add`::
162
163
163 $ ls
164 $ ls
164 foo.c
165 foo.c
165 $ hg status
166 $ hg status
166 ? foo.c
167 ? foo.c
167 $ hg add
168 $ hg add
168 adding foo.c
169 adding foo.c
169 $ hg status
170 $ hg status
170 A foo.c
171 A foo.c
171
172
172 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
173 """
174 """
174
175
175 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
179 return rejected and 1 or 0
179
180
180 @command('addremove',
181 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
185 """add all new files, delete all missing files
185
186
186 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
187 repository.
188 repository.
188
189
189 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
192 commit.
192
193
193 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
202 identical files are detected.
202
203
203 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
204 """
205 """
205 try:
206 try:
206 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
207 except ValueError:
208 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
213
213 @command('^annotate|blame',
214 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
216 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
229 """show changeset information by line for each file
229
230
230 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
231 each line
232 each line
232
233
233 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
234 by whom.
235 by whom.
235
236
236 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
239 nor desirable.
240 nor desirable.
240
241
241 Returns 0 on success.
242 Returns 0 on success.
242 """
243 """
243 if opts.get('follow'):
244 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
247 opts['file'] = True
247
248
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
251
251 if not pats:
252 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
253
254
254 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
255
256
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
260 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
262 ]
263 ]
263
264
264 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
267 opts['number'] = True
267
268
268 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
272
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
275
275 def bad(x, y):
276 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
277
278
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
281 m.bad = bad
281 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
284 fctx = ctx[abs]
285 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
288 continue
288
289
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
291 diffopts=diffopts)
291 pieces = []
292 pieces = []
292
293
293 for f, sep in funcmap:
294 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
295 if l:
296 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
300 for x, w in sized])
300
301
301 if pieces:
302 if pieces:
302 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
304
305
305 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
307 ui.write('\n')
307
308
308 @command('archive',
309 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
312 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
318
319
319 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
321
322
322 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
324 extension (or override using -t/--type).
324
325
325 .. container:: verbose
326 .. container:: verbose
326
327
327 Examples:
328 Examples:
328
329
329 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
330
331
331 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
332
333
333 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
334
335
335 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
336
337
337 Valid types are:
338 Valid types are:
338
339
339 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
345
346
346 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
348
349
349 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
352 removed.
353 removed.
353
354
354 Returns 0 on success.
355 Returns 0 on success.
355 '''
356 '''
356
357
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
359 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
361 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
364
365
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
367
368
368 if dest == '-':
369 if dest == '-':
369 if kind == 'files':
370 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
373 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
374
375
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379
380
380 @command('backout',
381 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
383 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
389
390
390 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
392 current working directory.
392
393
393 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
396
397
397 .. note::
398 .. note::
398 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
399 incorrect merge.
400 incorrect merge.
400
401
401 .. container:: verbose
402 .. container:: verbose
402
403
403 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
407
408
408 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
411 merged separately.
412 merged separately.
412
413
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414
415
415 Returns 0 on success.
416 Returns 0 on success.
416 '''
417 '''
417 if rev and node:
418 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
419
420
420 if not rev:
421 if not rev:
421 rev = node
422 rev = node
422
423
423 if not rev:
424 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
425
426
426 date = opts.get('date')
427 date = opts.get('date')
427 if date:
428 if date:
428 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
429
430
430 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
432
433
433 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
435 if a != node:
436 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
437
438
438 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
440 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
442 if p2 != nullid:
442 if not opts.get('parent'):
443 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
446 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
448 (short(p), short(node)))
448 parent = p
449 parent = p
449 else:
450 else:
450 if opts.get('parent'):
451 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
453 parent = p1
453
454
454 # the backout should appear on the same branch
455 # the backout should appear on the same branch
455 wlock = repo.wlock()
456 wlock = repo.wlock()
456 try:
457 try:
457 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
459 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
460 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
461 revert_opts = opts.copy()
461 revert_opts['date'] = None
462 revert_opts['date'] = None
462 revert_opts['all'] = True
463 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
464 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
465 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
466 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
467 if not opts.get('merge') and op1 != node:
467 try:
468 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
470 return hg.update(repo, op1)
470 finally:
471 finally:
471 ui.setconfig('ui', 'forcemerge', '')
472 ui.setconfig('ui', 'forcemerge', '')
472
473
473 commit_opts = opts.copy()
474 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
475 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
477 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
479 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
480 commit(ui, repo, **commit_opts)
480 def nice(node):
481 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
484 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
485 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
486 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
487 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
488 % nice(repo.changelog.tip()))
488 try:
489 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
492 finally:
492 ui.setconfig('ui', 'forcemerge', '')
493 ui.setconfig('ui', 'forcemerge', '')
493 finally:
494 finally:
494 wlock.release()
495 wlock.release()
495 return 0
496 return 0
496
497
497 @command('bisect',
498 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
499 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
505 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
509 noupdate=None):
509 """subdivision search of changesets
510 """subdivision search of changesets
510
511
511 This command helps to find changesets which introduce problems. To
512 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
513 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
514 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
515 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
516 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
517 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
518 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
519 or announce that it has found the bad revision.
519
520
520 As a shortcut, you can also use the revision argument to mark a
521 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
522 revision as good or bad without checking it out first.
522
523
523 If you supply a command, it will be used for automatic bisection.
524 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
525 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
526 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
527 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
528 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
529 bisection, and any other non-zero exit status means the revision
529 is bad.
530 is bad.
530
531
531 .. container:: verbose
532 .. container:: verbose
532
533
533 Some examples:
534 Some examples:
534
535
535 - start a bisection with known bad revision 12, and good revision 34::
536 - start a bisection with known bad revision 12, and good revision 34::
536
537
537 hg bisect --bad 34
538 hg bisect --bad 34
538 hg bisect --good 12
539 hg bisect --good 12
539
540
540 - advance the current bisection by marking current revision as good or
541 - advance the current bisection by marking current revision as good or
541 bad::
542 bad::
542
543
543 hg bisect --good
544 hg bisect --good
544 hg bisect --bad
545 hg bisect --bad
545
546
546 - mark the current revision, or a known revision, to be skipped (e.g. if
547 - mark the current revision, or a known revision, to be skipped (e.g. if
547 that revision is not usable because of another issue)::
548 that revision is not usable because of another issue)::
548
549
549 hg bisect --skip
550 hg bisect --skip
550 hg bisect --skip 23
551 hg bisect --skip 23
551
552
552 - skip all revisions that do not touch directories ``foo`` or ``bar``
553 - skip all revisions that do not touch directories ``foo`` or ``bar``
553
554
554 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
555 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
555
556
556 - forget the current bisection::
557 - forget the current bisection::
557
558
558 hg bisect --reset
559 hg bisect --reset
559
560
560 - use 'make && make tests' to automatically find the first broken
561 - use 'make && make tests' to automatically find the first broken
561 revision::
562 revision::
562
563
563 hg bisect --reset
564 hg bisect --reset
564 hg bisect --bad 34
565 hg bisect --bad 34
565 hg bisect --good 12
566 hg bisect --good 12
566 hg bisect --command 'make && make tests'
567 hg bisect --command 'make && make tests'
567
568
568 - see all changesets whose states are already known in the current
569 - see all changesets whose states are already known in the current
569 bisection::
570 bisection::
570
571
571 hg log -r "bisect(pruned)"
572 hg log -r "bisect(pruned)"
572
573
573 - see the changeset currently being bisected (especially useful
574 - see the changeset currently being bisected (especially useful
574 if running with -U/--noupdate)::
575 if running with -U/--noupdate)::
575
576
576 hg log -r "bisect(current)"
577 hg log -r "bisect(current)"
577
578
578 - see all changesets that took part in the current bisection::
579 - see all changesets that took part in the current bisection::
579
580
580 hg log -r "bisect(range)"
581 hg log -r "bisect(range)"
581
582
582 - with the graphlog extension, you can even get a nice graph::
583 - with the graphlog extension, you can even get a nice graph::
583
584
584 hg log --graph -r "bisect(range)"
585 hg log --graph -r "bisect(range)"
585
586
586 See :hg:`help revsets` for more about the `bisect()` keyword.
587 See :hg:`help revsets` for more about the `bisect()` keyword.
587
588
588 Returns 0 on success.
589 Returns 0 on success.
589 """
590 """
590 def extendbisectrange(nodes, good):
591 def extendbisectrange(nodes, good):
591 # bisect is incomplete when it ends on a merge node and
592 # bisect is incomplete when it ends on a merge node and
592 # one of the parent was not checked.
593 # one of the parent was not checked.
593 parents = repo[nodes[0]].parents()
594 parents = repo[nodes[0]].parents()
594 if len(parents) > 1:
595 if len(parents) > 1:
595 side = good and state['bad'] or state['good']
596 side = good and state['bad'] or state['good']
596 num = len(set(i.node() for i in parents) & set(side))
597 num = len(set(i.node() for i in parents) & set(side))
597 if num == 1:
598 if num == 1:
598 return parents[0].ancestor(parents[1])
599 return parents[0].ancestor(parents[1])
599 return None
600 return None
600
601
601 def print_result(nodes, good):
602 def print_result(nodes, good):
602 displayer = cmdutil.show_changeset(ui, repo, {})
603 displayer = cmdutil.show_changeset(ui, repo, {})
603 if len(nodes) == 1:
604 if len(nodes) == 1:
604 # narrowed it down to a single revision
605 # narrowed it down to a single revision
605 if good:
606 if good:
606 ui.write(_("The first good revision is:\n"))
607 ui.write(_("The first good revision is:\n"))
607 else:
608 else:
608 ui.write(_("The first bad revision is:\n"))
609 ui.write(_("The first bad revision is:\n"))
609 displayer.show(repo[nodes[0]])
610 displayer.show(repo[nodes[0]])
610 extendnode = extendbisectrange(nodes, good)
611 extendnode = extendbisectrange(nodes, good)
611 if extendnode is not None:
612 if extendnode is not None:
612 ui.write(_('Not all ancestors of this changeset have been'
613 ui.write(_('Not all ancestors of this changeset have been'
613 ' checked.\nUse bisect --extend to continue the '
614 ' checked.\nUse bisect --extend to continue the '
614 'bisection from\nthe common ancestor, %s.\n')
615 'bisection from\nthe common ancestor, %s.\n')
615 % extendnode)
616 % extendnode)
616 else:
617 else:
617 # multiple possible revisions
618 # multiple possible revisions
618 if good:
619 if good:
619 ui.write(_("Due to skipped revisions, the first "
620 ui.write(_("Due to skipped revisions, the first "
620 "good revision could be any of:\n"))
621 "good revision could be any of:\n"))
621 else:
622 else:
622 ui.write(_("Due to skipped revisions, the first "
623 ui.write(_("Due to skipped revisions, the first "
623 "bad revision could be any of:\n"))
624 "bad revision could be any of:\n"))
624 for n in nodes:
625 for n in nodes:
625 displayer.show(repo[n])
626 displayer.show(repo[n])
626 displayer.close()
627 displayer.close()
627
628
628 def check_state(state, interactive=True):
629 def check_state(state, interactive=True):
629 if not state['good'] or not state['bad']:
630 if not state['good'] or not state['bad']:
630 if (good or bad or skip or reset) and interactive:
631 if (good or bad or skip or reset) and interactive:
631 return
632 return
632 if not state['good']:
633 if not state['good']:
633 raise util.Abort(_('cannot bisect (no known good revisions)'))
634 raise util.Abort(_('cannot bisect (no known good revisions)'))
634 else:
635 else:
635 raise util.Abort(_('cannot bisect (no known bad revisions)'))
636 raise util.Abort(_('cannot bisect (no known bad revisions)'))
636 return True
637 return True
637
638
638 # backward compatibility
639 # backward compatibility
639 if rev in "good bad reset init".split():
640 if rev in "good bad reset init".split():
640 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
641 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
641 cmd, rev, extra = rev, extra, None
642 cmd, rev, extra = rev, extra, None
642 if cmd == "good":
643 if cmd == "good":
643 good = True
644 good = True
644 elif cmd == "bad":
645 elif cmd == "bad":
645 bad = True
646 bad = True
646 else:
647 else:
647 reset = True
648 reset = True
648 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
649 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
649 raise util.Abort(_('incompatible arguments'))
650 raise util.Abort(_('incompatible arguments'))
650
651
651 if reset:
652 if reset:
652 p = repo.join("bisect.state")
653 p = repo.join("bisect.state")
653 if os.path.exists(p):
654 if os.path.exists(p):
654 os.unlink(p)
655 os.unlink(p)
655 return
656 return
656
657
657 state = hbisect.load_state(repo)
658 state = hbisect.load_state(repo)
658
659
659 if command:
660 if command:
660 changesets = 1
661 changesets = 1
661 try:
662 try:
662 node = state['current'][0]
663 node = state['current'][0]
663 except LookupError:
664 except LookupError:
664 if noupdate:
665 if noupdate:
665 raise util.Abort(_('current bisect revision is unknown - '
666 raise util.Abort(_('current bisect revision is unknown - '
666 'start a new bisect to fix'))
667 'start a new bisect to fix'))
667 node, p2 = repo.dirstate.parents()
668 node, p2 = repo.dirstate.parents()
668 if p2 != nullid:
669 if p2 != nullid:
669 raise util.Abort(_('current bisect revision is a merge'))
670 raise util.Abort(_('current bisect revision is a merge'))
670 try:
671 try:
671 while changesets:
672 while changesets:
672 # update state
673 # update state
673 state['current'] = [node]
674 state['current'] = [node]
674 hbisect.save_state(repo, state)
675 hbisect.save_state(repo, state)
675 status = util.system(command,
676 status = util.system(command,
676 environ={'HG_NODE': hex(node)},
677 environ={'HG_NODE': hex(node)},
677 out=ui.fout)
678 out=ui.fout)
678 if status == 125:
679 if status == 125:
679 transition = "skip"
680 transition = "skip"
680 elif status == 0:
681 elif status == 0:
681 transition = "good"
682 transition = "good"
682 # status < 0 means process was killed
683 # status < 0 means process was killed
683 elif status == 127:
684 elif status == 127:
684 raise util.Abort(_("failed to execute %s") % command)
685 raise util.Abort(_("failed to execute %s") % command)
685 elif status < 0:
686 elif status < 0:
686 raise util.Abort(_("%s killed") % command)
687 raise util.Abort(_("%s killed") % command)
687 else:
688 else:
688 transition = "bad"
689 transition = "bad"
689 ctx = scmutil.revsingle(repo, rev, node)
690 ctx = scmutil.revsingle(repo, rev, node)
690 rev = None # clear for future iterations
691 rev = None # clear for future iterations
691 state[transition].append(ctx.node())
692 state[transition].append(ctx.node())
692 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
693 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
693 check_state(state, interactive=False)
694 check_state(state, interactive=False)
694 # bisect
695 # bisect
695 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
696 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
696 # update to next check
697 # update to next check
697 node = nodes[0]
698 node = nodes[0]
698 if not noupdate:
699 if not noupdate:
699 cmdutil.bailifchanged(repo)
700 cmdutil.bailifchanged(repo)
700 hg.clean(repo, node, show_stats=False)
701 hg.clean(repo, node, show_stats=False)
701 finally:
702 finally:
702 state['current'] = [node]
703 state['current'] = [node]
703 hbisect.save_state(repo, state)
704 hbisect.save_state(repo, state)
704 print_result(nodes, good)
705 print_result(nodes, good)
705 return
706 return
706
707
707 # update state
708 # update state
708
709
709 if rev:
710 if rev:
710 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
711 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
711 else:
712 else:
712 nodes = [repo.lookup('.')]
713 nodes = [repo.lookup('.')]
713
714
714 if good or bad or skip:
715 if good or bad or skip:
715 if good:
716 if good:
716 state['good'] += nodes
717 state['good'] += nodes
717 elif bad:
718 elif bad:
718 state['bad'] += nodes
719 state['bad'] += nodes
719 elif skip:
720 elif skip:
720 state['skip'] += nodes
721 state['skip'] += nodes
721 hbisect.save_state(repo, state)
722 hbisect.save_state(repo, state)
722
723
723 if not check_state(state):
724 if not check_state(state):
724 return
725 return
725
726
726 # actually bisect
727 # actually bisect
727 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
728 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
728 if extend:
729 if extend:
729 if not changesets:
730 if not changesets:
730 extendnode = extendbisectrange(nodes, good)
731 extendnode = extendbisectrange(nodes, good)
731 if extendnode is not None:
732 if extendnode is not None:
732 ui.write(_("Extending search to changeset %d:%s\n"
733 ui.write(_("Extending search to changeset %d:%s\n"
733 % (extendnode.rev(), extendnode)))
734 % (extendnode.rev(), extendnode)))
734 state['current'] = [extendnode.node()]
735 state['current'] = [extendnode.node()]
735 hbisect.save_state(repo, state)
736 hbisect.save_state(repo, state)
736 if noupdate:
737 if noupdate:
737 return
738 return
738 cmdutil.bailifchanged(repo)
739 cmdutil.bailifchanged(repo)
739 return hg.clean(repo, extendnode.node())
740 return hg.clean(repo, extendnode.node())
740 raise util.Abort(_("nothing to extend"))
741 raise util.Abort(_("nothing to extend"))
741
742
742 if changesets == 0:
743 if changesets == 0:
743 print_result(nodes, good)
744 print_result(nodes, good)
744 else:
745 else:
745 assert len(nodes) == 1 # only a single node can be tested next
746 assert len(nodes) == 1 # only a single node can be tested next
746 node = nodes[0]
747 node = nodes[0]
747 # compute the approximate number of remaining tests
748 # compute the approximate number of remaining tests
748 tests, size = 0, 2
749 tests, size = 0, 2
749 while size <= changesets:
750 while size <= changesets:
750 tests, size = tests + 1, size * 2
751 tests, size = tests + 1, size * 2
751 rev = repo.changelog.rev(node)
752 rev = repo.changelog.rev(node)
752 ui.write(_("Testing changeset %d:%s "
753 ui.write(_("Testing changeset %d:%s "
753 "(%d changesets remaining, ~%d tests)\n")
754 "(%d changesets remaining, ~%d tests)\n")
754 % (rev, short(node), changesets, tests))
755 % (rev, short(node), changesets, tests))
755 state['current'] = [node]
756 state['current'] = [node]
756 hbisect.save_state(repo, state)
757 hbisect.save_state(repo, state)
757 if not noupdate:
758 if not noupdate:
758 cmdutil.bailifchanged(repo)
759 cmdutil.bailifchanged(repo)
759 return hg.clean(repo, node)
760 return hg.clean(repo, node)
760
761
761 @command('bookmarks|bookmark',
762 @command('bookmarks|bookmark',
762 [('f', 'force', False, _('force')),
763 [('f', 'force', False, _('force')),
763 ('r', 'rev', '', _('revision'), _('REV')),
764 ('r', 'rev', '', _('revision'), _('REV')),
764 ('d', 'delete', False, _('delete a given bookmark')),
765 ('d', 'delete', False, _('delete a given bookmark')),
765 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
766 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
766 ('i', 'inactive', False, _('mark a bookmark inactive'))],
767 ('i', 'inactive', False, _('mark a bookmark inactive'))],
767 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
768 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
768 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
769 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
769 rename=None, inactive=False):
770 rename=None, inactive=False):
770 '''track a line of development with movable markers
771 '''track a line of development with movable markers
771
772
772 Bookmarks are pointers to certain commits that move when committing.
773 Bookmarks are pointers to certain commits that move when committing.
773 Bookmarks are local. They can be renamed, copied and deleted. It is
774 Bookmarks are local. They can be renamed, copied and deleted. It is
774 possible to use :hg:`merge NAME` to merge from a given bookmark, and
775 possible to use :hg:`merge NAME` to merge from a given bookmark, and
775 :hg:`update NAME` to update to a given bookmark.
776 :hg:`update NAME` to update to a given bookmark.
776
777
777 You can use :hg:`bookmark NAME` to set a bookmark on the working
778 You can use :hg:`bookmark NAME` to set a bookmark on the working
778 directory's parent revision with the given name. If you specify
779 directory's parent revision with the given name. If you specify
779 a revision using -r REV (where REV may be an existing bookmark),
780 a revision using -r REV (where REV may be an existing bookmark),
780 the bookmark is assigned to that revision.
781 the bookmark is assigned to that revision.
781
782
782 Bookmarks can be pushed and pulled between repositories (see :hg:`help
783 Bookmarks can be pushed and pulled between repositories (see :hg:`help
783 push` and :hg:`help pull`). This requires both the local and remote
784 push` and :hg:`help pull`). This requires both the local and remote
784 repositories to support bookmarks. For versions prior to 1.8, this means
785 repositories to support bookmarks. For versions prior to 1.8, this means
785 the bookmarks extension must be enabled.
786 the bookmarks extension must be enabled.
786
787
787 With -i/--inactive, the new bookmark will not be made the active
788 With -i/--inactive, the new bookmark will not be made the active
788 bookmark. If -r/--rev is given, the new bookmark will not be made
789 bookmark. If -r/--rev is given, the new bookmark will not be made
789 active even if -i/--inactive is not given. If no NAME is given, the
790 active even if -i/--inactive is not given. If no NAME is given, the
790 current active bookmark will be marked inactive.
791 current active bookmark will be marked inactive.
791 '''
792 '''
792 hexfn = ui.debugflag and hex or short
793 hexfn = ui.debugflag and hex or short
793 marks = repo._bookmarks
794 marks = repo._bookmarks
794 cur = repo.changectx('.').node()
795 cur = repo.changectx('.').node()
795
796
796 def checkformat(mark):
797 def checkformat(mark):
797 mark = mark.strip()
798 mark = mark.strip()
798 if not mark:
799 if not mark:
799 raise util.Abort(_("bookmark names cannot consist entirely of "
800 raise util.Abort(_("bookmark names cannot consist entirely of "
800 "whitespace"))
801 "whitespace"))
801 scmutil.checknewlabel(repo, mark, 'bookmark')
802 scmutil.checknewlabel(repo, mark, 'bookmark')
802 return mark
803 return mark
803
804
804 def checkconflict(repo, mark, force=False):
805 def checkconflict(repo, mark, force=False):
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 in repo.branchmap() or mark == repo.dirstate.branch())
809 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
809 and not force):
810 and not force):
810 raise util.Abort(
811 raise util.Abort(
811 _("a bookmark cannot have the name of an existing branch"))
812 _("a bookmark cannot have the name of an existing branch"))
812
813
813 if delete and rename:
814 if delete and rename:
814 raise util.Abort(_("--delete and --rename are incompatible"))
815 raise util.Abort(_("--delete and --rename are incompatible"))
815 if delete and rev:
816 if delete and rev:
816 raise util.Abort(_("--rev is incompatible with --delete"))
817 raise util.Abort(_("--rev is incompatible with --delete"))
817 if rename and rev:
818 if rename and rev:
818 raise util.Abort(_("--rev is incompatible with --rename"))
819 raise util.Abort(_("--rev is incompatible with --rename"))
819 if mark is None and (delete or rev):
820 if mark is None and (delete or rev):
820 raise util.Abort(_("bookmark name required"))
821 raise util.Abort(_("bookmark name required"))
821
822
822 if delete:
823 if delete:
823 if mark not in marks:
824 if mark not in marks:
824 raise util.Abort(_("bookmark '%s' does not exist") % mark)
825 raise util.Abort(_("bookmark '%s' does not exist") % mark)
825 if mark == repo._bookmarkcurrent:
826 if mark == repo._bookmarkcurrent:
826 bookmarks.setcurrent(repo, None)
827 bookmarks.setcurrent(repo, None)
827 del marks[mark]
828 del marks[mark]
828 marks.write()
829 marks.write()
829
830
830 elif rename:
831 elif rename:
831 if mark is None:
832 if mark is None:
832 raise util.Abort(_("new bookmark name required"))
833 raise util.Abort(_("new bookmark name required"))
833 mark = checkformat(mark)
834 mark = checkformat(mark)
834 if rename not in marks:
835 if rename not in marks:
835 raise util.Abort(_("bookmark '%s' does not exist") % rename)
836 raise util.Abort(_("bookmark '%s' does not exist") % rename)
836 checkconflict(repo, mark, force)
837 checkconflict(repo, mark, force)
837 marks[mark] = marks[rename]
838 marks[mark] = marks[rename]
838 if repo._bookmarkcurrent == rename and not inactive:
839 if repo._bookmarkcurrent == rename and not inactive:
839 bookmarks.setcurrent(repo, mark)
840 bookmarks.setcurrent(repo, mark)
840 del marks[rename]
841 del marks[rename]
841 marks.write()
842 marks.write()
842
843
843 elif mark is not None:
844 elif mark is not None:
844 mark = checkformat(mark)
845 mark = checkformat(mark)
845 if inactive and mark == repo._bookmarkcurrent:
846 if inactive and mark == repo._bookmarkcurrent:
846 bookmarks.setcurrent(repo, None)
847 bookmarks.setcurrent(repo, None)
847 return
848 return
848 checkconflict(repo, mark, force)
849 checkconflict(repo, mark, force)
849 if rev:
850 if rev:
850 marks[mark] = scmutil.revsingle(repo, rev).node()
851 marks[mark] = scmutil.revsingle(repo, rev).node()
851 else:
852 else:
852 marks[mark] = cur
853 marks[mark] = cur
853 if not inactive and cur == marks[mark]:
854 if not inactive and cur == marks[mark]:
854 bookmarks.setcurrent(repo, mark)
855 bookmarks.setcurrent(repo, mark)
855 marks.write()
856 marks.write()
856
857
857 # Same message whether trying to deactivate the current bookmark (-i
858 # Same message whether trying to deactivate the current bookmark (-i
858 # with no NAME) or listing bookmarks
859 # with no NAME) or listing bookmarks
859 elif len(marks) == 0:
860 elif len(marks) == 0:
860 ui.status(_("no bookmarks set\n"))
861 ui.status(_("no bookmarks set\n"))
861
862
862 elif inactive:
863 elif inactive:
863 if not repo._bookmarkcurrent:
864 if not repo._bookmarkcurrent:
864 ui.status(_("no active bookmark\n"))
865 ui.status(_("no active bookmark\n"))
865 else:
866 else:
866 bookmarks.setcurrent(repo, None)
867 bookmarks.setcurrent(repo, None)
867
868
868 else: # show bookmarks
869 else: # show bookmarks
869 for bmark, n in sorted(marks.iteritems()):
870 for bmark, n in sorted(marks.iteritems()):
870 current = repo._bookmarkcurrent
871 current = repo._bookmarkcurrent
871 if bmark == current and n == cur:
872 if bmark == current and n == cur:
872 prefix, label = '*', 'bookmarks.current'
873 prefix, label = '*', 'bookmarks.current'
873 else:
874 else:
874 prefix, label = ' ', ''
875 prefix, label = ' ', ''
875
876
876 if ui.quiet:
877 if ui.quiet:
877 ui.write("%s\n" % bmark, label=label)
878 ui.write("%s\n" % bmark, label=label)
878 else:
879 else:
879 ui.write(" %s %-25s %d:%s\n" % (
880 ui.write(" %s %-25s %d:%s\n" % (
880 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
881 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
881 label=label)
882 label=label)
882
883
883 @command('branch',
884 @command('branch',
884 [('f', 'force', None,
885 [('f', 'force', None,
885 _('set branch name even if it shadows an existing branch')),
886 _('set branch name even if it shadows an existing branch')),
886 ('C', 'clean', None, _('reset branch name to parent branch name'))],
887 ('C', 'clean', None, _('reset branch name to parent branch name'))],
887 _('[-fC] [NAME]'))
888 _('[-fC] [NAME]'))
888 def branch(ui, repo, label=None, **opts):
889 def branch(ui, repo, label=None, **opts):
889 """set or show the current branch name
890 """set or show the current branch name
890
891
891 .. note::
892 .. note::
892 Branch names are permanent and global. Use :hg:`bookmark` to create a
893 Branch names are permanent and global. Use :hg:`bookmark` to create a
893 light-weight bookmark instead. See :hg:`help glossary` for more
894 light-weight bookmark instead. See :hg:`help glossary` for more
894 information about named branches and bookmarks.
895 information about named branches and bookmarks.
895
896
896 With no argument, show the current branch name. With one argument,
897 With no argument, show the current branch name. With one argument,
897 set the working directory branch name (the branch will not exist
898 set the working directory branch name (the branch will not exist
898 in the repository until the next commit). Standard practice
899 in the repository until the next commit). Standard practice
899 recommends that primary development take place on the 'default'
900 recommends that primary development take place on the 'default'
900 branch.
901 branch.
901
902
902 Unless -f/--force is specified, branch will not let you set a
903 Unless -f/--force is specified, branch will not let you set a
903 branch name that already exists, even if it's inactive.
904 branch name that already exists, even if it's inactive.
904
905
905 Use -C/--clean to reset the working directory branch to that of
906 Use -C/--clean to reset the working directory branch to that of
906 the parent of the working directory, negating a previous branch
907 the parent of the working directory, negating a previous branch
907 change.
908 change.
908
909
909 Use the command :hg:`update` to switch to an existing branch. Use
910 Use the command :hg:`update` to switch to an existing branch. Use
910 :hg:`commit --close-branch` to mark this branch as closed.
911 :hg:`commit --close-branch` to mark this branch as closed.
911
912
912 Returns 0 on success.
913 Returns 0 on success.
913 """
914 """
914 if not opts.get('clean') and not label:
915 if not opts.get('clean') and not label:
915 ui.write("%s\n" % repo.dirstate.branch())
916 ui.write("%s\n" % repo.dirstate.branch())
916 return
917 return
917
918
918 wlock = repo.wlock()
919 wlock = repo.wlock()
919 try:
920 try:
920 if opts.get('clean'):
921 if opts.get('clean'):
921 label = repo[None].p1().branch()
922 label = repo[None].p1().branch()
922 repo.dirstate.setbranch(label)
923 repo.dirstate.setbranch(label)
923 ui.status(_('reset working directory to branch %s\n') % label)
924 ui.status(_('reset working directory to branch %s\n') % label)
924 elif label:
925 elif label:
925 if not opts.get('force') and label in repo.branchmap():
926 if not opts.get('force') and label in repo.branchmap():
926 if label not in [p.branch() for p in repo.parents()]:
927 if label not in [p.branch() for p in repo.parents()]:
927 raise util.Abort(_('a branch of the same name already'
928 raise util.Abort(_('a branch of the same name already'
928 ' exists'),
929 ' exists'),
929 # i18n: "it" refers to an existing branch
930 # i18n: "it" refers to an existing branch
930 hint=_("use 'hg update' to switch to it"))
931 hint=_("use 'hg update' to switch to it"))
931 scmutil.checknewlabel(repo, label, 'branch')
932 scmutil.checknewlabel(repo, label, 'branch')
932 repo.dirstate.setbranch(label)
933 repo.dirstate.setbranch(label)
933 ui.status(_('marked working directory as branch %s\n') % label)
934 ui.status(_('marked working directory as branch %s\n') % label)
934 ui.status(_('(branches are permanent and global, '
935 ui.status(_('(branches are permanent and global, '
935 'did you want a bookmark?)\n'))
936 'did you want a bookmark?)\n'))
936 finally:
937 finally:
937 wlock.release()
938 wlock.release()
938
939
939 @command('branches',
940 @command('branches',
940 [('a', 'active', False, _('show only branches that have unmerged heads')),
941 [('a', 'active', False, _('show only branches that have unmerged heads')),
941 ('c', 'closed', False, _('show normal and closed branches'))],
942 ('c', 'closed', False, _('show normal and closed branches'))],
942 _('[-ac]'))
943 _('[-ac]'))
943 def branches(ui, repo, active=False, closed=False):
944 def branches(ui, repo, active=False, closed=False):
944 """list repository named branches
945 """list repository named branches
945
946
946 List the repository's named branches, indicating which ones are
947 List the repository's named branches, indicating which ones are
947 inactive. If -c/--closed is specified, also list branches which have
948 inactive. If -c/--closed is specified, also list branches which have
948 been marked closed (see :hg:`commit --close-branch`).
949 been marked closed (see :hg:`commit --close-branch`).
949
950
950 If -a/--active is specified, only show active branches. A branch
951 If -a/--active is specified, only show active branches. A branch
951 is considered active if it contains repository heads.
952 is considered active if it contains repository heads.
952
953
953 Use the command :hg:`update` to switch to an existing branch.
954 Use the command :hg:`update` to switch to an existing branch.
954
955
955 Returns 0.
956 Returns 0.
956 """
957 """
957
958
958 hexfunc = ui.debugflag and hex or short
959 hexfunc = ui.debugflag and hex or short
959
960
960 activebranches = set([repo[n].branch() for n in repo.heads()])
961 activebranches = set([repo[n].branch() for n in repo.heads()])
961 branches = []
962 branches = []
962 for tag, heads in repo.branchmap().iteritems():
963 for tag, heads in repo.branchmap().iteritems():
963 for h in reversed(heads):
964 for h in reversed(heads):
964 ctx = repo[h]
965 ctx = repo[h]
965 isopen = not ctx.closesbranch()
966 isopen = not ctx.closesbranch()
966 if isopen:
967 if isopen:
967 tip = ctx
968 tip = ctx
968 break
969 break
969 else:
970 else:
970 tip = repo[heads[-1]]
971 tip = repo[heads[-1]]
971 isactive = tag in activebranches and isopen
972 isactive = tag in activebranches and isopen
972 branches.append((tip, isactive, isopen))
973 branches.append((tip, isactive, isopen))
973 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
974 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
974 reverse=True)
975 reverse=True)
975
976
976 for ctx, isactive, isopen in branches:
977 for ctx, isactive, isopen in branches:
977 if (not active) or isactive:
978 if (not active) or isactive:
978 if isactive:
979 if isactive:
979 label = 'branches.active'
980 label = 'branches.active'
980 notice = ''
981 notice = ''
981 elif not isopen:
982 elif not isopen:
982 if not closed:
983 if not closed:
983 continue
984 continue
984 label = 'branches.closed'
985 label = 'branches.closed'
985 notice = _(' (closed)')
986 notice = _(' (closed)')
986 else:
987 else:
987 label = 'branches.inactive'
988 label = 'branches.inactive'
988 notice = _(' (inactive)')
989 notice = _(' (inactive)')
989 if ctx.branch() == repo.dirstate.branch():
990 if ctx.branch() == repo.dirstate.branch():
990 label = 'branches.current'
991 label = 'branches.current'
991 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
992 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
992 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
993 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
993 'log.changeset changeset.%s' % ctx.phasestr())
994 'log.changeset changeset.%s' % ctx.phasestr())
994 tag = ui.label(ctx.branch(), label)
995 tag = ui.label(ctx.branch(), label)
995 if ui.quiet:
996 if ui.quiet:
996 ui.write("%s\n" % tag)
997 ui.write("%s\n" % tag)
997 else:
998 else:
998 ui.write("%s %s%s\n" % (tag, rev, notice))
999 ui.write("%s %s%s\n" % (tag, rev, notice))
999
1000
1000 @command('bundle',
1001 @command('bundle',
1001 [('f', 'force', None, _('run even when the destination is unrelated')),
1002 [('f', 'force', None, _('run even when the destination is unrelated')),
1002 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1003 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1003 _('REV')),
1004 _('REV')),
1004 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1005 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1005 _('BRANCH')),
1006 _('BRANCH')),
1006 ('', 'base', [],
1007 ('', 'base', [],
1007 _('a base changeset assumed to be available at the destination'),
1008 _('a base changeset assumed to be available at the destination'),
1008 _('REV')),
1009 _('REV')),
1009 ('a', 'all', None, _('bundle all changesets in the repository')),
1010 ('a', 'all', None, _('bundle all changesets in the repository')),
1010 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1011 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1011 ] + remoteopts,
1012 ] + remoteopts,
1012 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1013 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1013 def bundle(ui, repo, fname, dest=None, **opts):
1014 def bundle(ui, repo, fname, dest=None, **opts):
1014 """create a changegroup file
1015 """create a changegroup file
1015
1016
1016 Generate a compressed changegroup file collecting changesets not
1017 Generate a compressed changegroup file collecting changesets not
1017 known to be in another repository.
1018 known to be in another repository.
1018
1019
1019 If you omit the destination repository, then hg assumes the
1020 If you omit the destination repository, then hg assumes the
1020 destination will have all the nodes you specify with --base
1021 destination will have all the nodes you specify with --base
1021 parameters. To create a bundle containing all changesets, use
1022 parameters. To create a bundle containing all changesets, use
1022 -a/--all (or --base null).
1023 -a/--all (or --base null).
1023
1024
1024 You can change compression method with the -t/--type option.
1025 You can change compression method with the -t/--type option.
1025 The available compression methods are: none, bzip2, and
1026 The available compression methods are: none, bzip2, and
1026 gzip (by default, bundles are compressed using bzip2).
1027 gzip (by default, bundles are compressed using bzip2).
1027
1028
1028 The bundle file can then be transferred using conventional means
1029 The bundle file can then be transferred using conventional means
1029 and applied to another repository with the unbundle or pull
1030 and applied to another repository with the unbundle or pull
1030 command. This is useful when direct push and pull are not
1031 command. This is useful when direct push and pull are not
1031 available or when exporting an entire repository is undesirable.
1032 available or when exporting an entire repository is undesirable.
1032
1033
1033 Applying bundles preserves all changeset contents including
1034 Applying bundles preserves all changeset contents including
1034 permissions, copy/rename information, and revision history.
1035 permissions, copy/rename information, and revision history.
1035
1036
1036 Returns 0 on success, 1 if no changes found.
1037 Returns 0 on success, 1 if no changes found.
1037 """
1038 """
1038 revs = None
1039 revs = None
1039 if 'rev' in opts:
1040 if 'rev' in opts:
1040 revs = scmutil.revrange(repo, opts['rev'])
1041 revs = scmutil.revrange(repo, opts['rev'])
1041
1042
1042 bundletype = opts.get('type', 'bzip2').lower()
1043 bundletype = opts.get('type', 'bzip2').lower()
1043 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1044 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1044 bundletype = btypes.get(bundletype)
1045 bundletype = btypes.get(bundletype)
1045 if bundletype not in changegroup.bundletypes:
1046 if bundletype not in changegroup.bundletypes:
1046 raise util.Abort(_('unknown bundle type specified with --type'))
1047 raise util.Abort(_('unknown bundle type specified with --type'))
1047
1048
1048 if opts.get('all'):
1049 if opts.get('all'):
1049 base = ['null']
1050 base = ['null']
1050 else:
1051 else:
1051 base = scmutil.revrange(repo, opts.get('base'))
1052 base = scmutil.revrange(repo, opts.get('base'))
1052 if base:
1053 if base:
1053 if dest:
1054 if dest:
1054 raise util.Abort(_("--base is incompatible with specifying "
1055 raise util.Abort(_("--base is incompatible with specifying "
1055 "a destination"))
1056 "a destination"))
1056 common = [repo.lookup(rev) for rev in base]
1057 common = [repo.lookup(rev) for rev in base]
1057 heads = revs and map(repo.lookup, revs) or revs
1058 heads = revs and map(repo.lookup, revs) or revs
1058 cg = repo.getbundle('bundle', heads=heads, common=common)
1059 cg = repo.getbundle('bundle', heads=heads, common=common)
1059 outgoing = None
1060 outgoing = None
1060 else:
1061 else:
1061 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1062 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1062 dest, branches = hg.parseurl(dest, opts.get('branch'))
1063 dest, branches = hg.parseurl(dest, opts.get('branch'))
1063 other = hg.peer(repo, opts, dest)
1064 other = hg.peer(repo, opts, dest)
1064 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1065 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1065 heads = revs and map(repo.lookup, revs) or revs
1066 heads = revs and map(repo.lookup, revs) or revs
1066 outgoing = discovery.findcommonoutgoing(repo, other,
1067 outgoing = discovery.findcommonoutgoing(repo, other,
1067 onlyheads=heads,
1068 onlyheads=heads,
1068 force=opts.get('force'),
1069 force=opts.get('force'),
1069 portable=True)
1070 portable=True)
1070 cg = repo.getlocalbundle('bundle', outgoing)
1071 cg = repo.getlocalbundle('bundle', outgoing)
1071 if not cg:
1072 if not cg:
1072 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1073 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1073 return 1
1074 return 1
1074
1075
1075 changegroup.writebundle(cg, fname, bundletype)
1076 changegroup.writebundle(cg, fname, bundletype)
1076
1077
1077 @command('cat',
1078 @command('cat',
1078 [('o', 'output', '',
1079 [('o', 'output', '',
1079 _('print output to file with formatted name'), _('FORMAT')),
1080 _('print output to file with formatted name'), _('FORMAT')),
1080 ('r', 'rev', '', _('print the given revision'), _('REV')),
1081 ('r', 'rev', '', _('print the given revision'), _('REV')),
1081 ('', 'decode', None, _('apply any matching decode filter')),
1082 ('', 'decode', None, _('apply any matching decode filter')),
1082 ] + walkopts,
1083 ] + walkopts,
1083 _('[OPTION]... FILE...'))
1084 _('[OPTION]... FILE...'))
1084 def cat(ui, repo, file1, *pats, **opts):
1085 def cat(ui, repo, file1, *pats, **opts):
1085 """output the current or given revision of files
1086 """output the current or given revision of files
1086
1087
1087 Print the specified files as they were at the given revision. If
1088 Print the specified files as they were at the given revision. If
1088 no revision is given, the parent of the working directory is used,
1089 no revision is given, the parent of the working directory is used,
1089 or tip if no revision is checked out.
1090 or tip if no revision is checked out.
1090
1091
1091 Output may be to a file, in which case the name of the file is
1092 Output may be to a file, in which case the name of the file is
1092 given using a format string. The formatting rules are the same as
1093 given using a format string. The formatting rules are the same as
1093 for the export command, with the following additions:
1094 for the export command, with the following additions:
1094
1095
1095 :``%s``: basename of file being printed
1096 :``%s``: basename of file being printed
1096 :``%d``: dirname of file being printed, or '.' if in repository root
1097 :``%d``: dirname of file being printed, or '.' if in repository root
1097 :``%p``: root-relative path name of file being printed
1098 :``%p``: root-relative path name of file being printed
1098
1099
1099 Returns 0 on success.
1100 Returns 0 on success.
1100 """
1101 """
1101 ctx = scmutil.revsingle(repo, opts.get('rev'))
1102 ctx = scmutil.revsingle(repo, opts.get('rev'))
1102 err = 1
1103 err = 1
1103 m = scmutil.match(ctx, (file1,) + pats, opts)
1104 m = scmutil.match(ctx, (file1,) + pats, opts)
1104 for abs in ctx.walk(m):
1105 for abs in ctx.walk(m):
1105 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1106 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1106 pathname=abs)
1107 pathname=abs)
1107 data = ctx[abs].data()
1108 data = ctx[abs].data()
1108 if opts.get('decode'):
1109 if opts.get('decode'):
1109 data = repo.wwritedata(abs, data)
1110 data = repo.wwritedata(abs, data)
1110 fp.write(data)
1111 fp.write(data)
1111 fp.close()
1112 fp.close()
1112 err = 0
1113 err = 0
1113 return err
1114 return err
1114
1115
1115 @command('^clone',
1116 @command('^clone',
1116 [('U', 'noupdate', None,
1117 [('U', 'noupdate', None,
1117 _('the clone will include an empty working copy (only a repository)')),
1118 _('the clone will include an empty working copy (only a repository)')),
1118 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1119 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1119 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1120 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1120 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1121 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1121 ('', 'pull', None, _('use pull protocol to copy metadata')),
1122 ('', 'pull', None, _('use pull protocol to copy metadata')),
1122 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1123 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1123 ] + remoteopts,
1124 ] + remoteopts,
1124 _('[OPTION]... SOURCE [DEST]'))
1125 _('[OPTION]... SOURCE [DEST]'))
1125 def clone(ui, source, dest=None, **opts):
1126 def clone(ui, source, dest=None, **opts):
1126 """make a copy of an existing repository
1127 """make a copy of an existing repository
1127
1128
1128 Create a copy of an existing repository in a new directory.
1129 Create a copy of an existing repository in a new directory.
1129
1130
1130 If no destination directory name is specified, it defaults to the
1131 If no destination directory name is specified, it defaults to the
1131 basename of the source.
1132 basename of the source.
1132
1133
1133 The location of the source is added to the new repository's
1134 The location of the source is added to the new repository's
1134 ``.hg/hgrc`` file, as the default to be used for future pulls.
1135 ``.hg/hgrc`` file, as the default to be used for future pulls.
1135
1136
1136 Only local paths and ``ssh://`` URLs are supported as
1137 Only local paths and ``ssh://`` URLs are supported as
1137 destinations. For ``ssh://`` destinations, no working directory or
1138 destinations. For ``ssh://`` destinations, no working directory or
1138 ``.hg/hgrc`` will be created on the remote side.
1139 ``.hg/hgrc`` will be created on the remote side.
1139
1140
1140 To pull only a subset of changesets, specify one or more revisions
1141 To pull only a subset of changesets, specify one or more revisions
1141 identifiers with -r/--rev or branches with -b/--branch. The
1142 identifiers with -r/--rev or branches with -b/--branch. The
1142 resulting clone will contain only the specified changesets and
1143 resulting clone will contain only the specified changesets and
1143 their ancestors. These options (or 'clone src#rev dest') imply
1144 their ancestors. These options (or 'clone src#rev dest') imply
1144 --pull, even for local source repositories. Note that specifying a
1145 --pull, even for local source repositories. Note that specifying a
1145 tag will include the tagged changeset but not the changeset
1146 tag will include the tagged changeset but not the changeset
1146 containing the tag.
1147 containing the tag.
1147
1148
1148 To check out a particular version, use -u/--update, or
1149 To check out a particular version, use -u/--update, or
1149 -U/--noupdate to create a clone with no working directory.
1150 -U/--noupdate to create a clone with no working directory.
1150
1151
1151 .. container:: verbose
1152 .. container:: verbose
1152
1153
1153 For efficiency, hardlinks are used for cloning whenever the
1154 For efficiency, hardlinks are used for cloning whenever the
1154 source and destination are on the same filesystem (note this
1155 source and destination are on the same filesystem (note this
1155 applies only to the repository data, not to the working
1156 applies only to the repository data, not to the working
1156 directory). Some filesystems, such as AFS, implement hardlinking
1157 directory). Some filesystems, such as AFS, implement hardlinking
1157 incorrectly, but do not report errors. In these cases, use the
1158 incorrectly, but do not report errors. In these cases, use the
1158 --pull option to avoid hardlinking.
1159 --pull option to avoid hardlinking.
1159
1160
1160 In some cases, you can clone repositories and the working
1161 In some cases, you can clone repositories and the working
1161 directory using full hardlinks with ::
1162 directory using full hardlinks with ::
1162
1163
1163 $ cp -al REPO REPOCLONE
1164 $ cp -al REPO REPOCLONE
1164
1165
1165 This is the fastest way to clone, but it is not always safe. The
1166 This is the fastest way to clone, but it is not always safe. The
1166 operation is not atomic (making sure REPO is not modified during
1167 operation is not atomic (making sure REPO is not modified during
1167 the operation is up to you) and you have to make sure your
1168 the operation is up to you) and you have to make sure your
1168 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1169 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1169 so). Also, this is not compatible with certain extensions that
1170 so). Also, this is not compatible with certain extensions that
1170 place their metadata under the .hg directory, such as mq.
1171 place their metadata under the .hg directory, such as mq.
1171
1172
1172 Mercurial will update the working directory to the first applicable
1173 Mercurial will update the working directory to the first applicable
1173 revision from this list:
1174 revision from this list:
1174
1175
1175 a) null if -U or the source repository has no changesets
1176 a) null if -U or the source repository has no changesets
1176 b) if -u . and the source repository is local, the first parent of
1177 b) if -u . and the source repository is local, the first parent of
1177 the source repository's working directory
1178 the source repository's working directory
1178 c) the changeset specified with -u (if a branch name, this means the
1179 c) the changeset specified with -u (if a branch name, this means the
1179 latest head of that branch)
1180 latest head of that branch)
1180 d) the changeset specified with -r
1181 d) the changeset specified with -r
1181 e) the tipmost head specified with -b
1182 e) the tipmost head specified with -b
1182 f) the tipmost head specified with the url#branch source syntax
1183 f) the tipmost head specified with the url#branch source syntax
1183 g) the tipmost head of the default branch
1184 g) the tipmost head of the default branch
1184 h) tip
1185 h) tip
1185
1186
1186 Examples:
1187 Examples:
1187
1188
1188 - clone a remote repository to a new directory named hg/::
1189 - clone a remote repository to a new directory named hg/::
1189
1190
1190 hg clone http://selenic.com/hg
1191 hg clone http://selenic.com/hg
1191
1192
1192 - create a lightweight local clone::
1193 - create a lightweight local clone::
1193
1194
1194 hg clone project/ project-feature/
1195 hg clone project/ project-feature/
1195
1196
1196 - clone from an absolute path on an ssh server (note double-slash)::
1197 - clone from an absolute path on an ssh server (note double-slash)::
1197
1198
1198 hg clone ssh://user@server//home/projects/alpha/
1199 hg clone ssh://user@server//home/projects/alpha/
1199
1200
1200 - do a high-speed clone over a LAN while checking out a
1201 - do a high-speed clone over a LAN while checking out a
1201 specified version::
1202 specified version::
1202
1203
1203 hg clone --uncompressed http://server/repo -u 1.5
1204 hg clone --uncompressed http://server/repo -u 1.5
1204
1205
1205 - create a repository without changesets after a particular revision::
1206 - create a repository without changesets after a particular revision::
1206
1207
1207 hg clone -r 04e544 experimental/ good/
1208 hg clone -r 04e544 experimental/ good/
1208
1209
1209 - clone (and track) a particular named branch::
1210 - clone (and track) a particular named branch::
1210
1211
1211 hg clone http://selenic.com/hg#stable
1212 hg clone http://selenic.com/hg#stable
1212
1213
1213 See :hg:`help urls` for details on specifying URLs.
1214 See :hg:`help urls` for details on specifying URLs.
1214
1215
1215 Returns 0 on success.
1216 Returns 0 on success.
1216 """
1217 """
1217 if opts.get('noupdate') and opts.get('updaterev'):
1218 if opts.get('noupdate') and opts.get('updaterev'):
1218 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1219 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1219
1220
1220 r = hg.clone(ui, opts, source, dest,
1221 r = hg.clone(ui, opts, source, dest,
1221 pull=opts.get('pull'),
1222 pull=opts.get('pull'),
1222 stream=opts.get('uncompressed'),
1223 stream=opts.get('uncompressed'),
1223 rev=opts.get('rev'),
1224 rev=opts.get('rev'),
1224 update=opts.get('updaterev') or not opts.get('noupdate'),
1225 update=opts.get('updaterev') or not opts.get('noupdate'),
1225 branch=opts.get('branch'))
1226 branch=opts.get('branch'))
1226
1227
1227 return r is None
1228 return r is None
1228
1229
1229 @command('^commit|ci',
1230 @command('^commit|ci',
1230 [('A', 'addremove', None,
1231 [('A', 'addremove', None,
1231 _('mark new/missing files as added/removed before committing')),
1232 _('mark new/missing files as added/removed before committing')),
1232 ('', 'close-branch', None,
1233 ('', 'close-branch', None,
1233 _('mark a branch as closed, hiding it from the branch list')),
1234 _('mark a branch as closed, hiding it from the branch list')),
1234 ('', 'amend', None, _('amend the parent of the working dir')),
1235 ('', 'amend', None, _('amend the parent of the working dir')),
1235 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1236 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1236 _('[OPTION]... [FILE]...'))
1237 _('[OPTION]... [FILE]...'))
1237 def commit(ui, repo, *pats, **opts):
1238 def commit(ui, repo, *pats, **opts):
1238 """commit the specified files or all outstanding changes
1239 """commit the specified files or all outstanding changes
1239
1240
1240 Commit changes to the given files into the repository. Unlike a
1241 Commit changes to the given files into the repository. Unlike a
1241 centralized SCM, this operation is a local operation. See
1242 centralized SCM, this operation is a local operation. See
1242 :hg:`push` for a way to actively distribute your changes.
1243 :hg:`push` for a way to actively distribute your changes.
1243
1244
1244 If a list of files is omitted, all changes reported by :hg:`status`
1245 If a list of files is omitted, all changes reported by :hg:`status`
1245 will be committed.
1246 will be committed.
1246
1247
1247 If you are committing the result of a merge, do not provide any
1248 If you are committing the result of a merge, do not provide any
1248 filenames or -I/-X filters.
1249 filenames or -I/-X filters.
1249
1250
1250 If no commit message is specified, Mercurial starts your
1251 If no commit message is specified, Mercurial starts your
1251 configured editor where you can enter a message. In case your
1252 configured editor where you can enter a message. In case your
1252 commit fails, you will find a backup of your message in
1253 commit fails, you will find a backup of your message in
1253 ``.hg/last-message.txt``.
1254 ``.hg/last-message.txt``.
1254
1255
1255 The --amend flag can be used to amend the parent of the
1256 The --amend flag can be used to amend the parent of the
1256 working directory with a new commit that contains the changes
1257 working directory with a new commit that contains the changes
1257 in the parent in addition to those currently reported by :hg:`status`,
1258 in the parent in addition to those currently reported by :hg:`status`,
1258 if there are any. The old commit is stored in a backup bundle in
1259 if there are any. The old commit is stored in a backup bundle in
1259 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1260 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1260 on how to restore it).
1261 on how to restore it).
1261
1262
1262 Message, user and date are taken from the amended commit unless
1263 Message, user and date are taken from the amended commit unless
1263 specified. When a message isn't specified on the command line,
1264 specified. When a message isn't specified on the command line,
1264 the editor will open with the message of the amended commit.
1265 the editor will open with the message of the amended commit.
1265
1266
1266 It is not possible to amend public changesets (see :hg:`help phases`)
1267 It is not possible to amend public changesets (see :hg:`help phases`)
1267 or changesets that have children.
1268 or changesets that have children.
1268
1269
1269 See :hg:`help dates` for a list of formats valid for -d/--date.
1270 See :hg:`help dates` for a list of formats valid for -d/--date.
1270
1271
1271 Returns 0 on success, 1 if nothing changed.
1272 Returns 0 on success, 1 if nothing changed.
1272 """
1273 """
1273 if opts.get('subrepos'):
1274 if opts.get('subrepos'):
1274 # Let --subrepos on the command line override config setting.
1275 # Let --subrepos on the command line override config setting.
1275 ui.setconfig('ui', 'commitsubrepos', True)
1276 ui.setconfig('ui', 'commitsubrepos', True)
1276
1277
1277 extra = {}
1278 extra = {}
1278 if opts.get('close_branch'):
1279 if opts.get('close_branch'):
1279 if repo['.'].node() not in repo.branchheads():
1280 if repo['.'].node() not in repo.branchheads():
1280 # The topo heads set is included in the branch heads set of the
1281 # The topo heads set is included in the branch heads set of the
1281 # current branch, so it's sufficient to test branchheads
1282 # current branch, so it's sufficient to test branchheads
1282 raise util.Abort(_('can only close branch heads'))
1283 raise util.Abort(_('can only close branch heads'))
1283 extra['close'] = 1
1284 extra['close'] = 1
1284
1285
1285 branch = repo[None].branch()
1286 branch = repo[None].branch()
1286 bheads = repo.branchheads(branch)
1287 bheads = repo.branchheads(branch)
1287
1288
1288 if opts.get('amend'):
1289 if opts.get('amend'):
1289 if ui.configbool('ui', 'commitsubrepos'):
1290 if ui.configbool('ui', 'commitsubrepos'):
1290 raise util.Abort(_('cannot amend recursively'))
1291 raise util.Abort(_('cannot amend recursively'))
1291
1292
1292 old = repo['.']
1293 old = repo['.']
1293 if old.phase() == phases.public:
1294 if old.phase() == phases.public:
1294 raise util.Abort(_('cannot amend public changesets'))
1295 raise util.Abort(_('cannot amend public changesets'))
1295 if len(old.parents()) > 1:
1296 if len(old.parents()) > 1:
1296 raise util.Abort(_('cannot amend merge changesets'))
1297 raise util.Abort(_('cannot amend merge changesets'))
1297 if len(repo[None].parents()) > 1:
1298 if len(repo[None].parents()) > 1:
1298 raise util.Abort(_('cannot amend while merging'))
1299 raise util.Abort(_('cannot amend while merging'))
1299 if (not obsolete._enabled) and old.children():
1300 if (not obsolete._enabled) and old.children():
1300 raise util.Abort(_('cannot amend changeset with children'))
1301 raise util.Abort(_('cannot amend changeset with children'))
1301
1302
1302 e = cmdutil.commiteditor
1303 e = cmdutil.commiteditor
1303 if opts.get('force_editor'):
1304 if opts.get('force_editor'):
1304 e = cmdutil.commitforceeditor
1305 e = cmdutil.commitforceeditor
1305
1306
1306 def commitfunc(ui, repo, message, match, opts):
1307 def commitfunc(ui, repo, message, match, opts):
1307 editor = e
1308 editor = e
1308 # message contains text from -m or -l, if it's empty,
1309 # message contains text from -m or -l, if it's empty,
1309 # open the editor with the old message
1310 # open the editor with the old message
1310 if not message:
1311 if not message:
1311 message = old.description()
1312 message = old.description()
1312 editor = cmdutil.commitforceeditor
1313 editor = cmdutil.commitforceeditor
1313 return repo.commit(message,
1314 return repo.commit(message,
1314 opts.get('user') or old.user(),
1315 opts.get('user') or old.user(),
1315 opts.get('date') or old.date(),
1316 opts.get('date') or old.date(),
1316 match,
1317 match,
1317 editor=editor,
1318 editor=editor,
1318 extra=extra)
1319 extra=extra)
1319
1320
1320 current = repo._bookmarkcurrent
1321 current = repo._bookmarkcurrent
1321 marks = old.bookmarks()
1322 marks = old.bookmarks()
1322 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1323 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1323 if node == old.node():
1324 if node == old.node():
1324 ui.status(_("nothing changed\n"))
1325 ui.status(_("nothing changed\n"))
1325 return 1
1326 return 1
1326 elif marks:
1327 elif marks:
1327 ui.debug('moving bookmarks %r from %s to %s\n' %
1328 ui.debug('moving bookmarks %r from %s to %s\n' %
1328 (marks, old.hex(), hex(node)))
1329 (marks, old.hex(), hex(node)))
1329 newmarks = repo._bookmarks
1330 newmarks = repo._bookmarks
1330 for bm in marks:
1331 for bm in marks:
1331 newmarks[bm] = node
1332 newmarks[bm] = node
1332 if bm == current:
1333 if bm == current:
1333 bookmarks.setcurrent(repo, bm)
1334 bookmarks.setcurrent(repo, bm)
1334 newmarks.write()
1335 newmarks.write()
1335 else:
1336 else:
1336 e = cmdutil.commiteditor
1337 e = cmdutil.commiteditor
1337 if opts.get('force_editor'):
1338 if opts.get('force_editor'):
1338 e = cmdutil.commitforceeditor
1339 e = cmdutil.commitforceeditor
1339
1340
1340 def commitfunc(ui, repo, message, match, opts):
1341 def commitfunc(ui, repo, message, match, opts):
1341 return repo.commit(message, opts.get('user'), opts.get('date'),
1342 return repo.commit(message, opts.get('user'), opts.get('date'),
1342 match, editor=e, extra=extra)
1343 match, editor=e, extra=extra)
1343
1344
1344 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1345 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1345
1346
1346 if not node:
1347 if not node:
1347 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1348 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1348 if stat[3]:
1349 if stat[3]:
1349 ui.status(_("nothing changed (%d missing files, see "
1350 ui.status(_("nothing changed (%d missing files, see "
1350 "'hg status')\n") % len(stat[3]))
1351 "'hg status')\n") % len(stat[3]))
1351 else:
1352 else:
1352 ui.status(_("nothing changed\n"))
1353 ui.status(_("nothing changed\n"))
1353 return 1
1354 return 1
1354
1355
1355 ctx = repo[node]
1356 ctx = repo[node]
1356 parents = ctx.parents()
1357 parents = ctx.parents()
1357
1358
1358 if (not opts.get('amend') and bheads and node not in bheads and not
1359 if (not opts.get('amend') and bheads and node not in bheads and not
1359 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1360 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1360 ui.status(_('created new head\n'))
1361 ui.status(_('created new head\n'))
1361 # The message is not printed for initial roots. For the other
1362 # The message is not printed for initial roots. For the other
1362 # changesets, it is printed in the following situations:
1363 # changesets, it is printed in the following situations:
1363 #
1364 #
1364 # Par column: for the 2 parents with ...
1365 # Par column: for the 2 parents with ...
1365 # N: null or no parent
1366 # N: null or no parent
1366 # B: parent is on another named branch
1367 # B: parent is on another named branch
1367 # C: parent is a regular non head changeset
1368 # C: parent is a regular non head changeset
1368 # H: parent was a branch head of the current branch
1369 # H: parent was a branch head of the current branch
1369 # Msg column: whether we print "created new head" message
1370 # Msg column: whether we print "created new head" message
1370 # In the following, it is assumed that there already exists some
1371 # In the following, it is assumed that there already exists some
1371 # initial branch heads of the current branch, otherwise nothing is
1372 # initial branch heads of the current branch, otherwise nothing is
1372 # printed anyway.
1373 # printed anyway.
1373 #
1374 #
1374 # Par Msg Comment
1375 # Par Msg Comment
1375 # N N y additional topo root
1376 # N N y additional topo root
1376 #
1377 #
1377 # B N y additional branch root
1378 # B N y additional branch root
1378 # C N y additional topo head
1379 # C N y additional topo head
1379 # H N n usual case
1380 # H N n usual case
1380 #
1381 #
1381 # B B y weird additional branch root
1382 # B B y weird additional branch root
1382 # C B y branch merge
1383 # C B y branch merge
1383 # H B n merge with named branch
1384 # H B n merge with named branch
1384 #
1385 #
1385 # C C y additional head from merge
1386 # C C y additional head from merge
1386 # C H n merge with a head
1387 # C H n merge with a head
1387 #
1388 #
1388 # H H n head merge: head count decreases
1389 # H H n head merge: head count decreases
1389
1390
1390 if not opts.get('close_branch'):
1391 if not opts.get('close_branch'):
1391 for r in parents:
1392 for r in parents:
1392 if r.closesbranch() and r.branch() == branch:
1393 if r.closesbranch() and r.branch() == branch:
1393 ui.status(_('reopening closed branch head %d\n') % r)
1394 ui.status(_('reopening closed branch head %d\n') % r)
1394
1395
1395 if ui.debugflag:
1396 if ui.debugflag:
1396 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1397 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1397 elif ui.verbose:
1398 elif ui.verbose:
1398 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1399 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1399
1400
1400 @command('copy|cp',
1401 @command('copy|cp',
1401 [('A', 'after', None, _('record a copy that has already occurred')),
1402 [('A', 'after', None, _('record a copy that has already occurred')),
1402 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1403 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1403 ] + walkopts + dryrunopts,
1404 ] + walkopts + dryrunopts,
1404 _('[OPTION]... [SOURCE]... DEST'))
1405 _('[OPTION]... [SOURCE]... DEST'))
1405 def copy(ui, repo, *pats, **opts):
1406 def copy(ui, repo, *pats, **opts):
1406 """mark files as copied for the next commit
1407 """mark files as copied for the next commit
1407
1408
1408 Mark dest as having copies of source files. If dest is a
1409 Mark dest as having copies of source files. If dest is a
1409 directory, copies are put in that directory. If dest is a file,
1410 directory, copies are put in that directory. If dest is a file,
1410 the source must be a single file.
1411 the source must be a single file.
1411
1412
1412 By default, this command copies the contents of files as they
1413 By default, this command copies the contents of files as they
1413 exist in the working directory. If invoked with -A/--after, the
1414 exist in the working directory. If invoked with -A/--after, the
1414 operation is recorded, but no copying is performed.
1415 operation is recorded, but no copying is performed.
1415
1416
1416 This command takes effect with the next commit. To undo a copy
1417 This command takes effect with the next commit. To undo a copy
1417 before that, see :hg:`revert`.
1418 before that, see :hg:`revert`.
1418
1419
1419 Returns 0 on success, 1 if errors are encountered.
1420 Returns 0 on success, 1 if errors are encountered.
1420 """
1421 """
1421 wlock = repo.wlock(False)
1422 wlock = repo.wlock(False)
1422 try:
1423 try:
1423 return cmdutil.copy(ui, repo, pats, opts)
1424 return cmdutil.copy(ui, repo, pats, opts)
1424 finally:
1425 finally:
1425 wlock.release()
1426 wlock.release()
1426
1427
1427 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1428 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1428 def debugancestor(ui, repo, *args):
1429 def debugancestor(ui, repo, *args):
1429 """find the ancestor revision of two revisions in a given index"""
1430 """find the ancestor revision of two revisions in a given index"""
1430 if len(args) == 3:
1431 if len(args) == 3:
1431 index, rev1, rev2 = args
1432 index, rev1, rev2 = args
1432 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1433 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1433 lookup = r.lookup
1434 lookup = r.lookup
1434 elif len(args) == 2:
1435 elif len(args) == 2:
1435 if not repo:
1436 if not repo:
1436 raise util.Abort(_("there is no Mercurial repository here "
1437 raise util.Abort(_("there is no Mercurial repository here "
1437 "(.hg not found)"))
1438 "(.hg not found)"))
1438 rev1, rev2 = args
1439 rev1, rev2 = args
1439 r = repo.changelog
1440 r = repo.changelog
1440 lookup = repo.lookup
1441 lookup = repo.lookup
1441 else:
1442 else:
1442 raise util.Abort(_('either two or three arguments required'))
1443 raise util.Abort(_('either two or three arguments required'))
1443 a = r.ancestor(lookup(rev1), lookup(rev2))
1444 a = r.ancestor(lookup(rev1), lookup(rev2))
1444 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1445 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1445
1446
1446 @command('debugbuilddag',
1447 @command('debugbuilddag',
1447 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1448 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1448 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1449 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1449 ('n', 'new-file', None, _('add new file at each rev'))],
1450 ('n', 'new-file', None, _('add new file at each rev'))],
1450 _('[OPTION]... [TEXT]'))
1451 _('[OPTION]... [TEXT]'))
1451 def debugbuilddag(ui, repo, text=None,
1452 def debugbuilddag(ui, repo, text=None,
1452 mergeable_file=False,
1453 mergeable_file=False,
1453 overwritten_file=False,
1454 overwritten_file=False,
1454 new_file=False):
1455 new_file=False):
1455 """builds a repo with a given DAG from scratch in the current empty repo
1456 """builds a repo with a given DAG from scratch in the current empty repo
1456
1457
1457 The description of the DAG is read from stdin if not given on the
1458 The description of the DAG is read from stdin if not given on the
1458 command line.
1459 command line.
1459
1460
1460 Elements:
1461 Elements:
1461
1462
1462 - "+n" is a linear run of n nodes based on the current default parent
1463 - "+n" is a linear run of n nodes based on the current default parent
1463 - "." is a single node based on the current default parent
1464 - "." is a single node based on the current default parent
1464 - "$" resets the default parent to null (implied at the start);
1465 - "$" resets the default parent to null (implied at the start);
1465 otherwise the default parent is always the last node created
1466 otherwise the default parent is always the last node created
1466 - "<p" sets the default parent to the backref p
1467 - "<p" sets the default parent to the backref p
1467 - "*p" is a fork at parent p, which is a backref
1468 - "*p" is a fork at parent p, which is a backref
1468 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1469 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1469 - "/p2" is a merge of the preceding node and p2
1470 - "/p2" is a merge of the preceding node and p2
1470 - ":tag" defines a local tag for the preceding node
1471 - ":tag" defines a local tag for the preceding node
1471 - "@branch" sets the named branch for subsequent nodes
1472 - "@branch" sets the named branch for subsequent nodes
1472 - "#...\\n" is a comment up to the end of the line
1473 - "#...\\n" is a comment up to the end of the line
1473
1474
1474 Whitespace between the above elements is ignored.
1475 Whitespace between the above elements is ignored.
1475
1476
1476 A backref is either
1477 A backref is either
1477
1478
1478 - a number n, which references the node curr-n, where curr is the current
1479 - a number n, which references the node curr-n, where curr is the current
1479 node, or
1480 node, or
1480 - the name of a local tag you placed earlier using ":tag", or
1481 - the name of a local tag you placed earlier using ":tag", or
1481 - empty to denote the default parent.
1482 - empty to denote the default parent.
1482
1483
1483 All string valued-elements are either strictly alphanumeric, or must
1484 All string valued-elements are either strictly alphanumeric, or must
1484 be enclosed in double quotes ("..."), with "\\" as escape character.
1485 be enclosed in double quotes ("..."), with "\\" as escape character.
1485 """
1486 """
1486
1487
1487 if text is None:
1488 if text is None:
1488 ui.status(_("reading DAG from stdin\n"))
1489 ui.status(_("reading DAG from stdin\n"))
1489 text = ui.fin.read()
1490 text = ui.fin.read()
1490
1491
1491 cl = repo.changelog
1492 cl = repo.changelog
1492 if len(cl) > 0:
1493 if len(cl) > 0:
1493 raise util.Abort(_('repository is not empty'))
1494 raise util.Abort(_('repository is not empty'))
1494
1495
1495 # determine number of revs in DAG
1496 # determine number of revs in DAG
1496 total = 0
1497 total = 0
1497 for type, data in dagparser.parsedag(text):
1498 for type, data in dagparser.parsedag(text):
1498 if type == 'n':
1499 if type == 'n':
1499 total += 1
1500 total += 1
1500
1501
1501 if mergeable_file:
1502 if mergeable_file:
1502 linesperrev = 2
1503 linesperrev = 2
1503 # make a file with k lines per rev
1504 # make a file with k lines per rev
1504 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1505 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1505 initialmergedlines.append("")
1506 initialmergedlines.append("")
1506
1507
1507 tags = []
1508 tags = []
1508
1509
1509 lock = tr = None
1510 lock = tr = None
1510 try:
1511 try:
1511 lock = repo.lock()
1512 lock = repo.lock()
1512 tr = repo.transaction("builddag")
1513 tr = repo.transaction("builddag")
1513
1514
1514 at = -1
1515 at = -1
1515 atbranch = 'default'
1516 atbranch = 'default'
1516 nodeids = []
1517 nodeids = []
1517 id = 0
1518 id = 0
1518 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1519 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1519 for type, data in dagparser.parsedag(text):
1520 for type, data in dagparser.parsedag(text):
1520 if type == 'n':
1521 if type == 'n':
1521 ui.note(('node %s\n' % str(data)))
1522 ui.note(('node %s\n' % str(data)))
1522 id, ps = data
1523 id, ps = data
1523
1524
1524 files = []
1525 files = []
1525 fctxs = {}
1526 fctxs = {}
1526
1527
1527 p2 = None
1528 p2 = None
1528 if mergeable_file:
1529 if mergeable_file:
1529 fn = "mf"
1530 fn = "mf"
1530 p1 = repo[ps[0]]
1531 p1 = repo[ps[0]]
1531 if len(ps) > 1:
1532 if len(ps) > 1:
1532 p2 = repo[ps[1]]
1533 p2 = repo[ps[1]]
1533 pa = p1.ancestor(p2)
1534 pa = p1.ancestor(p2)
1534 base, local, other = [x[fn].data() for x in (pa, p1,
1535 base, local, other = [x[fn].data() for x in (pa, p1,
1535 p2)]
1536 p2)]
1536 m3 = simplemerge.Merge3Text(base, local, other)
1537 m3 = simplemerge.Merge3Text(base, local, other)
1537 ml = [l.strip() for l in m3.merge_lines()]
1538 ml = [l.strip() for l in m3.merge_lines()]
1538 ml.append("")
1539 ml.append("")
1539 elif at > 0:
1540 elif at > 0:
1540 ml = p1[fn].data().split("\n")
1541 ml = p1[fn].data().split("\n")
1541 else:
1542 else:
1542 ml = initialmergedlines
1543 ml = initialmergedlines
1543 ml[id * linesperrev] += " r%i" % id
1544 ml[id * linesperrev] += " r%i" % id
1544 mergedtext = "\n".join(ml)
1545 mergedtext = "\n".join(ml)
1545 files.append(fn)
1546 files.append(fn)
1546 fctxs[fn] = context.memfilectx(fn, mergedtext)
1547 fctxs[fn] = context.memfilectx(fn, mergedtext)
1547
1548
1548 if overwritten_file:
1549 if overwritten_file:
1549 fn = "of"
1550 fn = "of"
1550 files.append(fn)
1551 files.append(fn)
1551 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1552 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1552
1553
1553 if new_file:
1554 if new_file:
1554 fn = "nf%i" % id
1555 fn = "nf%i" % id
1555 files.append(fn)
1556 files.append(fn)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557 if len(ps) > 1:
1558 if len(ps) > 1:
1558 if not p2:
1559 if not p2:
1559 p2 = repo[ps[1]]
1560 p2 = repo[ps[1]]
1560 for fn in p2:
1561 for fn in p2:
1561 if fn.startswith("nf"):
1562 if fn.startswith("nf"):
1562 files.append(fn)
1563 files.append(fn)
1563 fctxs[fn] = p2[fn]
1564 fctxs[fn] = p2[fn]
1564
1565
1565 def fctxfn(repo, cx, path):
1566 def fctxfn(repo, cx, path):
1566 return fctxs.get(path)
1567 return fctxs.get(path)
1567
1568
1568 if len(ps) == 0 or ps[0] < 0:
1569 if len(ps) == 0 or ps[0] < 0:
1569 pars = [None, None]
1570 pars = [None, None]
1570 elif len(ps) == 1:
1571 elif len(ps) == 1:
1571 pars = [nodeids[ps[0]], None]
1572 pars = [nodeids[ps[0]], None]
1572 else:
1573 else:
1573 pars = [nodeids[p] for p in ps]
1574 pars = [nodeids[p] for p in ps]
1574 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1575 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1575 date=(id, 0),
1576 date=(id, 0),
1576 user="debugbuilddag",
1577 user="debugbuilddag",
1577 extra={'branch': atbranch})
1578 extra={'branch': atbranch})
1578 nodeid = repo.commitctx(cx)
1579 nodeid = repo.commitctx(cx)
1579 nodeids.append(nodeid)
1580 nodeids.append(nodeid)
1580 at = id
1581 at = id
1581 elif type == 'l':
1582 elif type == 'l':
1582 id, name = data
1583 id, name = data
1583 ui.note(('tag %s\n' % name))
1584 ui.note(('tag %s\n' % name))
1584 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1585 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1585 elif type == 'a':
1586 elif type == 'a':
1586 ui.note(('branch %s\n' % data))
1587 ui.note(('branch %s\n' % data))
1587 atbranch = data
1588 atbranch = data
1588 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1589 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1589 tr.close()
1590 tr.close()
1590
1591
1591 if tags:
1592 if tags:
1592 repo.opener.write("localtags", "".join(tags))
1593 repo.opener.write("localtags", "".join(tags))
1593 finally:
1594 finally:
1594 ui.progress(_('building'), None)
1595 ui.progress(_('building'), None)
1595 release(tr, lock)
1596 release(tr, lock)
1596
1597
1597 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1598 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1598 def debugbundle(ui, bundlepath, all=None, **opts):
1599 def debugbundle(ui, bundlepath, all=None, **opts):
1599 """lists the contents of a bundle"""
1600 """lists the contents of a bundle"""
1600 f = hg.openpath(ui, bundlepath)
1601 f = hg.openpath(ui, bundlepath)
1601 try:
1602 try:
1602 gen = changegroup.readbundle(f, bundlepath)
1603 gen = changegroup.readbundle(f, bundlepath)
1603 if all:
1604 if all:
1604 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1605 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1605
1606
1606 def showchunks(named):
1607 def showchunks(named):
1607 ui.write("\n%s\n" % named)
1608 ui.write("\n%s\n" % named)
1608 chain = None
1609 chain = None
1609 while True:
1610 while True:
1610 chunkdata = gen.deltachunk(chain)
1611 chunkdata = gen.deltachunk(chain)
1611 if not chunkdata:
1612 if not chunkdata:
1612 break
1613 break
1613 node = chunkdata['node']
1614 node = chunkdata['node']
1614 p1 = chunkdata['p1']
1615 p1 = chunkdata['p1']
1615 p2 = chunkdata['p2']
1616 p2 = chunkdata['p2']
1616 cs = chunkdata['cs']
1617 cs = chunkdata['cs']
1617 deltabase = chunkdata['deltabase']
1618 deltabase = chunkdata['deltabase']
1618 delta = chunkdata['delta']
1619 delta = chunkdata['delta']
1619 ui.write("%s %s %s %s %s %s\n" %
1620 ui.write("%s %s %s %s %s %s\n" %
1620 (hex(node), hex(p1), hex(p2),
1621 (hex(node), hex(p1), hex(p2),
1621 hex(cs), hex(deltabase), len(delta)))
1622 hex(cs), hex(deltabase), len(delta)))
1622 chain = node
1623 chain = node
1623
1624
1624 chunkdata = gen.changelogheader()
1625 chunkdata = gen.changelogheader()
1625 showchunks("changelog")
1626 showchunks("changelog")
1626 chunkdata = gen.manifestheader()
1627 chunkdata = gen.manifestheader()
1627 showchunks("manifest")
1628 showchunks("manifest")
1628 while True:
1629 while True:
1629 chunkdata = gen.filelogheader()
1630 chunkdata = gen.filelogheader()
1630 if not chunkdata:
1631 if not chunkdata:
1631 break
1632 break
1632 fname = chunkdata['filename']
1633 fname = chunkdata['filename']
1633 showchunks(fname)
1634 showchunks(fname)
1634 else:
1635 else:
1635 chunkdata = gen.changelogheader()
1636 chunkdata = gen.changelogheader()
1636 chain = None
1637 chain = None
1637 while True:
1638 while True:
1638 chunkdata = gen.deltachunk(chain)
1639 chunkdata = gen.deltachunk(chain)
1639 if not chunkdata:
1640 if not chunkdata:
1640 break
1641 break
1641 node = chunkdata['node']
1642 node = chunkdata['node']
1642 ui.write("%s\n" % hex(node))
1643 ui.write("%s\n" % hex(node))
1643 chain = node
1644 chain = node
1644 finally:
1645 finally:
1645 f.close()
1646 f.close()
1646
1647
1647 @command('debugcheckstate', [], '')
1648 @command('debugcheckstate', [], '')
1648 def debugcheckstate(ui, repo):
1649 def debugcheckstate(ui, repo):
1649 """validate the correctness of the current dirstate"""
1650 """validate the correctness of the current dirstate"""
1650 parent1, parent2 = repo.dirstate.parents()
1651 parent1, parent2 = repo.dirstate.parents()
1651 m1 = repo[parent1].manifest()
1652 m1 = repo[parent1].manifest()
1652 m2 = repo[parent2].manifest()
1653 m2 = repo[parent2].manifest()
1653 errors = 0
1654 errors = 0
1654 for f in repo.dirstate:
1655 for f in repo.dirstate:
1655 state = repo.dirstate[f]
1656 state = repo.dirstate[f]
1656 if state in "nr" and f not in m1:
1657 if state in "nr" and f not in m1:
1657 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1658 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1658 errors += 1
1659 errors += 1
1659 if state in "a" and f in m1:
1660 if state in "a" and f in m1:
1660 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1661 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1661 errors += 1
1662 errors += 1
1662 if state in "m" and f not in m1 and f not in m2:
1663 if state in "m" and f not in m1 and f not in m2:
1663 ui.warn(_("%s in state %s, but not in either manifest\n") %
1664 ui.warn(_("%s in state %s, but not in either manifest\n") %
1664 (f, state))
1665 (f, state))
1665 errors += 1
1666 errors += 1
1666 for f in m1:
1667 for f in m1:
1667 state = repo.dirstate[f]
1668 state = repo.dirstate[f]
1668 if state not in "nrm":
1669 if state not in "nrm":
1669 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1670 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1670 errors += 1
1671 errors += 1
1671 if errors:
1672 if errors:
1672 error = _(".hg/dirstate inconsistent with current parent's manifest")
1673 error = _(".hg/dirstate inconsistent with current parent's manifest")
1673 raise util.Abort(error)
1674 raise util.Abort(error)
1674
1675
1675 @command('debugcommands', [], _('[COMMAND]'))
1676 @command('debugcommands', [], _('[COMMAND]'))
1676 def debugcommands(ui, cmd='', *args):
1677 def debugcommands(ui, cmd='', *args):
1677 """list all available commands and options"""
1678 """list all available commands and options"""
1678 for cmd, vals in sorted(table.iteritems()):
1679 for cmd, vals in sorted(table.iteritems()):
1679 cmd = cmd.split('|')[0].strip('^')
1680 cmd = cmd.split('|')[0].strip('^')
1680 opts = ', '.join([i[1] for i in vals[1]])
1681 opts = ', '.join([i[1] for i in vals[1]])
1681 ui.write('%s: %s\n' % (cmd, opts))
1682 ui.write('%s: %s\n' % (cmd, opts))
1682
1683
1683 @command('debugcomplete',
1684 @command('debugcomplete',
1684 [('o', 'options', None, _('show the command options'))],
1685 [('o', 'options', None, _('show the command options'))],
1685 _('[-o] CMD'))
1686 _('[-o] CMD'))
1686 def debugcomplete(ui, cmd='', **opts):
1687 def debugcomplete(ui, cmd='', **opts):
1687 """returns the completion list associated with the given command"""
1688 """returns the completion list associated with the given command"""
1688
1689
1689 if opts.get('options'):
1690 if opts.get('options'):
1690 options = []
1691 options = []
1691 otables = [globalopts]
1692 otables = [globalopts]
1692 if cmd:
1693 if cmd:
1693 aliases, entry = cmdutil.findcmd(cmd, table, False)
1694 aliases, entry = cmdutil.findcmd(cmd, table, False)
1694 otables.append(entry[1])
1695 otables.append(entry[1])
1695 for t in otables:
1696 for t in otables:
1696 for o in t:
1697 for o in t:
1697 if "(DEPRECATED)" in o[3]:
1698 if "(DEPRECATED)" in o[3]:
1698 continue
1699 continue
1699 if o[0]:
1700 if o[0]:
1700 options.append('-%s' % o[0])
1701 options.append('-%s' % o[0])
1701 options.append('--%s' % o[1])
1702 options.append('--%s' % o[1])
1702 ui.write("%s\n" % "\n".join(options))
1703 ui.write("%s\n" % "\n".join(options))
1703 return
1704 return
1704
1705
1705 cmdlist = cmdutil.findpossible(cmd, table)
1706 cmdlist = cmdutil.findpossible(cmd, table)
1706 if ui.verbose:
1707 if ui.verbose:
1707 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1708 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1708 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1709 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1709
1710
1710 @command('debugdag',
1711 @command('debugdag',
1711 [('t', 'tags', None, _('use tags as labels')),
1712 [('t', 'tags', None, _('use tags as labels')),
1712 ('b', 'branches', None, _('annotate with branch names')),
1713 ('b', 'branches', None, _('annotate with branch names')),
1713 ('', 'dots', None, _('use dots for runs')),
1714 ('', 'dots', None, _('use dots for runs')),
1714 ('s', 'spaces', None, _('separate elements by spaces'))],
1715 ('s', 'spaces', None, _('separate elements by spaces'))],
1715 _('[OPTION]... [FILE [REV]...]'))
1716 _('[OPTION]... [FILE [REV]...]'))
1716 def debugdag(ui, repo, file_=None, *revs, **opts):
1717 def debugdag(ui, repo, file_=None, *revs, **opts):
1717 """format the changelog or an index DAG as a concise textual description
1718 """format the changelog or an index DAG as a concise textual description
1718
1719
1719 If you pass a revlog index, the revlog's DAG is emitted. If you list
1720 If you pass a revlog index, the revlog's DAG is emitted. If you list
1720 revision numbers, they get labeled in the output as rN.
1721 revision numbers, they get labeled in the output as rN.
1721
1722
1722 Otherwise, the changelog DAG of the current repo is emitted.
1723 Otherwise, the changelog DAG of the current repo is emitted.
1723 """
1724 """
1724 spaces = opts.get('spaces')
1725 spaces = opts.get('spaces')
1725 dots = opts.get('dots')
1726 dots = opts.get('dots')
1726 if file_:
1727 if file_:
1727 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1728 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1728 revs = set((int(r) for r in revs))
1729 revs = set((int(r) for r in revs))
1729 def events():
1730 def events():
1730 for r in rlog:
1731 for r in rlog:
1731 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1732 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1732 if p != -1)))
1733 if p != -1)))
1733 if r in revs:
1734 if r in revs:
1734 yield 'l', (r, "r%i" % r)
1735 yield 'l', (r, "r%i" % r)
1735 elif repo:
1736 elif repo:
1736 cl = repo.changelog
1737 cl = repo.changelog
1737 tags = opts.get('tags')
1738 tags = opts.get('tags')
1738 branches = opts.get('branches')
1739 branches = opts.get('branches')
1739 if tags:
1740 if tags:
1740 labels = {}
1741 labels = {}
1741 for l, n in repo.tags().items():
1742 for l, n in repo.tags().items():
1742 labels.setdefault(cl.rev(n), []).append(l)
1743 labels.setdefault(cl.rev(n), []).append(l)
1743 def events():
1744 def events():
1744 b = "default"
1745 b = "default"
1745 for r in cl:
1746 for r in cl:
1746 if branches:
1747 if branches:
1747 newb = cl.read(cl.node(r))[5]['branch']
1748 newb = cl.read(cl.node(r))[5]['branch']
1748 if newb != b:
1749 if newb != b:
1749 yield 'a', newb
1750 yield 'a', newb
1750 b = newb
1751 b = newb
1751 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1752 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1752 if p != -1)))
1753 if p != -1)))
1753 if tags:
1754 if tags:
1754 ls = labels.get(r)
1755 ls = labels.get(r)
1755 if ls:
1756 if ls:
1756 for l in ls:
1757 for l in ls:
1757 yield 'l', (r, l)
1758 yield 'l', (r, l)
1758 else:
1759 else:
1759 raise util.Abort(_('need repo for changelog dag'))
1760 raise util.Abort(_('need repo for changelog dag'))
1760
1761
1761 for line in dagparser.dagtextlines(events(),
1762 for line in dagparser.dagtextlines(events(),
1762 addspaces=spaces,
1763 addspaces=spaces,
1763 wraplabels=True,
1764 wraplabels=True,
1764 wrapannotations=True,
1765 wrapannotations=True,
1765 wrapnonlinear=dots,
1766 wrapnonlinear=dots,
1766 usedots=dots,
1767 usedots=dots,
1767 maxlinewidth=70):
1768 maxlinewidth=70):
1768 ui.write(line)
1769 ui.write(line)
1769 ui.write("\n")
1770 ui.write("\n")
1770
1771
1771 @command('debugdata',
1772 @command('debugdata',
1772 [('c', 'changelog', False, _('open changelog')),
1773 [('c', 'changelog', False, _('open changelog')),
1773 ('m', 'manifest', False, _('open manifest'))],
1774 ('m', 'manifest', False, _('open manifest'))],
1774 _('-c|-m|FILE REV'))
1775 _('-c|-m|FILE REV'))
1775 def debugdata(ui, repo, file_, rev = None, **opts):
1776 def debugdata(ui, repo, file_, rev = None, **opts):
1776 """dump the contents of a data file revision"""
1777 """dump the contents of a data file revision"""
1777 if opts.get('changelog') or opts.get('manifest'):
1778 if opts.get('changelog') or opts.get('manifest'):
1778 file_, rev = None, file_
1779 file_, rev = None, file_
1779 elif rev is None:
1780 elif rev is None:
1780 raise error.CommandError('debugdata', _('invalid arguments'))
1781 raise error.CommandError('debugdata', _('invalid arguments'))
1781 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1782 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1782 try:
1783 try:
1783 ui.write(r.revision(r.lookup(rev)))
1784 ui.write(r.revision(r.lookup(rev)))
1784 except KeyError:
1785 except KeyError:
1785 raise util.Abort(_('invalid revision identifier %s') % rev)
1786 raise util.Abort(_('invalid revision identifier %s') % rev)
1786
1787
1787 @command('debugdate',
1788 @command('debugdate',
1788 [('e', 'extended', None, _('try extended date formats'))],
1789 [('e', 'extended', None, _('try extended date formats'))],
1789 _('[-e] DATE [RANGE]'))
1790 _('[-e] DATE [RANGE]'))
1790 def debugdate(ui, date, range=None, **opts):
1791 def debugdate(ui, date, range=None, **opts):
1791 """parse and display a date"""
1792 """parse and display a date"""
1792 if opts["extended"]:
1793 if opts["extended"]:
1793 d = util.parsedate(date, util.extendeddateformats)
1794 d = util.parsedate(date, util.extendeddateformats)
1794 else:
1795 else:
1795 d = util.parsedate(date)
1796 d = util.parsedate(date)
1796 ui.write(("internal: %s %s\n") % d)
1797 ui.write(("internal: %s %s\n") % d)
1797 ui.write(("standard: %s\n") % util.datestr(d))
1798 ui.write(("standard: %s\n") % util.datestr(d))
1798 if range:
1799 if range:
1799 m = util.matchdate(range)
1800 m = util.matchdate(range)
1800 ui.write(("match: %s\n") % m(d[0]))
1801 ui.write(("match: %s\n") % m(d[0]))
1801
1802
1802 @command('debugdiscovery',
1803 @command('debugdiscovery',
1803 [('', 'old', None, _('use old-style discovery')),
1804 [('', 'old', None, _('use old-style discovery')),
1804 ('', 'nonheads', None,
1805 ('', 'nonheads', None,
1805 _('use old-style discovery with non-heads included')),
1806 _('use old-style discovery with non-heads included')),
1806 ] + remoteopts,
1807 ] + remoteopts,
1807 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1808 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1808 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1809 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1809 """runs the changeset discovery protocol in isolation"""
1810 """runs the changeset discovery protocol in isolation"""
1810 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1811 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1811 opts.get('branch'))
1812 opts.get('branch'))
1812 remote = hg.peer(repo, opts, remoteurl)
1813 remote = hg.peer(repo, opts, remoteurl)
1813 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1814 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1814
1815
1815 # make sure tests are repeatable
1816 # make sure tests are repeatable
1816 random.seed(12323)
1817 random.seed(12323)
1817
1818
1818 def doit(localheads, remoteheads, remote=remote):
1819 def doit(localheads, remoteheads, remote=remote):
1819 if opts.get('old'):
1820 if opts.get('old'):
1820 if localheads:
1821 if localheads:
1821 raise util.Abort('cannot use localheads with old style '
1822 raise util.Abort('cannot use localheads with old style '
1822 'discovery')
1823 'discovery')
1823 if not util.safehasattr(remote, 'branches'):
1824 if not util.safehasattr(remote, 'branches'):
1824 # enable in-client legacy support
1825 # enable in-client legacy support
1825 remote = localrepo.locallegacypeer(remote.local())
1826 remote = localrepo.locallegacypeer(remote.local())
1826 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1827 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1827 force=True)
1828 force=True)
1828 common = set(common)
1829 common = set(common)
1829 if not opts.get('nonheads'):
1830 if not opts.get('nonheads'):
1830 ui.write(("unpruned common: %s\n") %
1831 ui.write(("unpruned common: %s\n") %
1831 " ".join(sorted(short(n) for n in common)))
1832 " ".join(sorted(short(n) for n in common)))
1832 dag = dagutil.revlogdag(repo.changelog)
1833 dag = dagutil.revlogdag(repo.changelog)
1833 all = dag.ancestorset(dag.internalizeall(common))
1834 all = dag.ancestorset(dag.internalizeall(common))
1834 common = dag.externalizeall(dag.headsetofconnecteds(all))
1835 common = dag.externalizeall(dag.headsetofconnecteds(all))
1835 else:
1836 else:
1836 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1837 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1837 common = set(common)
1838 common = set(common)
1838 rheads = set(hds)
1839 rheads = set(hds)
1839 lheads = set(repo.heads())
1840 lheads = set(repo.heads())
1840 ui.write(("common heads: %s\n") %
1841 ui.write(("common heads: %s\n") %
1841 " ".join(sorted(short(n) for n in common)))
1842 " ".join(sorted(short(n) for n in common)))
1842 if lheads <= common:
1843 if lheads <= common:
1843 ui.write(("local is subset\n"))
1844 ui.write(("local is subset\n"))
1844 elif rheads <= common:
1845 elif rheads <= common:
1845 ui.write(("remote is subset\n"))
1846 ui.write(("remote is subset\n"))
1846
1847
1847 serverlogs = opts.get('serverlog')
1848 serverlogs = opts.get('serverlog')
1848 if serverlogs:
1849 if serverlogs:
1849 for filename in serverlogs:
1850 for filename in serverlogs:
1850 logfile = open(filename, 'r')
1851 logfile = open(filename, 'r')
1851 try:
1852 try:
1852 line = logfile.readline()
1853 line = logfile.readline()
1853 while line:
1854 while line:
1854 parts = line.strip().split(';')
1855 parts = line.strip().split(';')
1855 op = parts[1]
1856 op = parts[1]
1856 if op == 'cg':
1857 if op == 'cg':
1857 pass
1858 pass
1858 elif op == 'cgss':
1859 elif op == 'cgss':
1859 doit(parts[2].split(' '), parts[3].split(' '))
1860 doit(parts[2].split(' '), parts[3].split(' '))
1860 elif op == 'unb':
1861 elif op == 'unb':
1861 doit(parts[3].split(' '), parts[2].split(' '))
1862 doit(parts[3].split(' '), parts[2].split(' '))
1862 line = logfile.readline()
1863 line = logfile.readline()
1863 finally:
1864 finally:
1864 logfile.close()
1865 logfile.close()
1865
1866
1866 else:
1867 else:
1867 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1868 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1868 opts.get('remote_head'))
1869 opts.get('remote_head'))
1869 localrevs = opts.get('local_head')
1870 localrevs = opts.get('local_head')
1870 doit(localrevs, remoterevs)
1871 doit(localrevs, remoterevs)
1871
1872
1872 @command('debugfileset',
1873 @command('debugfileset',
1873 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1874 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1874 _('[-r REV] FILESPEC'))
1875 _('[-r REV] FILESPEC'))
1875 def debugfileset(ui, repo, expr, **opts):
1876 def debugfileset(ui, repo, expr, **opts):
1876 '''parse and apply a fileset specification'''
1877 '''parse and apply a fileset specification'''
1877 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1878 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1878 if ui.verbose:
1879 if ui.verbose:
1879 tree = fileset.parse(expr)[0]
1880 tree = fileset.parse(expr)[0]
1880 ui.note(tree, "\n")
1881 ui.note(tree, "\n")
1881
1882
1882 for f in fileset.getfileset(ctx, expr):
1883 for f in fileset.getfileset(ctx, expr):
1883 ui.write("%s\n" % f)
1884 ui.write("%s\n" % f)
1884
1885
1885 @command('debugfsinfo', [], _('[PATH]'))
1886 @command('debugfsinfo', [], _('[PATH]'))
1886 def debugfsinfo(ui, path = "."):
1887 def debugfsinfo(ui, path = "."):
1887 """show information detected about current filesystem"""
1888 """show information detected about current filesystem"""
1888 util.writefile('.debugfsinfo', '')
1889 util.writefile('.debugfsinfo', '')
1889 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1890 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1890 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1891 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1891 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1892 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1892 and 'yes' or 'no'))
1893 and 'yes' or 'no'))
1893 os.unlink('.debugfsinfo')
1894 os.unlink('.debugfsinfo')
1894
1895
1895 @command('debuggetbundle',
1896 @command('debuggetbundle',
1896 [('H', 'head', [], _('id of head node'), _('ID')),
1897 [('H', 'head', [], _('id of head node'), _('ID')),
1897 ('C', 'common', [], _('id of common node'), _('ID')),
1898 ('C', 'common', [], _('id of common node'), _('ID')),
1898 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1899 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1899 _('REPO FILE [-H|-C ID]...'))
1900 _('REPO FILE [-H|-C ID]...'))
1900 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1901 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1901 """retrieves a bundle from a repo
1902 """retrieves a bundle from a repo
1902
1903
1903 Every ID must be a full-length hex node id string. Saves the bundle to the
1904 Every ID must be a full-length hex node id string. Saves the bundle to the
1904 given file.
1905 given file.
1905 """
1906 """
1906 repo = hg.peer(ui, opts, repopath)
1907 repo = hg.peer(ui, opts, repopath)
1907 if not repo.capable('getbundle'):
1908 if not repo.capable('getbundle'):
1908 raise util.Abort("getbundle() not supported by target repository")
1909 raise util.Abort("getbundle() not supported by target repository")
1909 args = {}
1910 args = {}
1910 if common:
1911 if common:
1911 args['common'] = [bin(s) for s in common]
1912 args['common'] = [bin(s) for s in common]
1912 if head:
1913 if head:
1913 args['heads'] = [bin(s) for s in head]
1914 args['heads'] = [bin(s) for s in head]
1914 bundle = repo.getbundle('debug', **args)
1915 bundle = repo.getbundle('debug', **args)
1915
1916
1916 bundletype = opts.get('type', 'bzip2').lower()
1917 bundletype = opts.get('type', 'bzip2').lower()
1917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1918 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1918 bundletype = btypes.get(bundletype)
1919 bundletype = btypes.get(bundletype)
1919 if bundletype not in changegroup.bundletypes:
1920 if bundletype not in changegroup.bundletypes:
1920 raise util.Abort(_('unknown bundle type specified with --type'))
1921 raise util.Abort(_('unknown bundle type specified with --type'))
1921 changegroup.writebundle(bundle, bundlepath, bundletype)
1922 changegroup.writebundle(bundle, bundlepath, bundletype)
1922
1923
1923 @command('debugignore', [], '')
1924 @command('debugignore', [], '')
1924 def debugignore(ui, repo, *values, **opts):
1925 def debugignore(ui, repo, *values, **opts):
1925 """display the combined ignore pattern"""
1926 """display the combined ignore pattern"""
1926 ignore = repo.dirstate._ignore
1927 ignore = repo.dirstate._ignore
1927 includepat = getattr(ignore, 'includepat', None)
1928 includepat = getattr(ignore, 'includepat', None)
1928 if includepat is not None:
1929 if includepat is not None:
1929 ui.write("%s\n" % includepat)
1930 ui.write("%s\n" % includepat)
1930 else:
1931 else:
1931 raise util.Abort(_("no ignore patterns found"))
1932 raise util.Abort(_("no ignore patterns found"))
1932
1933
1933 @command('debugindex',
1934 @command('debugindex',
1934 [('c', 'changelog', False, _('open changelog')),
1935 [('c', 'changelog', False, _('open changelog')),
1935 ('m', 'manifest', False, _('open manifest')),
1936 ('m', 'manifest', False, _('open manifest')),
1936 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1937 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1937 _('[-f FORMAT] -c|-m|FILE'))
1938 _('[-f FORMAT] -c|-m|FILE'))
1938 def debugindex(ui, repo, file_ = None, **opts):
1939 def debugindex(ui, repo, file_ = None, **opts):
1939 """dump the contents of an index file"""
1940 """dump the contents of an index file"""
1940 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1941 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1941 format = opts.get('format', 0)
1942 format = opts.get('format', 0)
1942 if format not in (0, 1):
1943 if format not in (0, 1):
1943 raise util.Abort(_("unknown format %d") % format)
1944 raise util.Abort(_("unknown format %d") % format)
1944
1945
1945 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1946 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1946 if generaldelta:
1947 if generaldelta:
1947 basehdr = ' delta'
1948 basehdr = ' delta'
1948 else:
1949 else:
1949 basehdr = ' base'
1950 basehdr = ' base'
1950
1951
1951 if format == 0:
1952 if format == 0:
1952 ui.write(" rev offset length " + basehdr + " linkrev"
1953 ui.write(" rev offset length " + basehdr + " linkrev"
1953 " nodeid p1 p2\n")
1954 " nodeid p1 p2\n")
1954 elif format == 1:
1955 elif format == 1:
1955 ui.write(" rev flag offset length"
1956 ui.write(" rev flag offset length"
1956 " size " + basehdr + " link p1 p2"
1957 " size " + basehdr + " link p1 p2"
1957 " nodeid\n")
1958 " nodeid\n")
1958
1959
1959 for i in r:
1960 for i in r:
1960 node = r.node(i)
1961 node = r.node(i)
1961 if generaldelta:
1962 if generaldelta:
1962 base = r.deltaparent(i)
1963 base = r.deltaparent(i)
1963 else:
1964 else:
1964 base = r.chainbase(i)
1965 base = r.chainbase(i)
1965 if format == 0:
1966 if format == 0:
1966 try:
1967 try:
1967 pp = r.parents(node)
1968 pp = r.parents(node)
1968 except Exception:
1969 except Exception:
1969 pp = [nullid, nullid]
1970 pp = [nullid, nullid]
1970 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1971 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1971 i, r.start(i), r.length(i), base, r.linkrev(i),
1972 i, r.start(i), r.length(i), base, r.linkrev(i),
1972 short(node), short(pp[0]), short(pp[1])))
1973 short(node), short(pp[0]), short(pp[1])))
1973 elif format == 1:
1974 elif format == 1:
1974 pr = r.parentrevs(i)
1975 pr = r.parentrevs(i)
1975 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1976 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1976 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1977 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1977 base, r.linkrev(i), pr[0], pr[1], short(node)))
1978 base, r.linkrev(i), pr[0], pr[1], short(node)))
1978
1979
1979 @command('debugindexdot', [], _('FILE'))
1980 @command('debugindexdot', [], _('FILE'))
1980 def debugindexdot(ui, repo, file_):
1981 def debugindexdot(ui, repo, file_):
1981 """dump an index DAG as a graphviz dot file"""
1982 """dump an index DAG as a graphviz dot file"""
1982 r = None
1983 r = None
1983 if repo:
1984 if repo:
1984 filelog = repo.file(file_)
1985 filelog = repo.file(file_)
1985 if len(filelog):
1986 if len(filelog):
1986 r = filelog
1987 r = filelog
1987 if not r:
1988 if not r:
1988 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1989 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1989 ui.write(("digraph G {\n"))
1990 ui.write(("digraph G {\n"))
1990 for i in r:
1991 for i in r:
1991 node = r.node(i)
1992 node = r.node(i)
1992 pp = r.parents(node)
1993 pp = r.parents(node)
1993 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1994 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1994 if pp[1] != nullid:
1995 if pp[1] != nullid:
1995 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1996 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1996 ui.write("}\n")
1997 ui.write("}\n")
1997
1998
1998 @command('debuginstall', [], '')
1999 @command('debuginstall', [], '')
1999 def debuginstall(ui):
2000 def debuginstall(ui):
2000 '''test Mercurial installation
2001 '''test Mercurial installation
2001
2002
2002 Returns 0 on success.
2003 Returns 0 on success.
2003 '''
2004 '''
2004
2005
2005 def writetemp(contents):
2006 def writetemp(contents):
2006 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2007 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2007 f = os.fdopen(fd, "wb")
2008 f = os.fdopen(fd, "wb")
2008 f.write(contents)
2009 f.write(contents)
2009 f.close()
2010 f.close()
2010 return name
2011 return name
2011
2012
2012 problems = 0
2013 problems = 0
2013
2014
2014 # encoding
2015 # encoding
2015 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2016 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2016 try:
2017 try:
2017 encoding.fromlocal("test")
2018 encoding.fromlocal("test")
2018 except util.Abort, inst:
2019 except util.Abort, inst:
2019 ui.write(" %s\n" % inst)
2020 ui.write(" %s\n" % inst)
2020 ui.write(_(" (check that your locale is properly set)\n"))
2021 ui.write(_(" (check that your locale is properly set)\n"))
2021 problems += 1
2022 problems += 1
2022
2023
2023 # Python lib
2024 # Python lib
2024 ui.status(_("checking Python lib (%s)...\n")
2025 ui.status(_("checking Python lib (%s)...\n")
2025 % os.path.dirname(os.__file__))
2026 % os.path.dirname(os.__file__))
2026
2027
2027 # compiled modules
2028 # compiled modules
2028 ui.status(_("checking installed modules (%s)...\n")
2029 ui.status(_("checking installed modules (%s)...\n")
2029 % os.path.dirname(__file__))
2030 % os.path.dirname(__file__))
2030 try:
2031 try:
2031 import bdiff, mpatch, base85, osutil
2032 import bdiff, mpatch, base85, osutil
2032 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2033 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2033 except Exception, inst:
2034 except Exception, inst:
2034 ui.write(" %s\n" % inst)
2035 ui.write(" %s\n" % inst)
2035 ui.write(_(" One or more extensions could not be found"))
2036 ui.write(_(" One or more extensions could not be found"))
2036 ui.write(_(" (check that you compiled the extensions)\n"))
2037 ui.write(_(" (check that you compiled the extensions)\n"))
2037 problems += 1
2038 problems += 1
2038
2039
2039 # templates
2040 # templates
2040 import templater
2041 import templater
2041 p = templater.templatepath()
2042 p = templater.templatepath()
2042 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2043 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2043 try:
2044 try:
2044 templater.templater(templater.templatepath("map-cmdline.default"))
2045 templater.templater(templater.templatepath("map-cmdline.default"))
2045 except Exception, inst:
2046 except Exception, inst:
2046 ui.write(" %s\n" % inst)
2047 ui.write(" %s\n" % inst)
2047 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2048 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2048 problems += 1
2049 problems += 1
2049
2050
2050 # editor
2051 # editor
2051 ui.status(_("checking commit editor...\n"))
2052 ui.status(_("checking commit editor...\n"))
2052 editor = ui.geteditor()
2053 editor = ui.geteditor()
2053 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2054 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2054 if not cmdpath:
2055 if not cmdpath:
2055 if editor == 'vi':
2056 if editor == 'vi':
2056 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2057 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2057 ui.write(_(" (specify a commit editor in your configuration"
2058 ui.write(_(" (specify a commit editor in your configuration"
2058 " file)\n"))
2059 " file)\n"))
2059 else:
2060 else:
2060 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2061 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2061 ui.write(_(" (specify a commit editor in your configuration"
2062 ui.write(_(" (specify a commit editor in your configuration"
2062 " file)\n"))
2063 " file)\n"))
2063 problems += 1
2064 problems += 1
2064
2065
2065 # check username
2066 # check username
2066 ui.status(_("checking username...\n"))
2067 ui.status(_("checking username...\n"))
2067 try:
2068 try:
2068 ui.username()
2069 ui.username()
2069 except util.Abort, e:
2070 except util.Abort, e:
2070 ui.write(" %s\n" % e)
2071 ui.write(" %s\n" % e)
2071 ui.write(_(" (specify a username in your configuration file)\n"))
2072 ui.write(_(" (specify a username in your configuration file)\n"))
2072 problems += 1
2073 problems += 1
2073
2074
2074 if not problems:
2075 if not problems:
2075 ui.status(_("no problems detected\n"))
2076 ui.status(_("no problems detected\n"))
2076 else:
2077 else:
2077 ui.write(_("%s problems detected,"
2078 ui.write(_("%s problems detected,"
2078 " please check your install!\n") % problems)
2079 " please check your install!\n") % problems)
2079
2080
2080 return problems
2081 return problems
2081
2082
2082 @command('debugknown', [], _('REPO ID...'))
2083 @command('debugknown', [], _('REPO ID...'))
2083 def debugknown(ui, repopath, *ids, **opts):
2084 def debugknown(ui, repopath, *ids, **opts):
2084 """test whether node ids are known to a repo
2085 """test whether node ids are known to a repo
2085
2086
2086 Every ID must be a full-length hex node id string. Returns a list of 0s
2087 Every ID must be a full-length hex node id string. Returns a list of 0s
2087 and 1s indicating unknown/known.
2088 and 1s indicating unknown/known.
2088 """
2089 """
2089 repo = hg.peer(ui, opts, repopath)
2090 repo = hg.peer(ui, opts, repopath)
2090 if not repo.capable('known'):
2091 if not repo.capable('known'):
2091 raise util.Abort("known() not supported by target repository")
2092 raise util.Abort("known() not supported by target repository")
2092 flags = repo.known([bin(s) for s in ids])
2093 flags = repo.known([bin(s) for s in ids])
2093 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2094 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2094
2095
2095 @command('debugobsolete',
2096 @command('debugobsolete',
2096 [('', 'flags', 0, _('markers flag')),
2097 [('', 'flags', 0, _('markers flag')),
2097 ] + commitopts2,
2098 ] + commitopts2,
2098 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2099 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2099 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2100 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2100 """create arbitrary obsolete marker"""
2101 """create arbitrary obsolete marker"""
2101 def parsenodeid(s):
2102 def parsenodeid(s):
2102 try:
2103 try:
2103 # We do not use revsingle/revrange functions here to accept
2104 # We do not use revsingle/revrange functions here to accept
2104 # arbitrary node identifiers, possibly not present in the
2105 # arbitrary node identifiers, possibly not present in the
2105 # local repository.
2106 # local repository.
2106 n = bin(s)
2107 n = bin(s)
2107 if len(n) != len(nullid):
2108 if len(n) != len(nullid):
2108 raise TypeError()
2109 raise TypeError()
2109 return n
2110 return n
2110 except TypeError:
2111 except TypeError:
2111 raise util.Abort('changeset references must be full hexadecimal '
2112 raise util.Abort('changeset references must be full hexadecimal '
2112 'node identifiers')
2113 'node identifiers')
2113
2114
2114 if precursor is not None:
2115 if precursor is not None:
2115 metadata = {}
2116 metadata = {}
2116 if 'date' in opts:
2117 if 'date' in opts:
2117 metadata['date'] = opts['date']
2118 metadata['date'] = opts['date']
2118 metadata['user'] = opts['user'] or ui.username()
2119 metadata['user'] = opts['user'] or ui.username()
2119 succs = tuple(parsenodeid(succ) for succ in successors)
2120 succs = tuple(parsenodeid(succ) for succ in successors)
2120 l = repo.lock()
2121 l = repo.lock()
2121 try:
2122 try:
2122 tr = repo.transaction('debugobsolete')
2123 tr = repo.transaction('debugobsolete')
2123 try:
2124 try:
2124 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2125 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2125 opts['flags'], metadata)
2126 opts['flags'], metadata)
2126 tr.close()
2127 tr.close()
2127 finally:
2128 finally:
2128 tr.release()
2129 tr.release()
2129 finally:
2130 finally:
2130 l.release()
2131 l.release()
2131 else:
2132 else:
2132 for m in obsolete.allmarkers(repo):
2133 for m in obsolete.allmarkers(repo):
2133 ui.write(hex(m.precnode()))
2134 ui.write(hex(m.precnode()))
2134 for repl in m.succnodes():
2135 for repl in m.succnodes():
2135 ui.write(' ')
2136 ui.write(' ')
2136 ui.write(hex(repl))
2137 ui.write(hex(repl))
2137 ui.write(' %X ' % m._data[2])
2138 ui.write(' %X ' % m._data[2])
2138 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2139 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2139 sorted(m.metadata().items()))))
2140 sorted(m.metadata().items()))))
2140 ui.write('\n')
2141 ui.write('\n')
2141
2142
2142 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2143 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2143 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2144 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2144 '''access the pushkey key/value protocol
2145 '''access the pushkey key/value protocol
2145
2146
2146 With two args, list the keys in the given namespace.
2147 With two args, list the keys in the given namespace.
2147
2148
2148 With five args, set a key to new if it currently is set to old.
2149 With five args, set a key to new if it currently is set to old.
2149 Reports success or failure.
2150 Reports success or failure.
2150 '''
2151 '''
2151
2152
2152 target = hg.peer(ui, {}, repopath)
2153 target = hg.peer(ui, {}, repopath)
2153 if keyinfo:
2154 if keyinfo:
2154 key, old, new = keyinfo
2155 key, old, new = keyinfo
2155 r = target.pushkey(namespace, key, old, new)
2156 r = target.pushkey(namespace, key, old, new)
2156 ui.status(str(r) + '\n')
2157 ui.status(str(r) + '\n')
2157 return not r
2158 return not r
2158 else:
2159 else:
2159 for k, v in sorted(target.listkeys(namespace).iteritems()):
2160 for k, v in sorted(target.listkeys(namespace).iteritems()):
2160 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2161 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2161 v.encode('string-escape')))
2162 v.encode('string-escape')))
2162
2163
2163 @command('debugpvec', [], _('A B'))
2164 @command('debugpvec', [], _('A B'))
2164 def debugpvec(ui, repo, a, b=None):
2165 def debugpvec(ui, repo, a, b=None):
2165 ca = scmutil.revsingle(repo, a)
2166 ca = scmutil.revsingle(repo, a)
2166 cb = scmutil.revsingle(repo, b)
2167 cb = scmutil.revsingle(repo, b)
2167 pa = pvec.ctxpvec(ca)
2168 pa = pvec.ctxpvec(ca)
2168 pb = pvec.ctxpvec(cb)
2169 pb = pvec.ctxpvec(cb)
2169 if pa == pb:
2170 if pa == pb:
2170 rel = "="
2171 rel = "="
2171 elif pa > pb:
2172 elif pa > pb:
2172 rel = ">"
2173 rel = ">"
2173 elif pa < pb:
2174 elif pa < pb:
2174 rel = "<"
2175 rel = "<"
2175 elif pa | pb:
2176 elif pa | pb:
2176 rel = "|"
2177 rel = "|"
2177 ui.write(_("a: %s\n") % pa)
2178 ui.write(_("a: %s\n") % pa)
2178 ui.write(_("b: %s\n") % pb)
2179 ui.write(_("b: %s\n") % pb)
2179 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2180 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2180 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2181 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2181 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2182 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2182 pa.distance(pb), rel))
2183 pa.distance(pb), rel))
2183
2184
2184 @command('debugrebuildstate',
2185 @command('debugrebuildstate',
2185 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2186 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2186 _('[-r REV] [REV]'))
2187 _('[-r REV] [REV]'))
2187 def debugrebuildstate(ui, repo, rev="tip"):
2188 def debugrebuildstate(ui, repo, rev="tip"):
2188 """rebuild the dirstate as it would look like for the given revision"""
2189 """rebuild the dirstate as it would look like for the given revision"""
2189 ctx = scmutil.revsingle(repo, rev)
2190 ctx = scmutil.revsingle(repo, rev)
2190 wlock = repo.wlock()
2191 wlock = repo.wlock()
2191 try:
2192 try:
2192 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2193 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2193 finally:
2194 finally:
2194 wlock.release()
2195 wlock.release()
2195
2196
2196 @command('debugrename',
2197 @command('debugrename',
2197 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2198 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2198 _('[-r REV] FILE'))
2199 _('[-r REV] FILE'))
2199 def debugrename(ui, repo, file1, *pats, **opts):
2200 def debugrename(ui, repo, file1, *pats, **opts):
2200 """dump rename information"""
2201 """dump rename information"""
2201
2202
2202 ctx = scmutil.revsingle(repo, opts.get('rev'))
2203 ctx = scmutil.revsingle(repo, opts.get('rev'))
2203 m = scmutil.match(ctx, (file1,) + pats, opts)
2204 m = scmutil.match(ctx, (file1,) + pats, opts)
2204 for abs in ctx.walk(m):
2205 for abs in ctx.walk(m):
2205 fctx = ctx[abs]
2206 fctx = ctx[abs]
2206 o = fctx.filelog().renamed(fctx.filenode())
2207 o = fctx.filelog().renamed(fctx.filenode())
2207 rel = m.rel(abs)
2208 rel = m.rel(abs)
2208 if o:
2209 if o:
2209 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2210 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2210 else:
2211 else:
2211 ui.write(_("%s not renamed\n") % rel)
2212 ui.write(_("%s not renamed\n") % rel)
2212
2213
2213 @command('debugrevlog',
2214 @command('debugrevlog',
2214 [('c', 'changelog', False, _('open changelog')),
2215 [('c', 'changelog', False, _('open changelog')),
2215 ('m', 'manifest', False, _('open manifest')),
2216 ('m', 'manifest', False, _('open manifest')),
2216 ('d', 'dump', False, _('dump index data'))],
2217 ('d', 'dump', False, _('dump index data'))],
2217 _('-c|-m|FILE'))
2218 _('-c|-m|FILE'))
2218 def debugrevlog(ui, repo, file_ = None, **opts):
2219 def debugrevlog(ui, repo, file_ = None, **opts):
2219 """show data and statistics about a revlog"""
2220 """show data and statistics about a revlog"""
2220 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2221 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2221
2222
2222 if opts.get("dump"):
2223 if opts.get("dump"):
2223 numrevs = len(r)
2224 numrevs = len(r)
2224 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2225 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2225 " rawsize totalsize compression heads\n")
2226 " rawsize totalsize compression heads\n")
2226 ts = 0
2227 ts = 0
2227 heads = set()
2228 heads = set()
2228 for rev in xrange(numrevs):
2229 for rev in xrange(numrevs):
2229 dbase = r.deltaparent(rev)
2230 dbase = r.deltaparent(rev)
2230 if dbase == -1:
2231 if dbase == -1:
2231 dbase = rev
2232 dbase = rev
2232 cbase = r.chainbase(rev)
2233 cbase = r.chainbase(rev)
2233 p1, p2 = r.parentrevs(rev)
2234 p1, p2 = r.parentrevs(rev)
2234 rs = r.rawsize(rev)
2235 rs = r.rawsize(rev)
2235 ts = ts + rs
2236 ts = ts + rs
2236 heads -= set(r.parentrevs(rev))
2237 heads -= set(r.parentrevs(rev))
2237 heads.add(rev)
2238 heads.add(rev)
2238 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2239 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2239 (rev, p1, p2, r.start(rev), r.end(rev),
2240 (rev, p1, p2, r.start(rev), r.end(rev),
2240 r.start(dbase), r.start(cbase),
2241 r.start(dbase), r.start(cbase),
2241 r.start(p1), r.start(p2),
2242 r.start(p1), r.start(p2),
2242 rs, ts, ts / r.end(rev), len(heads)))
2243 rs, ts, ts / r.end(rev), len(heads)))
2243 return 0
2244 return 0
2244
2245
2245 v = r.version
2246 v = r.version
2246 format = v & 0xFFFF
2247 format = v & 0xFFFF
2247 flags = []
2248 flags = []
2248 gdelta = False
2249 gdelta = False
2249 if v & revlog.REVLOGNGINLINEDATA:
2250 if v & revlog.REVLOGNGINLINEDATA:
2250 flags.append('inline')
2251 flags.append('inline')
2251 if v & revlog.REVLOGGENERALDELTA:
2252 if v & revlog.REVLOGGENERALDELTA:
2252 gdelta = True
2253 gdelta = True
2253 flags.append('generaldelta')
2254 flags.append('generaldelta')
2254 if not flags:
2255 if not flags:
2255 flags = ['(none)']
2256 flags = ['(none)']
2256
2257
2257 nummerges = 0
2258 nummerges = 0
2258 numfull = 0
2259 numfull = 0
2259 numprev = 0
2260 numprev = 0
2260 nump1 = 0
2261 nump1 = 0
2261 nump2 = 0
2262 nump2 = 0
2262 numother = 0
2263 numother = 0
2263 nump1prev = 0
2264 nump1prev = 0
2264 nump2prev = 0
2265 nump2prev = 0
2265 chainlengths = []
2266 chainlengths = []
2266
2267
2267 datasize = [None, 0, 0L]
2268 datasize = [None, 0, 0L]
2268 fullsize = [None, 0, 0L]
2269 fullsize = [None, 0, 0L]
2269 deltasize = [None, 0, 0L]
2270 deltasize = [None, 0, 0L]
2270
2271
2271 def addsize(size, l):
2272 def addsize(size, l):
2272 if l[0] is None or size < l[0]:
2273 if l[0] is None or size < l[0]:
2273 l[0] = size
2274 l[0] = size
2274 if size > l[1]:
2275 if size > l[1]:
2275 l[1] = size
2276 l[1] = size
2276 l[2] += size
2277 l[2] += size
2277
2278
2278 numrevs = len(r)
2279 numrevs = len(r)
2279 for rev in xrange(numrevs):
2280 for rev in xrange(numrevs):
2280 p1, p2 = r.parentrevs(rev)
2281 p1, p2 = r.parentrevs(rev)
2281 delta = r.deltaparent(rev)
2282 delta = r.deltaparent(rev)
2282 if format > 0:
2283 if format > 0:
2283 addsize(r.rawsize(rev), datasize)
2284 addsize(r.rawsize(rev), datasize)
2284 if p2 != nullrev:
2285 if p2 != nullrev:
2285 nummerges += 1
2286 nummerges += 1
2286 size = r.length(rev)
2287 size = r.length(rev)
2287 if delta == nullrev:
2288 if delta == nullrev:
2288 chainlengths.append(0)
2289 chainlengths.append(0)
2289 numfull += 1
2290 numfull += 1
2290 addsize(size, fullsize)
2291 addsize(size, fullsize)
2291 else:
2292 else:
2292 chainlengths.append(chainlengths[delta] + 1)
2293 chainlengths.append(chainlengths[delta] + 1)
2293 addsize(size, deltasize)
2294 addsize(size, deltasize)
2294 if delta == rev - 1:
2295 if delta == rev - 1:
2295 numprev += 1
2296 numprev += 1
2296 if delta == p1:
2297 if delta == p1:
2297 nump1prev += 1
2298 nump1prev += 1
2298 elif delta == p2:
2299 elif delta == p2:
2299 nump2prev += 1
2300 nump2prev += 1
2300 elif delta == p1:
2301 elif delta == p1:
2301 nump1 += 1
2302 nump1 += 1
2302 elif delta == p2:
2303 elif delta == p2:
2303 nump2 += 1
2304 nump2 += 1
2304 elif delta != nullrev:
2305 elif delta != nullrev:
2305 numother += 1
2306 numother += 1
2306
2307
2307 # Adjust size min value for empty cases
2308 # Adjust size min value for empty cases
2308 for size in (datasize, fullsize, deltasize):
2309 for size in (datasize, fullsize, deltasize):
2309 if size[0] is None:
2310 if size[0] is None:
2310 size[0] = 0
2311 size[0] = 0
2311
2312
2312 numdeltas = numrevs - numfull
2313 numdeltas = numrevs - numfull
2313 numoprev = numprev - nump1prev - nump2prev
2314 numoprev = numprev - nump1prev - nump2prev
2314 totalrawsize = datasize[2]
2315 totalrawsize = datasize[2]
2315 datasize[2] /= numrevs
2316 datasize[2] /= numrevs
2316 fulltotal = fullsize[2]
2317 fulltotal = fullsize[2]
2317 fullsize[2] /= numfull
2318 fullsize[2] /= numfull
2318 deltatotal = deltasize[2]
2319 deltatotal = deltasize[2]
2319 if numrevs - numfull > 0:
2320 if numrevs - numfull > 0:
2320 deltasize[2] /= numrevs - numfull
2321 deltasize[2] /= numrevs - numfull
2321 totalsize = fulltotal + deltatotal
2322 totalsize = fulltotal + deltatotal
2322 avgchainlen = sum(chainlengths) / numrevs
2323 avgchainlen = sum(chainlengths) / numrevs
2323 compratio = totalrawsize / totalsize
2324 compratio = totalrawsize / totalsize
2324
2325
2325 basedfmtstr = '%%%dd\n'
2326 basedfmtstr = '%%%dd\n'
2326 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2327 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2327
2328
2328 def dfmtstr(max):
2329 def dfmtstr(max):
2329 return basedfmtstr % len(str(max))
2330 return basedfmtstr % len(str(max))
2330 def pcfmtstr(max, padding=0):
2331 def pcfmtstr(max, padding=0):
2331 return basepcfmtstr % (len(str(max)), ' ' * padding)
2332 return basepcfmtstr % (len(str(max)), ' ' * padding)
2332
2333
2333 def pcfmt(value, total):
2334 def pcfmt(value, total):
2334 return (value, 100 * float(value) / total)
2335 return (value, 100 * float(value) / total)
2335
2336
2336 ui.write(('format : %d\n') % format)
2337 ui.write(('format : %d\n') % format)
2337 ui.write(('flags : %s\n') % ', '.join(flags))
2338 ui.write(('flags : %s\n') % ', '.join(flags))
2338
2339
2339 ui.write('\n')
2340 ui.write('\n')
2340 fmt = pcfmtstr(totalsize)
2341 fmt = pcfmtstr(totalsize)
2341 fmt2 = dfmtstr(totalsize)
2342 fmt2 = dfmtstr(totalsize)
2342 ui.write(('revisions : ') + fmt2 % numrevs)
2343 ui.write(('revisions : ') + fmt2 % numrevs)
2343 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2344 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2344 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2345 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2345 ui.write(('revisions : ') + fmt2 % numrevs)
2346 ui.write(('revisions : ') + fmt2 % numrevs)
2346 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2347 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2347 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2348 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2348 ui.write(('revision size : ') + fmt2 % totalsize)
2349 ui.write(('revision size : ') + fmt2 % totalsize)
2349 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2350 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2350 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2351 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2351
2352
2352 ui.write('\n')
2353 ui.write('\n')
2353 fmt = dfmtstr(max(avgchainlen, compratio))
2354 fmt = dfmtstr(max(avgchainlen, compratio))
2354 ui.write(('avg chain length : ') + fmt % avgchainlen)
2355 ui.write(('avg chain length : ') + fmt % avgchainlen)
2355 ui.write(('compression ratio : ') + fmt % compratio)
2356 ui.write(('compression ratio : ') + fmt % compratio)
2356
2357
2357 if format > 0:
2358 if format > 0:
2358 ui.write('\n')
2359 ui.write('\n')
2359 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2360 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2360 % tuple(datasize))
2361 % tuple(datasize))
2361 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2362 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2362 % tuple(fullsize))
2363 % tuple(fullsize))
2363 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2364 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2364 % tuple(deltasize))
2365 % tuple(deltasize))
2365
2366
2366 if numdeltas > 0:
2367 if numdeltas > 0:
2367 ui.write('\n')
2368 ui.write('\n')
2368 fmt = pcfmtstr(numdeltas)
2369 fmt = pcfmtstr(numdeltas)
2369 fmt2 = pcfmtstr(numdeltas, 4)
2370 fmt2 = pcfmtstr(numdeltas, 4)
2370 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2371 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2371 if numprev > 0:
2372 if numprev > 0:
2372 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2373 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2373 numprev))
2374 numprev))
2374 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2375 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2375 numprev))
2376 numprev))
2376 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2377 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2377 numprev))
2378 numprev))
2378 if gdelta:
2379 if gdelta:
2379 ui.write(('deltas against p1 : ')
2380 ui.write(('deltas against p1 : ')
2380 + fmt % pcfmt(nump1, numdeltas))
2381 + fmt % pcfmt(nump1, numdeltas))
2381 ui.write(('deltas against p2 : ')
2382 ui.write(('deltas against p2 : ')
2382 + fmt % pcfmt(nump2, numdeltas))
2383 + fmt % pcfmt(nump2, numdeltas))
2383 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2384 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2384 numdeltas))
2385 numdeltas))
2385
2386
2386 @command('debugrevspec', [], ('REVSPEC'))
2387 @command('debugrevspec', [], ('REVSPEC'))
2387 def debugrevspec(ui, repo, expr):
2388 def debugrevspec(ui, repo, expr):
2388 """parse and apply a revision specification
2389 """parse and apply a revision specification
2389
2390
2390 Use --verbose to print the parsed tree before and after aliases
2391 Use --verbose to print the parsed tree before and after aliases
2391 expansion.
2392 expansion.
2392 """
2393 """
2393 if ui.verbose:
2394 if ui.verbose:
2394 tree = revset.parse(expr)[0]
2395 tree = revset.parse(expr)[0]
2395 ui.note(revset.prettyformat(tree), "\n")
2396 ui.note(revset.prettyformat(tree), "\n")
2396 newtree = revset.findaliases(ui, tree)
2397 newtree = revset.findaliases(ui, tree)
2397 if newtree != tree:
2398 if newtree != tree:
2398 ui.note(revset.prettyformat(newtree), "\n")
2399 ui.note(revset.prettyformat(newtree), "\n")
2399 func = revset.match(ui, expr)
2400 func = revset.match(ui, expr)
2400 for c in func(repo, range(len(repo))):
2401 for c in func(repo, range(len(repo))):
2401 ui.write("%s\n" % c)
2402 ui.write("%s\n" % c)
2402
2403
2403 @command('debugsetparents', [], _('REV1 [REV2]'))
2404 @command('debugsetparents', [], _('REV1 [REV2]'))
2404 def debugsetparents(ui, repo, rev1, rev2=None):
2405 def debugsetparents(ui, repo, rev1, rev2=None):
2405 """manually set the parents of the current working directory
2406 """manually set the parents of the current working directory
2406
2407
2407 This is useful for writing repository conversion tools, but should
2408 This is useful for writing repository conversion tools, but should
2408 be used with care.
2409 be used with care.
2409
2410
2410 Returns 0 on success.
2411 Returns 0 on success.
2411 """
2412 """
2412
2413
2413 r1 = scmutil.revsingle(repo, rev1).node()
2414 r1 = scmutil.revsingle(repo, rev1).node()
2414 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2415 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2415
2416
2416 wlock = repo.wlock()
2417 wlock = repo.wlock()
2417 try:
2418 try:
2418 repo.setparents(r1, r2)
2419 repo.setparents(r1, r2)
2419 finally:
2420 finally:
2420 wlock.release()
2421 wlock.release()
2421
2422
2422 @command('debugstate',
2423 @command('debugstate',
2423 [('', 'nodates', None, _('do not display the saved mtime')),
2424 [('', 'nodates', None, _('do not display the saved mtime')),
2424 ('', 'datesort', None, _('sort by saved mtime'))],
2425 ('', 'datesort', None, _('sort by saved mtime'))],
2425 _('[OPTION]...'))
2426 _('[OPTION]...'))
2426 def debugstate(ui, repo, nodates=None, datesort=None):
2427 def debugstate(ui, repo, nodates=None, datesort=None):
2427 """show the contents of the current dirstate"""
2428 """show the contents of the current dirstate"""
2428 timestr = ""
2429 timestr = ""
2429 showdate = not nodates
2430 showdate = not nodates
2430 if datesort:
2431 if datesort:
2431 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2432 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2432 else:
2433 else:
2433 keyfunc = None # sort by filename
2434 keyfunc = None # sort by filename
2434 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2435 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2435 if showdate:
2436 if showdate:
2436 if ent[3] == -1:
2437 if ent[3] == -1:
2437 # Pad or slice to locale representation
2438 # Pad or slice to locale representation
2438 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2439 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2439 time.localtime(0)))
2440 time.localtime(0)))
2440 timestr = 'unset'
2441 timestr = 'unset'
2441 timestr = (timestr[:locale_len] +
2442 timestr = (timestr[:locale_len] +
2442 ' ' * (locale_len - len(timestr)))
2443 ' ' * (locale_len - len(timestr)))
2443 else:
2444 else:
2444 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2445 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2445 time.localtime(ent[3]))
2446 time.localtime(ent[3]))
2446 if ent[1] & 020000:
2447 if ent[1] & 020000:
2447 mode = 'lnk'
2448 mode = 'lnk'
2448 else:
2449 else:
2449 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2450 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2450 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2451 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2451 for f in repo.dirstate.copies():
2452 for f in repo.dirstate.copies():
2452 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2453 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2453
2454
2454 @command('debugsub',
2455 @command('debugsub',
2455 [('r', 'rev', '',
2456 [('r', 'rev', '',
2456 _('revision to check'), _('REV'))],
2457 _('revision to check'), _('REV'))],
2457 _('[-r REV] [REV]'))
2458 _('[-r REV] [REV]'))
2458 def debugsub(ui, repo, rev=None):
2459 def debugsub(ui, repo, rev=None):
2459 ctx = scmutil.revsingle(repo, rev, None)
2460 ctx = scmutil.revsingle(repo, rev, None)
2460 for k, v in sorted(ctx.substate.items()):
2461 for k, v in sorted(ctx.substate.items()):
2461 ui.write(('path %s\n') % k)
2462 ui.write(('path %s\n') % k)
2462 ui.write((' source %s\n') % v[0])
2463 ui.write((' source %s\n') % v[0])
2463 ui.write((' revision %s\n') % v[1])
2464 ui.write((' revision %s\n') % v[1])
2464
2465
2465 @command('debugsuccessorssets',
2466 @command('debugsuccessorssets',
2466 [],
2467 [],
2467 _('[REV]'))
2468 _('[REV]'))
2468 def debugsuccessorssets(ui, repo, *revs):
2469 def debugsuccessorssets(ui, repo, *revs):
2469 """show set of successors for revision
2470 """show set of successors for revision
2470
2471
2471 A successors set of changeset A is a consistent group of revisions that
2472 A successors set of changeset A is a consistent group of revisions that
2472 succeed A. It contains non-obsolete changesets only.
2473 succeed A. It contains non-obsolete changesets only.
2473
2474
2474 In most cases a changeset A has a single successors set containing a single
2475 In most cases a changeset A has a single successors set containing a single
2475 successors (changeset A replaced by A').
2476 successors (changeset A replaced by A').
2476
2477
2477 A changeset that is made obsolete with no successors are called "pruned".
2478 A changeset that is made obsolete with no successors are called "pruned".
2478 Such changesets have no successors sets at all.
2479 Such changesets have no successors sets at all.
2479
2480
2480 A changeset that has been "split" will have a successors set containing
2481 A changeset that has been "split" will have a successors set containing
2481 more than one successors.
2482 more than one successors.
2482
2483
2483 A changeset that has been rewritten in multiple different ways is called
2484 A changeset that has been rewritten in multiple different ways is called
2484 "divergent". Such changesets have multiple successor sets (each of which
2485 "divergent". Such changesets have multiple successor sets (each of which
2485 may also be split, i.e. have multiple successors).
2486 may also be split, i.e. have multiple successors).
2486
2487
2487 Results are displayed as follows::
2488 Results are displayed as follows::
2488
2489
2489 <rev1>
2490 <rev1>
2490 <successors-1A>
2491 <successors-1A>
2491 <rev2>
2492 <rev2>
2492 <successors-2A>
2493 <successors-2A>
2493 <successors-2B1> <successors-2B2> <successors-2B3>
2494 <successors-2B1> <successors-2B2> <successors-2B3>
2494
2495
2495 Here rev2 has two possible (i.e. divergent) successors sets. The first
2496 Here rev2 has two possible (i.e. divergent) successors sets. The first
2496 holds one element, whereas the second holds three (i.e. the changeset has
2497 holds one element, whereas the second holds three (i.e. the changeset has
2497 been split).
2498 been split).
2498 """
2499 """
2499 # passed to successorssets caching computation from one call to another
2500 # passed to successorssets caching computation from one call to another
2500 cache = {}
2501 cache = {}
2501 ctx2str = str
2502 ctx2str = str
2502 node2str = short
2503 node2str = short
2503 if ui.debug():
2504 if ui.debug():
2504 def ctx2str(ctx):
2505 def ctx2str(ctx):
2505 return ctx.hex()
2506 return ctx.hex()
2506 node2str = hex
2507 node2str = hex
2507 for rev in scmutil.revrange(repo, revs):
2508 for rev in scmutil.revrange(repo, revs):
2508 ctx = repo[rev]
2509 ctx = repo[rev]
2509 ui.write('%s\n'% ctx2str(ctx))
2510 ui.write('%s\n'% ctx2str(ctx))
2510 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2511 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2511 if succsset:
2512 if succsset:
2512 ui.write(' ')
2513 ui.write(' ')
2513 ui.write(node2str(succsset[0]))
2514 ui.write(node2str(succsset[0]))
2514 for node in succsset[1:]:
2515 for node in succsset[1:]:
2515 ui.write(' ')
2516 ui.write(' ')
2516 ui.write(node2str(node))
2517 ui.write(node2str(node))
2517 ui.write('\n')
2518 ui.write('\n')
2518
2519
2519 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2520 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2520 def debugwalk(ui, repo, *pats, **opts):
2521 def debugwalk(ui, repo, *pats, **opts):
2521 """show how files match on given patterns"""
2522 """show how files match on given patterns"""
2522 m = scmutil.match(repo[None], pats, opts)
2523 m = scmutil.match(repo[None], pats, opts)
2523 items = list(repo.walk(m))
2524 items = list(repo.walk(m))
2524 if not items:
2525 if not items:
2525 return
2526 return
2526 f = lambda fn: fn
2527 f = lambda fn: fn
2527 if ui.configbool('ui', 'slash') and os.sep != '/':
2528 if ui.configbool('ui', 'slash') and os.sep != '/':
2528 f = lambda fn: util.normpath(fn)
2529 f = lambda fn: util.normpath(fn)
2529 fmt = 'f %%-%ds %%-%ds %%s' % (
2530 fmt = 'f %%-%ds %%-%ds %%s' % (
2530 max([len(abs) for abs in items]),
2531 max([len(abs) for abs in items]),
2531 max([len(m.rel(abs)) for abs in items]))
2532 max([len(m.rel(abs)) for abs in items]))
2532 for abs in items:
2533 for abs in items:
2533 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2534 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2534 ui.write("%s\n" % line.rstrip())
2535 ui.write("%s\n" % line.rstrip())
2535
2536
2536 @command('debugwireargs',
2537 @command('debugwireargs',
2537 [('', 'three', '', 'three'),
2538 [('', 'three', '', 'three'),
2538 ('', 'four', '', 'four'),
2539 ('', 'four', '', 'four'),
2539 ('', 'five', '', 'five'),
2540 ('', 'five', '', 'five'),
2540 ] + remoteopts,
2541 ] + remoteopts,
2541 _('REPO [OPTIONS]... [ONE [TWO]]'))
2542 _('REPO [OPTIONS]... [ONE [TWO]]'))
2542 def debugwireargs(ui, repopath, *vals, **opts):
2543 def debugwireargs(ui, repopath, *vals, **opts):
2543 repo = hg.peer(ui, opts, repopath)
2544 repo = hg.peer(ui, opts, repopath)
2544 for opt in remoteopts:
2545 for opt in remoteopts:
2545 del opts[opt[1]]
2546 del opts[opt[1]]
2546 args = {}
2547 args = {}
2547 for k, v in opts.iteritems():
2548 for k, v in opts.iteritems():
2548 if v:
2549 if v:
2549 args[k] = v
2550 args[k] = v
2550 # run twice to check that we don't mess up the stream for the next command
2551 # run twice to check that we don't mess up the stream for the next command
2551 res1 = repo.debugwireargs(*vals, **args)
2552 res1 = repo.debugwireargs(*vals, **args)
2552 res2 = repo.debugwireargs(*vals, **args)
2553 res2 = repo.debugwireargs(*vals, **args)
2553 ui.write("%s\n" % res1)
2554 ui.write("%s\n" % res1)
2554 if res1 != res2:
2555 if res1 != res2:
2555 ui.warn("%s\n" % res2)
2556 ui.warn("%s\n" % res2)
2556
2557
2557 @command('^diff',
2558 @command('^diff',
2558 [('r', 'rev', [], _('revision'), _('REV')),
2559 [('r', 'rev', [], _('revision'), _('REV')),
2559 ('c', 'change', '', _('change made by revision'), _('REV'))
2560 ('c', 'change', '', _('change made by revision'), _('REV'))
2560 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2561 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2561 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2562 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2562 def diff(ui, repo, *pats, **opts):
2563 def diff(ui, repo, *pats, **opts):
2563 """diff repository (or selected files)
2564 """diff repository (or selected files)
2564
2565
2565 Show differences between revisions for the specified files.
2566 Show differences between revisions for the specified files.
2566
2567
2567 Differences between files are shown using the unified diff format.
2568 Differences between files are shown using the unified diff format.
2568
2569
2569 .. note::
2570 .. note::
2570 diff may generate unexpected results for merges, as it will
2571 diff may generate unexpected results for merges, as it will
2571 default to comparing against the working directory's first
2572 default to comparing against the working directory's first
2572 parent changeset if no revisions are specified.
2573 parent changeset if no revisions are specified.
2573
2574
2574 When two revision arguments are given, then changes are shown
2575 When two revision arguments are given, then changes are shown
2575 between those revisions. If only one revision is specified then
2576 between those revisions. If only one revision is specified then
2576 that revision is compared to the working directory, and, when no
2577 that revision is compared to the working directory, and, when no
2577 revisions are specified, the working directory files are compared
2578 revisions are specified, the working directory files are compared
2578 to its parent.
2579 to its parent.
2579
2580
2580 Alternatively you can specify -c/--change with a revision to see
2581 Alternatively you can specify -c/--change with a revision to see
2581 the changes in that changeset relative to its first parent.
2582 the changes in that changeset relative to its first parent.
2582
2583
2583 Without the -a/--text option, diff will avoid generating diffs of
2584 Without the -a/--text option, diff will avoid generating diffs of
2584 files it detects as binary. With -a, diff will generate a diff
2585 files it detects as binary. With -a, diff will generate a diff
2585 anyway, probably with undesirable results.
2586 anyway, probably with undesirable results.
2586
2587
2587 Use the -g/--git option to generate diffs in the git extended diff
2588 Use the -g/--git option to generate diffs in the git extended diff
2588 format. For more information, read :hg:`help diffs`.
2589 format. For more information, read :hg:`help diffs`.
2589
2590
2590 .. container:: verbose
2591 .. container:: verbose
2591
2592
2592 Examples:
2593 Examples:
2593
2594
2594 - compare a file in the current working directory to its parent::
2595 - compare a file in the current working directory to its parent::
2595
2596
2596 hg diff foo.c
2597 hg diff foo.c
2597
2598
2598 - compare two historical versions of a directory, with rename info::
2599 - compare two historical versions of a directory, with rename info::
2599
2600
2600 hg diff --git -r 1.0:1.2 lib/
2601 hg diff --git -r 1.0:1.2 lib/
2601
2602
2602 - get change stats relative to the last change on some date::
2603 - get change stats relative to the last change on some date::
2603
2604
2604 hg diff --stat -r "date('may 2')"
2605 hg diff --stat -r "date('may 2')"
2605
2606
2606 - diff all newly-added files that contain a keyword::
2607 - diff all newly-added files that contain a keyword::
2607
2608
2608 hg diff "set:added() and grep(GNU)"
2609 hg diff "set:added() and grep(GNU)"
2609
2610
2610 - compare a revision and its parents::
2611 - compare a revision and its parents::
2611
2612
2612 hg diff -c 9353 # compare against first parent
2613 hg diff -c 9353 # compare against first parent
2613 hg diff -r 9353^:9353 # same using revset syntax
2614 hg diff -r 9353^:9353 # same using revset syntax
2614 hg diff -r 9353^2:9353 # compare against the second parent
2615 hg diff -r 9353^2:9353 # compare against the second parent
2615
2616
2616 Returns 0 on success.
2617 Returns 0 on success.
2617 """
2618 """
2618
2619
2619 revs = opts.get('rev')
2620 revs = opts.get('rev')
2620 change = opts.get('change')
2621 change = opts.get('change')
2621 stat = opts.get('stat')
2622 stat = opts.get('stat')
2622 reverse = opts.get('reverse')
2623 reverse = opts.get('reverse')
2623
2624
2624 if revs and change:
2625 if revs and change:
2625 msg = _('cannot specify --rev and --change at the same time')
2626 msg = _('cannot specify --rev and --change at the same time')
2626 raise util.Abort(msg)
2627 raise util.Abort(msg)
2627 elif change:
2628 elif change:
2628 node2 = scmutil.revsingle(repo, change, None).node()
2629 node2 = scmutil.revsingle(repo, change, None).node()
2629 node1 = repo[node2].p1().node()
2630 node1 = repo[node2].p1().node()
2630 else:
2631 else:
2631 node1, node2 = scmutil.revpair(repo, revs)
2632 node1, node2 = scmutil.revpair(repo, revs)
2632
2633
2633 if reverse:
2634 if reverse:
2634 node1, node2 = node2, node1
2635 node1, node2 = node2, node1
2635
2636
2636 diffopts = patch.diffopts(ui, opts)
2637 diffopts = patch.diffopts(ui, opts)
2637 m = scmutil.match(repo[node2], pats, opts)
2638 m = scmutil.match(repo[node2], pats, opts)
2638 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2639 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2639 listsubrepos=opts.get('subrepos'))
2640 listsubrepos=opts.get('subrepos'))
2640
2641
2641 @command('^export',
2642 @command('^export',
2642 [('o', 'output', '',
2643 [('o', 'output', '',
2643 _('print output to file with formatted name'), _('FORMAT')),
2644 _('print output to file with formatted name'), _('FORMAT')),
2644 ('', 'switch-parent', None, _('diff against the second parent')),
2645 ('', 'switch-parent', None, _('diff against the second parent')),
2645 ('r', 'rev', [], _('revisions to export'), _('REV')),
2646 ('r', 'rev', [], _('revisions to export'), _('REV')),
2646 ] + diffopts,
2647 ] + diffopts,
2647 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2648 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2648 def export(ui, repo, *changesets, **opts):
2649 def export(ui, repo, *changesets, **opts):
2649 """dump the header and diffs for one or more changesets
2650 """dump the header and diffs for one or more changesets
2650
2651
2651 Print the changeset header and diffs for one or more revisions.
2652 Print the changeset header and diffs for one or more revisions.
2652
2653
2653 The information shown in the changeset header is: author, date,
2654 The information shown in the changeset header is: author, date,
2654 branch name (if non-default), changeset hash, parent(s) and commit
2655 branch name (if non-default), changeset hash, parent(s) and commit
2655 comment.
2656 comment.
2656
2657
2657 .. note::
2658 .. note::
2658 export may generate unexpected diff output for merge
2659 export may generate unexpected diff output for merge
2659 changesets, as it will compare the merge changeset against its
2660 changesets, as it will compare the merge changeset against its
2660 first parent only.
2661 first parent only.
2661
2662
2662 Output may be to a file, in which case the name of the file is
2663 Output may be to a file, in which case the name of the file is
2663 given using a format string. The formatting rules are as follows:
2664 given using a format string. The formatting rules are as follows:
2664
2665
2665 :``%%``: literal "%" character
2666 :``%%``: literal "%" character
2666 :``%H``: changeset hash (40 hexadecimal digits)
2667 :``%H``: changeset hash (40 hexadecimal digits)
2667 :``%N``: number of patches being generated
2668 :``%N``: number of patches being generated
2668 :``%R``: changeset revision number
2669 :``%R``: changeset revision number
2669 :``%b``: basename of the exporting repository
2670 :``%b``: basename of the exporting repository
2670 :``%h``: short-form changeset hash (12 hexadecimal digits)
2671 :``%h``: short-form changeset hash (12 hexadecimal digits)
2671 :``%m``: first line of the commit message (only alphanumeric characters)
2672 :``%m``: first line of the commit message (only alphanumeric characters)
2672 :``%n``: zero-padded sequence number, starting at 1
2673 :``%n``: zero-padded sequence number, starting at 1
2673 :``%r``: zero-padded changeset revision number
2674 :``%r``: zero-padded changeset revision number
2674
2675
2675 Without the -a/--text option, export will avoid generating diffs
2676 Without the -a/--text option, export will avoid generating diffs
2676 of files it detects as binary. With -a, export will generate a
2677 of files it detects as binary. With -a, export will generate a
2677 diff anyway, probably with undesirable results.
2678 diff anyway, probably with undesirable results.
2678
2679
2679 Use the -g/--git option to generate diffs in the git extended diff
2680 Use the -g/--git option to generate diffs in the git extended diff
2680 format. See :hg:`help diffs` for more information.
2681 format. See :hg:`help diffs` for more information.
2681
2682
2682 With the --switch-parent option, the diff will be against the
2683 With the --switch-parent option, the diff will be against the
2683 second parent. It can be useful to review a merge.
2684 second parent. It can be useful to review a merge.
2684
2685
2685 .. container:: verbose
2686 .. container:: verbose
2686
2687
2687 Examples:
2688 Examples:
2688
2689
2689 - use export and import to transplant a bugfix to the current
2690 - use export and import to transplant a bugfix to the current
2690 branch::
2691 branch::
2691
2692
2692 hg export -r 9353 | hg import -
2693 hg export -r 9353 | hg import -
2693
2694
2694 - export all the changesets between two revisions to a file with
2695 - export all the changesets between two revisions to a file with
2695 rename information::
2696 rename information::
2696
2697
2697 hg export --git -r 123:150 > changes.txt
2698 hg export --git -r 123:150 > changes.txt
2698
2699
2699 - split outgoing changes into a series of patches with
2700 - split outgoing changes into a series of patches with
2700 descriptive names::
2701 descriptive names::
2701
2702
2702 hg export -r "outgoing()" -o "%n-%m.patch"
2703 hg export -r "outgoing()" -o "%n-%m.patch"
2703
2704
2704 Returns 0 on success.
2705 Returns 0 on success.
2705 """
2706 """
2706 changesets += tuple(opts.get('rev', []))
2707 changesets += tuple(opts.get('rev', []))
2707 revs = scmutil.revrange(repo, changesets)
2708 revs = scmutil.revrange(repo, changesets)
2708 if not revs:
2709 if not revs:
2709 raise util.Abort(_("export requires at least one changeset"))
2710 raise util.Abort(_("export requires at least one changeset"))
2710 if len(revs) > 1:
2711 if len(revs) > 1:
2711 ui.note(_('exporting patches:\n'))
2712 ui.note(_('exporting patches:\n'))
2712 else:
2713 else:
2713 ui.note(_('exporting patch:\n'))
2714 ui.note(_('exporting patch:\n'))
2714 cmdutil.export(repo, revs, template=opts.get('output'),
2715 cmdutil.export(repo, revs, template=opts.get('output'),
2715 switch_parent=opts.get('switch_parent'),
2716 switch_parent=opts.get('switch_parent'),
2716 opts=patch.diffopts(ui, opts))
2717 opts=patch.diffopts(ui, opts))
2717
2718
2718 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2719 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2719 def forget(ui, repo, *pats, **opts):
2720 def forget(ui, repo, *pats, **opts):
2720 """forget the specified files on the next commit
2721 """forget the specified files on the next commit
2721
2722
2722 Mark the specified files so they will no longer be tracked
2723 Mark the specified files so they will no longer be tracked
2723 after the next commit.
2724 after the next commit.
2724
2725
2725 This only removes files from the current branch, not from the
2726 This only removes files from the current branch, not from the
2726 entire project history, and it does not delete them from the
2727 entire project history, and it does not delete them from the
2727 working directory.
2728 working directory.
2728
2729
2729 To undo a forget before the next commit, see :hg:`add`.
2730 To undo a forget before the next commit, see :hg:`add`.
2730
2731
2731 .. container:: verbose
2732 .. container:: verbose
2732
2733
2733 Examples:
2734 Examples:
2734
2735
2735 - forget newly-added binary files::
2736 - forget newly-added binary files::
2736
2737
2737 hg forget "set:added() and binary()"
2738 hg forget "set:added() and binary()"
2738
2739
2739 - forget files that would be excluded by .hgignore::
2740 - forget files that would be excluded by .hgignore::
2740
2741
2741 hg forget "set:hgignore()"
2742 hg forget "set:hgignore()"
2742
2743
2743 Returns 0 on success.
2744 Returns 0 on success.
2744 """
2745 """
2745
2746
2746 if not pats:
2747 if not pats:
2747 raise util.Abort(_('no files specified'))
2748 raise util.Abort(_('no files specified'))
2748
2749
2749 m = scmutil.match(repo[None], pats, opts)
2750 m = scmutil.match(repo[None], pats, opts)
2750 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2751 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2751 return rejected and 1 or 0
2752 return rejected and 1 or 0
2752
2753
2753 @command(
2754 @command(
2754 'graft',
2755 'graft',
2755 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2756 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2756 ('c', 'continue', False, _('resume interrupted graft')),
2757 ('c', 'continue', False, _('resume interrupted graft')),
2757 ('e', 'edit', False, _('invoke editor on commit messages')),
2758 ('e', 'edit', False, _('invoke editor on commit messages')),
2758 ('', 'log', None, _('append graft info to log message')),
2759 ('', 'log', None, _('append graft info to log message')),
2759 ('D', 'currentdate', False,
2760 ('D', 'currentdate', False,
2760 _('record the current date as commit date')),
2761 _('record the current date as commit date')),
2761 ('U', 'currentuser', False,
2762 ('U', 'currentuser', False,
2762 _('record the current user as committer'), _('DATE'))]
2763 _('record the current user as committer'), _('DATE'))]
2763 + commitopts2 + mergetoolopts + dryrunopts,
2764 + commitopts2 + mergetoolopts + dryrunopts,
2764 _('[OPTION]... [-r] REV...'))
2765 _('[OPTION]... [-r] REV...'))
2765 def graft(ui, repo, *revs, **opts):
2766 def graft(ui, repo, *revs, **opts):
2766 '''copy changes from other branches onto the current branch
2767 '''copy changes from other branches onto the current branch
2767
2768
2768 This command uses Mercurial's merge logic to copy individual
2769 This command uses Mercurial's merge logic to copy individual
2769 changes from other branches without merging branches in the
2770 changes from other branches without merging branches in the
2770 history graph. This is sometimes known as 'backporting' or
2771 history graph. This is sometimes known as 'backporting' or
2771 'cherry-picking'. By default, graft will copy user, date, and
2772 'cherry-picking'. By default, graft will copy user, date, and
2772 description from the source changesets.
2773 description from the source changesets.
2773
2774
2774 Changesets that are ancestors of the current revision, that have
2775 Changesets that are ancestors of the current revision, that have
2775 already been grafted, or that are merges will be skipped.
2776 already been grafted, or that are merges will be skipped.
2776
2777
2777 If --log is specified, log messages will have a comment appended
2778 If --log is specified, log messages will have a comment appended
2778 of the form::
2779 of the form::
2779
2780
2780 (grafted from CHANGESETHASH)
2781 (grafted from CHANGESETHASH)
2781
2782
2782 If a graft merge results in conflicts, the graft process is
2783 If a graft merge results in conflicts, the graft process is
2783 interrupted so that the current merge can be manually resolved.
2784 interrupted so that the current merge can be manually resolved.
2784 Once all conflicts are addressed, the graft process can be
2785 Once all conflicts are addressed, the graft process can be
2785 continued with the -c/--continue option.
2786 continued with the -c/--continue option.
2786
2787
2787 .. note::
2788 .. note::
2788 The -c/--continue option does not reapply earlier options.
2789 The -c/--continue option does not reapply earlier options.
2789
2790
2790 .. container:: verbose
2791 .. container:: verbose
2791
2792
2792 Examples:
2793 Examples:
2793
2794
2794 - copy a single change to the stable branch and edit its description::
2795 - copy a single change to the stable branch and edit its description::
2795
2796
2796 hg update stable
2797 hg update stable
2797 hg graft --edit 9393
2798 hg graft --edit 9393
2798
2799
2799 - graft a range of changesets with one exception, updating dates::
2800 - graft a range of changesets with one exception, updating dates::
2800
2801
2801 hg graft -D "2085::2093 and not 2091"
2802 hg graft -D "2085::2093 and not 2091"
2802
2803
2803 - continue a graft after resolving conflicts::
2804 - continue a graft after resolving conflicts::
2804
2805
2805 hg graft -c
2806 hg graft -c
2806
2807
2807 - show the source of a grafted changeset::
2808 - show the source of a grafted changeset::
2808
2809
2809 hg log --debug -r tip
2810 hg log --debug -r tip
2810
2811
2811 Returns 0 on successful completion.
2812 Returns 0 on successful completion.
2812 '''
2813 '''
2813
2814
2814 revs = list(revs)
2815 revs = list(revs)
2815 revs.extend(opts['rev'])
2816 revs.extend(opts['rev'])
2816
2817
2817 if not opts.get('user') and opts.get('currentuser'):
2818 if not opts.get('user') and opts.get('currentuser'):
2818 opts['user'] = ui.username()
2819 opts['user'] = ui.username()
2819 if not opts.get('date') and opts.get('currentdate'):
2820 if not opts.get('date') and opts.get('currentdate'):
2820 opts['date'] = "%d %d" % util.makedate()
2821 opts['date'] = "%d %d" % util.makedate()
2821
2822
2822 editor = None
2823 editor = None
2823 if opts.get('edit'):
2824 if opts.get('edit'):
2824 editor = cmdutil.commitforceeditor
2825 editor = cmdutil.commitforceeditor
2825
2826
2826 cont = False
2827 cont = False
2827 if opts['continue']:
2828 if opts['continue']:
2828 cont = True
2829 cont = True
2829 if revs:
2830 if revs:
2830 raise util.Abort(_("can't specify --continue and revisions"))
2831 raise util.Abort(_("can't specify --continue and revisions"))
2831 # read in unfinished revisions
2832 # read in unfinished revisions
2832 try:
2833 try:
2833 nodes = repo.opener.read('graftstate').splitlines()
2834 nodes = repo.opener.read('graftstate').splitlines()
2834 revs = [repo[node].rev() for node in nodes]
2835 revs = [repo[node].rev() for node in nodes]
2835 except IOError, inst:
2836 except IOError, inst:
2836 if inst.errno != errno.ENOENT:
2837 if inst.errno != errno.ENOENT:
2837 raise
2838 raise
2838 raise util.Abort(_("no graft state found, can't continue"))
2839 raise util.Abort(_("no graft state found, can't continue"))
2839 else:
2840 else:
2840 cmdutil.bailifchanged(repo)
2841 cmdutil.bailifchanged(repo)
2841 if not revs:
2842 if not revs:
2842 raise util.Abort(_('no revisions specified'))
2843 raise util.Abort(_('no revisions specified'))
2843 revs = scmutil.revrange(repo, revs)
2844 revs = scmutil.revrange(repo, revs)
2844
2845
2845 # check for merges
2846 # check for merges
2846 for rev in repo.revs('%ld and merge()', revs):
2847 for rev in repo.revs('%ld and merge()', revs):
2847 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2848 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2848 revs.remove(rev)
2849 revs.remove(rev)
2849 if not revs:
2850 if not revs:
2850 return -1
2851 return -1
2851
2852
2852 # check for ancestors of dest branch
2853 # check for ancestors of dest branch
2853 for rev in repo.revs('::. and %ld', revs):
2854 for rev in repo.revs('::. and %ld', revs):
2854 ui.warn(_('skipping ancestor revision %s\n') % rev)
2855 ui.warn(_('skipping ancestor revision %s\n') % rev)
2855 revs.remove(rev)
2856 revs.remove(rev)
2856 if not revs:
2857 if not revs:
2857 return -1
2858 return -1
2858
2859
2859 # analyze revs for earlier grafts
2860 # analyze revs for earlier grafts
2860 ids = {}
2861 ids = {}
2861 for ctx in repo.set("%ld", revs):
2862 for ctx in repo.set("%ld", revs):
2862 ids[ctx.hex()] = ctx.rev()
2863 ids[ctx.hex()] = ctx.rev()
2863 n = ctx.extra().get('source')
2864 n = ctx.extra().get('source')
2864 if n:
2865 if n:
2865 ids[n] = ctx.rev()
2866 ids[n] = ctx.rev()
2866
2867
2867 # check ancestors for earlier grafts
2868 # check ancestors for earlier grafts
2868 ui.debug('scanning for duplicate grafts\n')
2869 ui.debug('scanning for duplicate grafts\n')
2869 for ctx in repo.set("::. - ::%ld", revs):
2870 for ctx in repo.set("::. - ::%ld", revs):
2870 n = ctx.extra().get('source')
2871 n = ctx.extra().get('source')
2871 if n in ids:
2872 if n in ids:
2872 r = repo[n].rev()
2873 r = repo[n].rev()
2873 if r in revs:
2874 if r in revs:
2874 ui.warn(_('skipping already grafted revision %s\n') % r)
2875 ui.warn(_('skipping already grafted revision %s\n') % r)
2875 revs.remove(r)
2876 revs.remove(r)
2876 elif ids[n] in revs:
2877 elif ids[n] in revs:
2877 ui.warn(_('skipping already grafted revision %s '
2878 ui.warn(_('skipping already grafted revision %s '
2878 '(same origin %d)\n') % (ids[n], r))
2879 '(same origin %d)\n') % (ids[n], r))
2879 revs.remove(ids[n])
2880 revs.remove(ids[n])
2880 elif ctx.hex() in ids:
2881 elif ctx.hex() in ids:
2881 r = ids[ctx.hex()]
2882 r = ids[ctx.hex()]
2882 ui.warn(_('skipping already grafted revision %s '
2883 ui.warn(_('skipping already grafted revision %s '
2883 '(was grafted from %d)\n') % (r, ctx.rev()))
2884 '(was grafted from %d)\n') % (r, ctx.rev()))
2884 revs.remove(r)
2885 revs.remove(r)
2885 if not revs:
2886 if not revs:
2886 return -1
2887 return -1
2887
2888
2888 wlock = repo.wlock()
2889 wlock = repo.wlock()
2889 try:
2890 try:
2890 current = repo['.']
2891 current = repo['.']
2891 for pos, ctx in enumerate(repo.set("%ld", revs)):
2892 for pos, ctx in enumerate(repo.set("%ld", revs)):
2892
2893
2893 ui.status(_('grafting revision %s\n') % ctx.rev())
2894 ui.status(_('grafting revision %s\n') % ctx.rev())
2894 if opts.get('dry_run'):
2895 if opts.get('dry_run'):
2895 continue
2896 continue
2896
2897
2897 source = ctx.extra().get('source')
2898 source = ctx.extra().get('source')
2898 if not source:
2899 if not source:
2899 source = ctx.hex()
2900 source = ctx.hex()
2900 extra = {'source': source}
2901 extra = {'source': source}
2901 user = ctx.user()
2902 user = ctx.user()
2902 if opts.get('user'):
2903 if opts.get('user'):
2903 user = opts['user']
2904 user = opts['user']
2904 date = ctx.date()
2905 date = ctx.date()
2905 if opts.get('date'):
2906 if opts.get('date'):
2906 date = opts['date']
2907 date = opts['date']
2907 message = ctx.description()
2908 message = ctx.description()
2908 if opts.get('log'):
2909 if opts.get('log'):
2909 message += '\n(grafted from %s)' % ctx.hex()
2910 message += '\n(grafted from %s)' % ctx.hex()
2910
2911
2911 # we don't merge the first commit when continuing
2912 # we don't merge the first commit when continuing
2912 if not cont:
2913 if not cont:
2913 # perform the graft merge with p1(rev) as 'ancestor'
2914 # perform the graft merge with p1(rev) as 'ancestor'
2914 try:
2915 try:
2915 # ui.forcemerge is an internal variable, do not document
2916 # ui.forcemerge is an internal variable, do not document
2916 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2917 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2917 stats = mergemod.update(repo, ctx.node(), True, True, False,
2918 stats = mergemod.update(repo, ctx.node(), True, True, False,
2918 ctx.p1().node())
2919 ctx.p1().node())
2919 finally:
2920 finally:
2920 repo.ui.setconfig('ui', 'forcemerge', '')
2921 repo.ui.setconfig('ui', 'forcemerge', '')
2921 # report any conflicts
2922 # report any conflicts
2922 if stats and stats[3] > 0:
2923 if stats and stats[3] > 0:
2923 # write out state for --continue
2924 # write out state for --continue
2924 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2925 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2925 repo.opener.write('graftstate', ''.join(nodelines))
2926 repo.opener.write('graftstate', ''.join(nodelines))
2926 raise util.Abort(
2927 raise util.Abort(
2927 _("unresolved conflicts, can't continue"),
2928 _("unresolved conflicts, can't continue"),
2928 hint=_('use hg resolve and hg graft --continue'))
2929 hint=_('use hg resolve and hg graft --continue'))
2929 else:
2930 else:
2930 cont = False
2931 cont = False
2931
2932
2932 # drop the second merge parent
2933 # drop the second merge parent
2933 repo.setparents(current.node(), nullid)
2934 repo.setparents(current.node(), nullid)
2934 repo.dirstate.write()
2935 repo.dirstate.write()
2935 # fix up dirstate for copies and renames
2936 # fix up dirstate for copies and renames
2936 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2937 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2937
2938
2938 # commit
2939 # commit
2939 node = repo.commit(text=message, user=user,
2940 node = repo.commit(text=message, user=user,
2940 date=date, extra=extra, editor=editor)
2941 date=date, extra=extra, editor=editor)
2941 if node is None:
2942 if node is None:
2942 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2943 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2943 else:
2944 else:
2944 current = repo[node]
2945 current = repo[node]
2945 finally:
2946 finally:
2946 wlock.release()
2947 wlock.release()
2947
2948
2948 # remove state when we complete successfully
2949 # remove state when we complete successfully
2949 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2950 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2950 util.unlinkpath(repo.join('graftstate'))
2951 util.unlinkpath(repo.join('graftstate'))
2951
2952
2952 return 0
2953 return 0
2953
2954
2954 @command('grep',
2955 @command('grep',
2955 [('0', 'print0', None, _('end fields with NUL')),
2956 [('0', 'print0', None, _('end fields with NUL')),
2956 ('', 'all', None, _('print all revisions that match')),
2957 ('', 'all', None, _('print all revisions that match')),
2957 ('a', 'text', None, _('treat all files as text')),
2958 ('a', 'text', None, _('treat all files as text')),
2958 ('f', 'follow', None,
2959 ('f', 'follow', None,
2959 _('follow changeset history,'
2960 _('follow changeset history,'
2960 ' or file history across copies and renames')),
2961 ' or file history across copies and renames')),
2961 ('i', 'ignore-case', None, _('ignore case when matching')),
2962 ('i', 'ignore-case', None, _('ignore case when matching')),
2962 ('l', 'files-with-matches', None,
2963 ('l', 'files-with-matches', None,
2963 _('print only filenames and revisions that match')),
2964 _('print only filenames and revisions that match')),
2964 ('n', 'line-number', None, _('print matching line numbers')),
2965 ('n', 'line-number', None, _('print matching line numbers')),
2965 ('r', 'rev', [],
2966 ('r', 'rev', [],
2966 _('only search files changed within revision range'), _('REV')),
2967 _('only search files changed within revision range'), _('REV')),
2967 ('u', 'user', None, _('list the author (long with -v)')),
2968 ('u', 'user', None, _('list the author (long with -v)')),
2968 ('d', 'date', None, _('list the date (short with -q)')),
2969 ('d', 'date', None, _('list the date (short with -q)')),
2969 ] + walkopts,
2970 ] + walkopts,
2970 _('[OPTION]... PATTERN [FILE]...'))
2971 _('[OPTION]... PATTERN [FILE]...'))
2971 def grep(ui, repo, pattern, *pats, **opts):
2972 def grep(ui, repo, pattern, *pats, **opts):
2972 """search for a pattern in specified files and revisions
2973 """search for a pattern in specified files and revisions
2973
2974
2974 Search revisions of files for a regular expression.
2975 Search revisions of files for a regular expression.
2975
2976
2976 This command behaves differently than Unix grep. It only accepts
2977 This command behaves differently than Unix grep. It only accepts
2977 Python/Perl regexps. It searches repository history, not the
2978 Python/Perl regexps. It searches repository history, not the
2978 working directory. It always prints the revision number in which a
2979 working directory. It always prints the revision number in which a
2979 match appears.
2980 match appears.
2980
2981
2981 By default, grep only prints output for the first revision of a
2982 By default, grep only prints output for the first revision of a
2982 file in which it finds a match. To get it to print every revision
2983 file in which it finds a match. To get it to print every revision
2983 that contains a change in match status ("-" for a match that
2984 that contains a change in match status ("-" for a match that
2984 becomes a non-match, or "+" for a non-match that becomes a match),
2985 becomes a non-match, or "+" for a non-match that becomes a match),
2985 use the --all flag.
2986 use the --all flag.
2986
2987
2987 Returns 0 if a match is found, 1 otherwise.
2988 Returns 0 if a match is found, 1 otherwise.
2988 """
2989 """
2989 reflags = re.M
2990 reflags = re.M
2990 if opts.get('ignore_case'):
2991 if opts.get('ignore_case'):
2991 reflags |= re.I
2992 reflags |= re.I
2992 try:
2993 try:
2993 regexp = re.compile(pattern, reflags)
2994 regexp = re.compile(pattern, reflags)
2994 except re.error, inst:
2995 except re.error, inst:
2995 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2996 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2996 return 1
2997 return 1
2997 sep, eol = ':', '\n'
2998 sep, eol = ':', '\n'
2998 if opts.get('print0'):
2999 if opts.get('print0'):
2999 sep = eol = '\0'
3000 sep = eol = '\0'
3000
3001
3001 getfile = util.lrucachefunc(repo.file)
3002 getfile = util.lrucachefunc(repo.file)
3002
3003
3003 def matchlines(body):
3004 def matchlines(body):
3004 begin = 0
3005 begin = 0
3005 linenum = 0
3006 linenum = 0
3006 while begin < len(body):
3007 while begin < len(body):
3007 match = regexp.search(body, begin)
3008 match = regexp.search(body, begin)
3008 if not match:
3009 if not match:
3009 break
3010 break
3010 mstart, mend = match.span()
3011 mstart, mend = match.span()
3011 linenum += body.count('\n', begin, mstart) + 1
3012 linenum += body.count('\n', begin, mstart) + 1
3012 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3013 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3013 begin = body.find('\n', mend) + 1 or len(body) + 1
3014 begin = body.find('\n', mend) + 1 or len(body) + 1
3014 lend = begin - 1
3015 lend = begin - 1
3015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3016 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3016
3017
3017 class linestate(object):
3018 class linestate(object):
3018 def __init__(self, line, linenum, colstart, colend):
3019 def __init__(self, line, linenum, colstart, colend):
3019 self.line = line
3020 self.line = line
3020 self.linenum = linenum
3021 self.linenum = linenum
3021 self.colstart = colstart
3022 self.colstart = colstart
3022 self.colend = colend
3023 self.colend = colend
3023
3024
3024 def __hash__(self):
3025 def __hash__(self):
3025 return hash((self.linenum, self.line))
3026 return hash((self.linenum, self.line))
3026
3027
3027 def __eq__(self, other):
3028 def __eq__(self, other):
3028 return self.line == other.line
3029 return self.line == other.line
3029
3030
3030 matches = {}
3031 matches = {}
3031 copies = {}
3032 copies = {}
3032 def grepbody(fn, rev, body):
3033 def grepbody(fn, rev, body):
3033 matches[rev].setdefault(fn, [])
3034 matches[rev].setdefault(fn, [])
3034 m = matches[rev][fn]
3035 m = matches[rev][fn]
3035 for lnum, cstart, cend, line in matchlines(body):
3036 for lnum, cstart, cend, line in matchlines(body):
3036 s = linestate(line, lnum, cstart, cend)
3037 s = linestate(line, lnum, cstart, cend)
3037 m.append(s)
3038 m.append(s)
3038
3039
3039 def difflinestates(a, b):
3040 def difflinestates(a, b):
3040 sm = difflib.SequenceMatcher(None, a, b)
3041 sm = difflib.SequenceMatcher(None, a, b)
3041 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3042 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3042 if tag == 'insert':
3043 if tag == 'insert':
3043 for i in xrange(blo, bhi):
3044 for i in xrange(blo, bhi):
3044 yield ('+', b[i])
3045 yield ('+', b[i])
3045 elif tag == 'delete':
3046 elif tag == 'delete':
3046 for i in xrange(alo, ahi):
3047 for i in xrange(alo, ahi):
3047 yield ('-', a[i])
3048 yield ('-', a[i])
3048 elif tag == 'replace':
3049 elif tag == 'replace':
3049 for i in xrange(alo, ahi):
3050 for i in xrange(alo, ahi):
3050 yield ('-', a[i])
3051 yield ('-', a[i])
3051 for i in xrange(blo, bhi):
3052 for i in xrange(blo, bhi):
3052 yield ('+', b[i])
3053 yield ('+', b[i])
3053
3054
3054 def display(fn, ctx, pstates, states):
3055 def display(fn, ctx, pstates, states):
3055 rev = ctx.rev()
3056 rev = ctx.rev()
3056 datefunc = ui.quiet and util.shortdate or util.datestr
3057 datefunc = ui.quiet and util.shortdate or util.datestr
3057 found = False
3058 found = False
3058 filerevmatches = {}
3059 filerevmatches = {}
3059 def binary():
3060 def binary():
3060 flog = getfile(fn)
3061 flog = getfile(fn)
3061 return util.binary(flog.read(ctx.filenode(fn)))
3062 return util.binary(flog.read(ctx.filenode(fn)))
3062
3063
3063 if opts.get('all'):
3064 if opts.get('all'):
3064 iter = difflinestates(pstates, states)
3065 iter = difflinestates(pstates, states)
3065 else:
3066 else:
3066 iter = [('', l) for l in states]
3067 iter = [('', l) for l in states]
3067 for change, l in iter:
3068 for change, l in iter:
3068 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3069 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3069 before, match, after = None, None, None
3070 before, match, after = None, None, None
3070
3071
3071 if opts.get('line_number'):
3072 if opts.get('line_number'):
3072 cols.append((str(l.linenum), 'grep.linenumber'))
3073 cols.append((str(l.linenum), 'grep.linenumber'))
3073 if opts.get('all'):
3074 if opts.get('all'):
3074 cols.append((change, 'grep.change'))
3075 cols.append((change, 'grep.change'))
3075 if opts.get('user'):
3076 if opts.get('user'):
3076 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3077 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3077 if opts.get('date'):
3078 if opts.get('date'):
3078 cols.append((datefunc(ctx.date()), 'grep.date'))
3079 cols.append((datefunc(ctx.date()), 'grep.date'))
3079 if opts.get('files_with_matches'):
3080 if opts.get('files_with_matches'):
3080 c = (fn, rev)
3081 c = (fn, rev)
3081 if c in filerevmatches:
3082 if c in filerevmatches:
3082 continue
3083 continue
3083 filerevmatches[c] = 1
3084 filerevmatches[c] = 1
3084 else:
3085 else:
3085 before = l.line[:l.colstart]
3086 before = l.line[:l.colstart]
3086 match = l.line[l.colstart:l.colend]
3087 match = l.line[l.colstart:l.colend]
3087 after = l.line[l.colend:]
3088 after = l.line[l.colend:]
3088 for col, label in cols[:-1]:
3089 for col, label in cols[:-1]:
3089 ui.write(col, label=label)
3090 ui.write(col, label=label)
3090 ui.write(sep, label='grep.sep')
3091 ui.write(sep, label='grep.sep')
3091 ui.write(cols[-1][0], label=cols[-1][1])
3092 ui.write(cols[-1][0], label=cols[-1][1])
3092 if before is not None:
3093 if before is not None:
3093 ui.write(sep, label='grep.sep')
3094 ui.write(sep, label='grep.sep')
3094 if not opts.get('text') and binary():
3095 if not opts.get('text') and binary():
3095 ui.write(" Binary file matches")
3096 ui.write(" Binary file matches")
3096 else:
3097 else:
3097 ui.write(before)
3098 ui.write(before)
3098 ui.write(match, label='grep.match')
3099 ui.write(match, label='grep.match')
3099 ui.write(after)
3100 ui.write(after)
3100 ui.write(eol)
3101 ui.write(eol)
3101 found = True
3102 found = True
3102 return found
3103 return found
3103
3104
3104 skip = {}
3105 skip = {}
3105 revfiles = {}
3106 revfiles = {}
3106 matchfn = scmutil.match(repo[None], pats, opts)
3107 matchfn = scmutil.match(repo[None], pats, opts)
3107 found = False
3108 found = False
3108 follow = opts.get('follow')
3109 follow = opts.get('follow')
3109
3110
3110 def prep(ctx, fns):
3111 def prep(ctx, fns):
3111 rev = ctx.rev()
3112 rev = ctx.rev()
3112 pctx = ctx.p1()
3113 pctx = ctx.p1()
3113 parent = pctx.rev()
3114 parent = pctx.rev()
3114 matches.setdefault(rev, {})
3115 matches.setdefault(rev, {})
3115 matches.setdefault(parent, {})
3116 matches.setdefault(parent, {})
3116 files = revfiles.setdefault(rev, [])
3117 files = revfiles.setdefault(rev, [])
3117 for fn in fns:
3118 for fn in fns:
3118 flog = getfile(fn)
3119 flog = getfile(fn)
3119 try:
3120 try:
3120 fnode = ctx.filenode(fn)
3121 fnode = ctx.filenode(fn)
3121 except error.LookupError:
3122 except error.LookupError:
3122 continue
3123 continue
3123
3124
3124 copied = flog.renamed(fnode)
3125 copied = flog.renamed(fnode)
3125 copy = follow and copied and copied[0]
3126 copy = follow and copied and copied[0]
3126 if copy:
3127 if copy:
3127 copies.setdefault(rev, {})[fn] = copy
3128 copies.setdefault(rev, {})[fn] = copy
3128 if fn in skip:
3129 if fn in skip:
3129 if copy:
3130 if copy:
3130 skip[copy] = True
3131 skip[copy] = True
3131 continue
3132 continue
3132 files.append(fn)
3133 files.append(fn)
3133
3134
3134 if fn not in matches[rev]:
3135 if fn not in matches[rev]:
3135 grepbody(fn, rev, flog.read(fnode))
3136 grepbody(fn, rev, flog.read(fnode))
3136
3137
3137 pfn = copy or fn
3138 pfn = copy or fn
3138 if pfn not in matches[parent]:
3139 if pfn not in matches[parent]:
3139 try:
3140 try:
3140 fnode = pctx.filenode(pfn)
3141 fnode = pctx.filenode(pfn)
3141 grepbody(pfn, parent, flog.read(fnode))
3142 grepbody(pfn, parent, flog.read(fnode))
3142 except error.LookupError:
3143 except error.LookupError:
3143 pass
3144 pass
3144
3145
3145 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3146 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3146 rev = ctx.rev()
3147 rev = ctx.rev()
3147 parent = ctx.p1().rev()
3148 parent = ctx.p1().rev()
3148 for fn in sorted(revfiles.get(rev, [])):
3149 for fn in sorted(revfiles.get(rev, [])):
3149 states = matches[rev][fn]
3150 states = matches[rev][fn]
3150 copy = copies.get(rev, {}).get(fn)
3151 copy = copies.get(rev, {}).get(fn)
3151 if fn in skip:
3152 if fn in skip:
3152 if copy:
3153 if copy:
3153 skip[copy] = True
3154 skip[copy] = True
3154 continue
3155 continue
3155 pstates = matches.get(parent, {}).get(copy or fn, [])
3156 pstates = matches.get(parent, {}).get(copy or fn, [])
3156 if pstates or states:
3157 if pstates or states:
3157 r = display(fn, ctx, pstates, states)
3158 r = display(fn, ctx, pstates, states)
3158 found = found or r
3159 found = found or r
3159 if r and not opts.get('all'):
3160 if r and not opts.get('all'):
3160 skip[fn] = True
3161 skip[fn] = True
3161 if copy:
3162 if copy:
3162 skip[copy] = True
3163 skip[copy] = True
3163 del matches[rev]
3164 del matches[rev]
3164 del revfiles[rev]
3165 del revfiles[rev]
3165
3166
3166 return not found
3167 return not found
3167
3168
3168 @command('heads',
3169 @command('heads',
3169 [('r', 'rev', '',
3170 [('r', 'rev', '',
3170 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3171 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3171 ('t', 'topo', False, _('show topological heads only')),
3172 ('t', 'topo', False, _('show topological heads only')),
3172 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3173 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3173 ('c', 'closed', False, _('show normal and closed branch heads')),
3174 ('c', 'closed', False, _('show normal and closed branch heads')),
3174 ] + templateopts,
3175 ] + templateopts,
3175 _('[-ct] [-r STARTREV] [REV]...'))
3176 _('[-ct] [-r STARTREV] [REV]...'))
3176 def heads(ui, repo, *branchrevs, **opts):
3177 def heads(ui, repo, *branchrevs, **opts):
3177 """show current repository heads or show branch heads
3178 """show current repository heads or show branch heads
3178
3179
3179 With no arguments, show all repository branch heads.
3180 With no arguments, show all repository branch heads.
3180
3181
3181 Repository "heads" are changesets with no child changesets. They are
3182 Repository "heads" are changesets with no child changesets. They are
3182 where development generally takes place and are the usual targets
3183 where development generally takes place and are the usual targets
3183 for update and merge operations. Branch heads are changesets that have
3184 for update and merge operations. Branch heads are changesets that have
3184 no child changeset on the same branch.
3185 no child changeset on the same branch.
3185
3186
3186 If one or more REVs are given, only branch heads on the branches
3187 If one or more REVs are given, only branch heads on the branches
3187 associated with the specified changesets are shown. This means
3188 associated with the specified changesets are shown. This means
3188 that you can use :hg:`heads foo` to see the heads on a branch
3189 that you can use :hg:`heads foo` to see the heads on a branch
3189 named ``foo``.
3190 named ``foo``.
3190
3191
3191 If -c/--closed is specified, also show branch heads marked closed
3192 If -c/--closed is specified, also show branch heads marked closed
3192 (see :hg:`commit --close-branch`).
3193 (see :hg:`commit --close-branch`).
3193
3194
3194 If STARTREV is specified, only those heads that are descendants of
3195 If STARTREV is specified, only those heads that are descendants of
3195 STARTREV will be displayed.
3196 STARTREV will be displayed.
3196
3197
3197 If -t/--topo is specified, named branch mechanics will be ignored and only
3198 If -t/--topo is specified, named branch mechanics will be ignored and only
3198 changesets without children will be shown.
3199 changesets without children will be shown.
3199
3200
3200 Returns 0 if matching heads are found, 1 if not.
3201 Returns 0 if matching heads are found, 1 if not.
3201 """
3202 """
3202
3203
3203 start = None
3204 start = None
3204 if 'rev' in opts:
3205 if 'rev' in opts:
3205 start = scmutil.revsingle(repo, opts['rev'], None).node()
3206 start = scmutil.revsingle(repo, opts['rev'], None).node()
3206
3207
3207 if opts.get('topo'):
3208 if opts.get('topo'):
3208 heads = [repo[h] for h in repo.heads(start)]
3209 heads = [repo[h] for h in repo.heads(start)]
3209 else:
3210 else:
3210 heads = []
3211 heads = []
3211 for branch in repo.branchmap():
3212 for branch in repo.branchmap():
3212 heads += repo.branchheads(branch, start, opts.get('closed'))
3213 heads += repo.branchheads(branch, start, opts.get('closed'))
3213 heads = [repo[h] for h in heads]
3214 heads = [repo[h] for h in heads]
3214
3215
3215 if branchrevs:
3216 if branchrevs:
3216 branches = set(repo[br].branch() for br in branchrevs)
3217 branches = set(repo[br].branch() for br in branchrevs)
3217 heads = [h for h in heads if h.branch() in branches]
3218 heads = [h for h in heads if h.branch() in branches]
3218
3219
3219 if opts.get('active') and branchrevs:
3220 if opts.get('active') and branchrevs:
3220 dagheads = repo.heads(start)
3221 dagheads = repo.heads(start)
3221 heads = [h for h in heads if h.node() in dagheads]
3222 heads = [h for h in heads if h.node() in dagheads]
3222
3223
3223 if branchrevs:
3224 if branchrevs:
3224 haveheads = set(h.branch() for h in heads)
3225 haveheads = set(h.branch() for h in heads)
3225 if branches - haveheads:
3226 if branches - haveheads:
3226 headless = ', '.join(b for b in branches - haveheads)
3227 headless = ', '.join(b for b in branches - haveheads)
3227 msg = _('no open branch heads found on branches %s')
3228 msg = _('no open branch heads found on branches %s')
3228 if opts.get('rev'):
3229 if opts.get('rev'):
3229 msg += _(' (started at %s)') % opts['rev']
3230 msg += _(' (started at %s)') % opts['rev']
3230 ui.warn((msg + '\n') % headless)
3231 ui.warn((msg + '\n') % headless)
3231
3232
3232 if not heads:
3233 if not heads:
3233 return 1
3234 return 1
3234
3235
3235 heads = sorted(heads, key=lambda x: -x.rev())
3236 heads = sorted(heads, key=lambda x: -x.rev())
3236 displayer = cmdutil.show_changeset(ui, repo, opts)
3237 displayer = cmdutil.show_changeset(ui, repo, opts)
3237 for ctx in heads:
3238 for ctx in heads:
3238 displayer.show(ctx)
3239 displayer.show(ctx)
3239 displayer.close()
3240 displayer.close()
3240
3241
3241 @command('help',
3242 @command('help',
3242 [('e', 'extension', None, _('show only help for extensions')),
3243 [('e', 'extension', None, _('show only help for extensions')),
3243 ('c', 'command', None, _('show only help for commands')),
3244 ('c', 'command', None, _('show only help for commands')),
3244 ('k', 'keyword', '', _('show topics matching keyword')),
3245 ('k', 'keyword', '', _('show topics matching keyword')),
3245 ],
3246 ],
3246 _('[-ec] [TOPIC]'))
3247 _('[-ec] [TOPIC]'))
3247 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3248 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3248 """show help for a given topic or a help overview
3249 """show help for a given topic or a help overview
3249
3250
3250 With no arguments, print a list of commands with short help messages.
3251 With no arguments, print a list of commands with short help messages.
3251
3252
3252 Given a topic, extension, or command name, print help for that
3253 Given a topic, extension, or command name, print help for that
3253 topic.
3254 topic.
3254
3255
3255 Returns 0 if successful.
3256 Returns 0 if successful.
3256 """
3257 """
3257
3258
3258 textwidth = min(ui.termwidth(), 80) - 2
3259 textwidth = min(ui.termwidth(), 80) - 2
3259
3260
3260 def helpcmd(name):
3261 def helpcmd(name):
3261 try:
3262 try:
3262 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3263 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3263 except error.AmbiguousCommand, inst:
3264 except error.AmbiguousCommand, inst:
3264 # py3k fix: except vars can't be used outside the scope of the
3265 # py3k fix: except vars can't be used outside the scope of the
3265 # except block, nor can be used inside a lambda. python issue4617
3266 # except block, nor can be used inside a lambda. python issue4617
3266 prefix = inst.args[0]
3267 prefix = inst.args[0]
3267 select = lambda c: c.lstrip('^').startswith(prefix)
3268 select = lambda c: c.lstrip('^').startswith(prefix)
3268 rst = helplist(select)
3269 rst = helplist(select)
3269 return rst
3270 return rst
3270
3271
3271 rst = []
3272 rst = []
3272
3273
3273 # check if it's an invalid alias and display its error if it is
3274 # check if it's an invalid alias and display its error if it is
3274 if getattr(entry[0], 'badalias', False):
3275 if getattr(entry[0], 'badalias', False):
3275 if not unknowncmd:
3276 if not unknowncmd:
3276 ui.pushbuffer()
3277 ui.pushbuffer()
3277 entry[0](ui)
3278 entry[0](ui)
3278 rst.append(ui.popbuffer())
3279 rst.append(ui.popbuffer())
3279 return rst
3280 return rst
3280
3281
3281 # synopsis
3282 # synopsis
3282 if len(entry) > 2:
3283 if len(entry) > 2:
3283 if entry[2].startswith('hg'):
3284 if entry[2].startswith('hg'):
3284 rst.append("%s\n" % entry[2])
3285 rst.append("%s\n" % entry[2])
3285 else:
3286 else:
3286 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3287 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3287 else:
3288 else:
3288 rst.append('hg %s\n' % aliases[0])
3289 rst.append('hg %s\n' % aliases[0])
3289 # aliases
3290 # aliases
3290 if full and not ui.quiet and len(aliases) > 1:
3291 if full and not ui.quiet and len(aliases) > 1:
3291 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3292 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3292 rst.append('\n')
3293 rst.append('\n')
3293
3294
3294 # description
3295 # description
3295 doc = gettext(entry[0].__doc__)
3296 doc = gettext(entry[0].__doc__)
3296 if not doc:
3297 if not doc:
3297 doc = _("(no help text available)")
3298 doc = _("(no help text available)")
3298 if util.safehasattr(entry[0], 'definition'): # aliased command
3299 if util.safehasattr(entry[0], 'definition'): # aliased command
3299 if entry[0].definition.startswith('!'): # shell alias
3300 if entry[0].definition.startswith('!'): # shell alias
3300 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3301 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3301 else:
3302 else:
3302 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3303 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3303 doc = doc.splitlines(True)
3304 doc = doc.splitlines(True)
3304 if ui.quiet or not full:
3305 if ui.quiet or not full:
3305 rst.append(doc[0])
3306 rst.append(doc[0])
3306 else:
3307 else:
3307 rst.extend(doc)
3308 rst.extend(doc)
3308 rst.append('\n')
3309 rst.append('\n')
3309
3310
3310 # check if this command shadows a non-trivial (multi-line)
3311 # check if this command shadows a non-trivial (multi-line)
3311 # extension help text
3312 # extension help text
3312 try:
3313 try:
3313 mod = extensions.find(name)
3314 mod = extensions.find(name)
3314 doc = gettext(mod.__doc__) or ''
3315 doc = gettext(mod.__doc__) or ''
3315 if '\n' in doc.strip():
3316 if '\n' in doc.strip():
3316 msg = _('use "hg help -e %s" to show help for '
3317 msg = _('use "hg help -e %s" to show help for '
3317 'the %s extension') % (name, name)
3318 'the %s extension') % (name, name)
3318 rst.append('\n%s\n' % msg)
3319 rst.append('\n%s\n' % msg)
3319 except KeyError:
3320 except KeyError:
3320 pass
3321 pass
3321
3322
3322 # options
3323 # options
3323 if not ui.quiet and entry[1]:
3324 if not ui.quiet and entry[1]:
3324 rst.append('\n%s\n\n' % _("options:"))
3325 rst.append('\n%s\n\n' % _("options:"))
3325 rst.append(help.optrst(entry[1], ui.verbose))
3326 rst.append(help.optrst(entry[1], ui.verbose))
3326
3327
3327 if ui.verbose:
3328 if ui.verbose:
3328 rst.append('\n%s\n\n' % _("global options:"))
3329 rst.append('\n%s\n\n' % _("global options:"))
3329 rst.append(help.optrst(globalopts, ui.verbose))
3330 rst.append(help.optrst(globalopts, ui.verbose))
3330
3331
3331 if not ui.verbose:
3332 if not ui.verbose:
3332 if not full:
3333 if not full:
3333 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3334 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3334 % name)
3335 % name)
3335 elif not ui.quiet:
3336 elif not ui.quiet:
3336 omitted = _('use "hg -v help %s" to show more complete'
3337 omitted = _('use "hg -v help %s" to show more complete'
3337 ' help and the global options') % name
3338 ' help and the global options') % name
3338 notomitted = _('use "hg -v help %s" to show'
3339 notomitted = _('use "hg -v help %s" to show'
3339 ' the global options') % name
3340 ' the global options') % name
3340 help.indicateomitted(rst, omitted, notomitted)
3341 help.indicateomitted(rst, omitted, notomitted)
3341
3342
3342 return rst
3343 return rst
3343
3344
3344
3345
3345 def helplist(select=None):
3346 def helplist(select=None):
3346 # list of commands
3347 # list of commands
3347 if name == "shortlist":
3348 if name == "shortlist":
3348 header = _('basic commands:\n\n')
3349 header = _('basic commands:\n\n')
3349 else:
3350 else:
3350 header = _('list of commands:\n\n')
3351 header = _('list of commands:\n\n')
3351
3352
3352 h = {}
3353 h = {}
3353 cmds = {}
3354 cmds = {}
3354 for c, e in table.iteritems():
3355 for c, e in table.iteritems():
3355 f = c.split("|", 1)[0]
3356 f = c.split("|", 1)[0]
3356 if select and not select(f):
3357 if select and not select(f):
3357 continue
3358 continue
3358 if (not select and name != 'shortlist' and
3359 if (not select and name != 'shortlist' and
3359 e[0].__module__ != __name__):
3360 e[0].__module__ != __name__):
3360 continue
3361 continue
3361 if name == "shortlist" and not f.startswith("^"):
3362 if name == "shortlist" and not f.startswith("^"):
3362 continue
3363 continue
3363 f = f.lstrip("^")
3364 f = f.lstrip("^")
3364 if not ui.debugflag and f.startswith("debug"):
3365 if not ui.debugflag and f.startswith("debug"):
3365 continue
3366 continue
3366 doc = e[0].__doc__
3367 doc = e[0].__doc__
3367 if doc and 'DEPRECATED' in doc and not ui.verbose:
3368 if doc and 'DEPRECATED' in doc and not ui.verbose:
3368 continue
3369 continue
3369 doc = gettext(doc)
3370 doc = gettext(doc)
3370 if not doc:
3371 if not doc:
3371 doc = _("(no help text available)")
3372 doc = _("(no help text available)")
3372 h[f] = doc.splitlines()[0].rstrip()
3373 h[f] = doc.splitlines()[0].rstrip()
3373 cmds[f] = c.lstrip("^")
3374 cmds[f] = c.lstrip("^")
3374
3375
3375 rst = []
3376 rst = []
3376 if not h:
3377 if not h:
3377 if not ui.quiet:
3378 if not ui.quiet:
3378 rst.append(_('no commands defined\n'))
3379 rst.append(_('no commands defined\n'))
3379 return rst
3380 return rst
3380
3381
3381 if not ui.quiet:
3382 if not ui.quiet:
3382 rst.append(header)
3383 rst.append(header)
3383 fns = sorted(h)
3384 fns = sorted(h)
3384 for f in fns:
3385 for f in fns:
3385 if ui.verbose:
3386 if ui.verbose:
3386 commands = cmds[f].replace("|",", ")
3387 commands = cmds[f].replace("|",", ")
3387 rst.append(" :%s: %s\n" % (commands, h[f]))
3388 rst.append(" :%s: %s\n" % (commands, h[f]))
3388 else:
3389 else:
3389 rst.append(' :%s: %s\n' % (f, h[f]))
3390 rst.append(' :%s: %s\n' % (f, h[f]))
3390
3391
3391 if not name:
3392 if not name:
3392 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3393 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3393 if exts:
3394 if exts:
3394 rst.append('\n')
3395 rst.append('\n')
3395 rst.extend(exts)
3396 rst.extend(exts)
3396
3397
3397 rst.append(_("\nadditional help topics:\n\n"))
3398 rst.append(_("\nadditional help topics:\n\n"))
3398 topics = []
3399 topics = []
3399 for names, header, doc in help.helptable:
3400 for names, header, doc in help.helptable:
3400 topics.append((names[0], header))
3401 topics.append((names[0], header))
3401 for t, desc in topics:
3402 for t, desc in topics:
3402 rst.append(" :%s: %s\n" % (t, desc))
3403 rst.append(" :%s: %s\n" % (t, desc))
3403
3404
3404 optlist = []
3405 optlist = []
3405 if not ui.quiet:
3406 if not ui.quiet:
3406 if ui.verbose:
3407 if ui.verbose:
3407 optlist.append((_("global options:"), globalopts))
3408 optlist.append((_("global options:"), globalopts))
3408 if name == 'shortlist':
3409 if name == 'shortlist':
3409 optlist.append((_('use "hg help" for the full list '
3410 optlist.append((_('use "hg help" for the full list '
3410 'of commands'), ()))
3411 'of commands'), ()))
3411 else:
3412 else:
3412 if name == 'shortlist':
3413 if name == 'shortlist':
3413 msg = _('use "hg help" for the full list of commands '
3414 msg = _('use "hg help" for the full list of commands '
3414 'or "hg -v" for details')
3415 'or "hg -v" for details')
3415 elif name and not full:
3416 elif name and not full:
3416 msg = _('use "hg help %s" to show the full help '
3417 msg = _('use "hg help %s" to show the full help '
3417 'text') % name
3418 'text') % name
3418 else:
3419 else:
3419 msg = _('use "hg -v help%s" to show builtin aliases and '
3420 msg = _('use "hg -v help%s" to show builtin aliases and '
3420 'global options') % (name and " " + name or "")
3421 'global options') % (name and " " + name or "")
3421 optlist.append((msg, ()))
3422 optlist.append((msg, ()))
3422
3423
3423 if optlist:
3424 if optlist:
3424 for title, options in optlist:
3425 for title, options in optlist:
3425 rst.append('\n%s\n' % title)
3426 rst.append('\n%s\n' % title)
3426 if options:
3427 if options:
3427 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3428 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3428 return rst
3429 return rst
3429
3430
3430 def helptopic(name):
3431 def helptopic(name):
3431 for names, header, doc in help.helptable:
3432 for names, header, doc in help.helptable:
3432 if name in names:
3433 if name in names:
3433 break
3434 break
3434 else:
3435 else:
3435 raise error.UnknownCommand(name)
3436 raise error.UnknownCommand(name)
3436
3437
3437 rst = ["%s\n\n" % header]
3438 rst = ["%s\n\n" % header]
3438 # description
3439 # description
3439 if not doc:
3440 if not doc:
3440 rst.append(" %s\n" % _("(no help text available)"))
3441 rst.append(" %s\n" % _("(no help text available)"))
3441 if util.safehasattr(doc, '__call__'):
3442 if util.safehasattr(doc, '__call__'):
3442 rst += [" %s\n" % l for l in doc().splitlines()]
3443 rst += [" %s\n" % l for l in doc().splitlines()]
3443
3444
3444 if not ui.verbose:
3445 if not ui.verbose:
3445 omitted = (_('use "hg help -v %s" to show more complete help') %
3446 omitted = (_('use "hg help -v %s" to show more complete help') %
3446 name)
3447 name)
3447 help.indicateomitted(rst, omitted)
3448 help.indicateomitted(rst, omitted)
3448
3449
3449 try:
3450 try:
3450 cmdutil.findcmd(name, table)
3451 cmdutil.findcmd(name, table)
3451 rst.append(_('\nuse "hg help -c %s" to see help for '
3452 rst.append(_('\nuse "hg help -c %s" to see help for '
3452 'the %s command\n') % (name, name))
3453 'the %s command\n') % (name, name))
3453 except error.UnknownCommand:
3454 except error.UnknownCommand:
3454 pass
3455 pass
3455 return rst
3456 return rst
3456
3457
3457 def helpext(name):
3458 def helpext(name):
3458 try:
3459 try:
3459 mod = extensions.find(name)
3460 mod = extensions.find(name)
3460 doc = gettext(mod.__doc__) or _('no help text available')
3461 doc = gettext(mod.__doc__) or _('no help text available')
3461 except KeyError:
3462 except KeyError:
3462 mod = None
3463 mod = None
3463 doc = extensions.disabledext(name)
3464 doc = extensions.disabledext(name)
3464 if not doc:
3465 if not doc:
3465 raise error.UnknownCommand(name)
3466 raise error.UnknownCommand(name)
3466
3467
3467 if '\n' not in doc:
3468 if '\n' not in doc:
3468 head, tail = doc, ""
3469 head, tail = doc, ""
3469 else:
3470 else:
3470 head, tail = doc.split('\n', 1)
3471 head, tail = doc.split('\n', 1)
3471 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3472 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3472 if tail:
3473 if tail:
3473 rst.extend(tail.splitlines(True))
3474 rst.extend(tail.splitlines(True))
3474 rst.append('\n')
3475 rst.append('\n')
3475
3476
3476 if not ui.verbose:
3477 if not ui.verbose:
3477 omitted = (_('use "hg help -v %s" to show more complete help') %
3478 omitted = (_('use "hg help -v %s" to show more complete help') %
3478 name)
3479 name)
3479 help.indicateomitted(rst, omitted)
3480 help.indicateomitted(rst, omitted)
3480
3481
3481 if mod:
3482 if mod:
3482 try:
3483 try:
3483 ct = mod.cmdtable
3484 ct = mod.cmdtable
3484 except AttributeError:
3485 except AttributeError:
3485 ct = {}
3486 ct = {}
3486 modcmds = set([c.split('|', 1)[0] for c in ct])
3487 modcmds = set([c.split('|', 1)[0] for c in ct])
3487 rst.extend(helplist(modcmds.__contains__))
3488 rst.extend(helplist(modcmds.__contains__))
3488 else:
3489 else:
3489 rst.append(_('use "hg help extensions" for information on enabling '
3490 rst.append(_('use "hg help extensions" for information on enabling '
3490 'extensions\n'))
3491 'extensions\n'))
3491 return rst
3492 return rst
3492
3493
3493 def helpextcmd(name):
3494 def helpextcmd(name):
3494 cmd, ext, mod = extensions.disabledcmd(ui, name,
3495 cmd, ext, mod = extensions.disabledcmd(ui, name,
3495 ui.configbool('ui', 'strict'))
3496 ui.configbool('ui', 'strict'))
3496 doc = gettext(mod.__doc__).splitlines()[0]
3497 doc = gettext(mod.__doc__).splitlines()[0]
3497
3498
3498 rst = help.listexts(_("'%s' is provided by the following "
3499 rst = help.listexts(_("'%s' is provided by the following "
3499 "extension:") % cmd, {ext: doc}, indent=4)
3500 "extension:") % cmd, {ext: doc}, indent=4)
3500 rst.append('\n')
3501 rst.append('\n')
3501 rst.append(_('use "hg help extensions" for information on enabling '
3502 rst.append(_('use "hg help extensions" for information on enabling '
3502 'extensions\n'))
3503 'extensions\n'))
3503 return rst
3504 return rst
3504
3505
3505
3506
3506 rst = []
3507 rst = []
3507 kw = opts.get('keyword')
3508 kw = opts.get('keyword')
3508 if kw:
3509 if kw:
3509 matches = help.topicmatch(kw)
3510 matches = help.topicmatch(kw)
3510 for t, title in (('topics', _('Topics')),
3511 for t, title in (('topics', _('Topics')),
3511 ('commands', _('Commands')),
3512 ('commands', _('Commands')),
3512 ('extensions', _('Extensions')),
3513 ('extensions', _('Extensions')),
3513 ('extensioncommands', _('Extension Commands'))):
3514 ('extensioncommands', _('Extension Commands'))):
3514 if matches[t]:
3515 if matches[t]:
3515 rst.append('%s:\n\n' % title)
3516 rst.append('%s:\n\n' % title)
3516 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3517 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3517 rst.append('\n')
3518 rst.append('\n')
3518 elif name and name != 'shortlist':
3519 elif name and name != 'shortlist':
3519 i = None
3520 i = None
3520 if unknowncmd:
3521 if unknowncmd:
3521 queries = (helpextcmd,)
3522 queries = (helpextcmd,)
3522 elif opts.get('extension'):
3523 elif opts.get('extension'):
3523 queries = (helpext,)
3524 queries = (helpext,)
3524 elif opts.get('command'):
3525 elif opts.get('command'):
3525 queries = (helpcmd,)
3526 queries = (helpcmd,)
3526 else:
3527 else:
3527 queries = (helptopic, helpcmd, helpext, helpextcmd)
3528 queries = (helptopic, helpcmd, helpext, helpextcmd)
3528 for f in queries:
3529 for f in queries:
3529 try:
3530 try:
3530 rst = f(name)
3531 rst = f(name)
3531 i = None
3532 i = None
3532 break
3533 break
3533 except error.UnknownCommand, inst:
3534 except error.UnknownCommand, inst:
3534 i = inst
3535 i = inst
3535 if i:
3536 if i:
3536 raise i
3537 raise i
3537 else:
3538 else:
3538 # program name
3539 # program name
3539 if not ui.quiet:
3540 if not ui.quiet:
3540 rst = [_("Mercurial Distributed SCM\n"), '\n']
3541 rst = [_("Mercurial Distributed SCM\n"), '\n']
3541 rst.extend(helplist())
3542 rst.extend(helplist())
3542
3543
3543 keep = ui.verbose and ['verbose'] or []
3544 keep = ui.verbose and ['verbose'] or []
3544 text = ''.join(rst)
3545 text = ''.join(rst)
3545 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3546 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3546 if 'verbose' in pruned:
3547 if 'verbose' in pruned:
3547 keep.append('omitted')
3548 keep.append('omitted')
3548 else:
3549 else:
3549 keep.append('notomitted')
3550 keep.append('notomitted')
3550 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3551 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3551 ui.write(formatted)
3552 ui.write(formatted)
3552
3553
3553
3554
3554 @command('identify|id',
3555 @command('identify|id',
3555 [('r', 'rev', '',
3556 [('r', 'rev', '',
3556 _('identify the specified revision'), _('REV')),
3557 _('identify the specified revision'), _('REV')),
3557 ('n', 'num', None, _('show local revision number')),
3558 ('n', 'num', None, _('show local revision number')),
3558 ('i', 'id', None, _('show global revision id')),
3559 ('i', 'id', None, _('show global revision id')),
3559 ('b', 'branch', None, _('show branch')),
3560 ('b', 'branch', None, _('show branch')),
3560 ('t', 'tags', None, _('show tags')),
3561 ('t', 'tags', None, _('show tags')),
3561 ('B', 'bookmarks', None, _('show bookmarks')),
3562 ('B', 'bookmarks', None, _('show bookmarks')),
3562 ] + remoteopts,
3563 ] + remoteopts,
3563 _('[-nibtB] [-r REV] [SOURCE]'))
3564 _('[-nibtB] [-r REV] [SOURCE]'))
3564 def identify(ui, repo, source=None, rev=None,
3565 def identify(ui, repo, source=None, rev=None,
3565 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3566 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3566 """identify the working copy or specified revision
3567 """identify the working copy or specified revision
3567
3568
3568 Print a summary identifying the repository state at REV using one or
3569 Print a summary identifying the repository state at REV using one or
3569 two parent hash identifiers, followed by a "+" if the working
3570 two parent hash identifiers, followed by a "+" if the working
3570 directory has uncommitted changes, the branch name (if not default),
3571 directory has uncommitted changes, the branch name (if not default),
3571 a list of tags, and a list of bookmarks.
3572 a list of tags, and a list of bookmarks.
3572
3573
3573 When REV is not given, print a summary of the current state of the
3574 When REV is not given, print a summary of the current state of the
3574 repository.
3575 repository.
3575
3576
3576 Specifying a path to a repository root or Mercurial bundle will
3577 Specifying a path to a repository root or Mercurial bundle will
3577 cause lookup to operate on that repository/bundle.
3578 cause lookup to operate on that repository/bundle.
3578
3579
3579 .. container:: verbose
3580 .. container:: verbose
3580
3581
3581 Examples:
3582 Examples:
3582
3583
3583 - generate a build identifier for the working directory::
3584 - generate a build identifier for the working directory::
3584
3585
3585 hg id --id > build-id.dat
3586 hg id --id > build-id.dat
3586
3587
3587 - find the revision corresponding to a tag::
3588 - find the revision corresponding to a tag::
3588
3589
3589 hg id -n -r 1.3
3590 hg id -n -r 1.3
3590
3591
3591 - check the most recent revision of a remote repository::
3592 - check the most recent revision of a remote repository::
3592
3593
3593 hg id -r tip http://selenic.com/hg/
3594 hg id -r tip http://selenic.com/hg/
3594
3595
3595 Returns 0 if successful.
3596 Returns 0 if successful.
3596 """
3597 """
3597
3598
3598 if not repo and not source:
3599 if not repo and not source:
3599 raise util.Abort(_("there is no Mercurial repository here "
3600 raise util.Abort(_("there is no Mercurial repository here "
3600 "(.hg not found)"))
3601 "(.hg not found)"))
3601
3602
3602 hexfunc = ui.debugflag and hex or short
3603 hexfunc = ui.debugflag and hex or short
3603 default = not (num or id or branch or tags or bookmarks)
3604 default = not (num or id or branch or tags or bookmarks)
3604 output = []
3605 output = []
3605 revs = []
3606 revs = []
3606
3607
3607 if source:
3608 if source:
3608 source, branches = hg.parseurl(ui.expandpath(source))
3609 source, branches = hg.parseurl(ui.expandpath(source))
3609 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3610 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3610 repo = peer.local()
3611 repo = peer.local()
3611 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3612 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3612
3613
3613 if not repo:
3614 if not repo:
3614 if num or branch or tags:
3615 if num or branch or tags:
3615 raise util.Abort(
3616 raise util.Abort(
3616 _("can't query remote revision number, branch, or tags"))
3617 _("can't query remote revision number, branch, or tags"))
3617 if not rev and revs:
3618 if not rev and revs:
3618 rev = revs[0]
3619 rev = revs[0]
3619 if not rev:
3620 if not rev:
3620 rev = "tip"
3621 rev = "tip"
3621
3622
3622 remoterev = peer.lookup(rev)
3623 remoterev = peer.lookup(rev)
3623 if default or id:
3624 if default or id:
3624 output = [hexfunc(remoterev)]
3625 output = [hexfunc(remoterev)]
3625
3626
3626 def getbms():
3627 def getbms():
3627 bms = []
3628 bms = []
3628
3629
3629 if 'bookmarks' in peer.listkeys('namespaces'):
3630 if 'bookmarks' in peer.listkeys('namespaces'):
3630 hexremoterev = hex(remoterev)
3631 hexremoterev = hex(remoterev)
3631 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3632 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3632 if bmr == hexremoterev]
3633 if bmr == hexremoterev]
3633
3634
3634 return bms
3635 return bms
3635
3636
3636 if bookmarks:
3637 if bookmarks:
3637 output.extend(getbms())
3638 output.extend(getbms())
3638 elif default and not ui.quiet:
3639 elif default and not ui.quiet:
3639 # multiple bookmarks for a single parent separated by '/'
3640 # multiple bookmarks for a single parent separated by '/'
3640 bm = '/'.join(getbms())
3641 bm = '/'.join(getbms())
3641 if bm:
3642 if bm:
3642 output.append(bm)
3643 output.append(bm)
3643 else:
3644 else:
3644 if not rev:
3645 if not rev:
3645 ctx = repo[None]
3646 ctx = repo[None]
3646 parents = ctx.parents()
3647 parents = ctx.parents()
3647 changed = ""
3648 changed = ""
3648 if default or id or num:
3649 if default or id or num:
3649 if (util.any(repo.status())
3650 if (util.any(repo.status())
3650 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3651 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3651 changed = '+'
3652 changed = '+'
3652 if default or id:
3653 if default or id:
3653 output = ["%s%s" %
3654 output = ["%s%s" %
3654 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3655 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3655 if num:
3656 if num:
3656 output.append("%s%s" %
3657 output.append("%s%s" %
3657 ('+'.join([str(p.rev()) for p in parents]), changed))
3658 ('+'.join([str(p.rev()) for p in parents]), changed))
3658 else:
3659 else:
3659 ctx = scmutil.revsingle(repo, rev)
3660 ctx = scmutil.revsingle(repo, rev)
3660 if default or id:
3661 if default or id:
3661 output = [hexfunc(ctx.node())]
3662 output = [hexfunc(ctx.node())]
3662 if num:
3663 if num:
3663 output.append(str(ctx.rev()))
3664 output.append(str(ctx.rev()))
3664
3665
3665 if default and not ui.quiet:
3666 if default and not ui.quiet:
3666 b = ctx.branch()
3667 b = ctx.branch()
3667 if b != 'default':
3668 if b != 'default':
3668 output.append("(%s)" % b)
3669 output.append("(%s)" % b)
3669
3670
3670 # multiple tags for a single parent separated by '/'
3671 # multiple tags for a single parent separated by '/'
3671 t = '/'.join(ctx.tags())
3672 t = '/'.join(ctx.tags())
3672 if t:
3673 if t:
3673 output.append(t)
3674 output.append(t)
3674
3675
3675 # multiple bookmarks for a single parent separated by '/'
3676 # multiple bookmarks for a single parent separated by '/'
3676 bm = '/'.join(ctx.bookmarks())
3677 bm = '/'.join(ctx.bookmarks())
3677 if bm:
3678 if bm:
3678 output.append(bm)
3679 output.append(bm)
3679 else:
3680 else:
3680 if branch:
3681 if branch:
3681 output.append(ctx.branch())
3682 output.append(ctx.branch())
3682
3683
3683 if tags:
3684 if tags:
3684 output.extend(ctx.tags())
3685 output.extend(ctx.tags())
3685
3686
3686 if bookmarks:
3687 if bookmarks:
3687 output.extend(ctx.bookmarks())
3688 output.extend(ctx.bookmarks())
3688
3689
3689 ui.write("%s\n" % ' '.join(output))
3690 ui.write("%s\n" % ' '.join(output))
3690
3691
3691 @command('import|patch',
3692 @command('import|patch',
3692 [('p', 'strip', 1,
3693 [('p', 'strip', 1,
3693 _('directory strip option for patch. This has the same '
3694 _('directory strip option for patch. This has the same '
3694 'meaning as the corresponding patch option'), _('NUM')),
3695 'meaning as the corresponding patch option'), _('NUM')),
3695 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3696 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3696 ('e', 'edit', False, _('invoke editor on commit messages')),
3697 ('e', 'edit', False, _('invoke editor on commit messages')),
3697 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3698 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3698 ('', 'no-commit', None,
3699 ('', 'no-commit', None,
3699 _("don't commit, just update the working directory")),
3700 _("don't commit, just update the working directory")),
3700 ('', 'bypass', None,
3701 ('', 'bypass', None,
3701 _("apply patch without touching the working directory")),
3702 _("apply patch without touching the working directory")),
3702 ('', 'exact', None,
3703 ('', 'exact', None,
3703 _('apply patch to the nodes from which it was generated')),
3704 _('apply patch to the nodes from which it was generated')),
3704 ('', 'import-branch', None,
3705 ('', 'import-branch', None,
3705 _('use any branch information in patch (implied by --exact)'))] +
3706 _('use any branch information in patch (implied by --exact)'))] +
3706 commitopts + commitopts2 + similarityopts,
3707 commitopts + commitopts2 + similarityopts,
3707 _('[OPTION]... PATCH...'))
3708 _('[OPTION]... PATCH...'))
3708 def import_(ui, repo, patch1=None, *patches, **opts):
3709 def import_(ui, repo, patch1=None, *patches, **opts):
3709 """import an ordered set of patches
3710 """import an ordered set of patches
3710
3711
3711 Import a list of patches and commit them individually (unless
3712 Import a list of patches and commit them individually (unless
3712 --no-commit is specified).
3713 --no-commit is specified).
3713
3714
3714 If there are outstanding changes in the working directory, import
3715 If there are outstanding changes in the working directory, import
3715 will abort unless given the -f/--force flag.
3716 will abort unless given the -f/--force flag.
3716
3717
3717 You can import a patch straight from a mail message. Even patches
3718 You can import a patch straight from a mail message. Even patches
3718 as attachments work (to use the body part, it must have type
3719 as attachments work (to use the body part, it must have type
3719 text/plain or text/x-patch). From and Subject headers of email
3720 text/plain or text/x-patch). From and Subject headers of email
3720 message are used as default committer and commit message. All
3721 message are used as default committer and commit message. All
3721 text/plain body parts before first diff are added to commit
3722 text/plain body parts before first diff are added to commit
3722 message.
3723 message.
3723
3724
3724 If the imported patch was generated by :hg:`export`, user and
3725 If the imported patch was generated by :hg:`export`, user and
3725 description from patch override values from message headers and
3726 description from patch override values from message headers and
3726 body. Values given on command line with -m/--message and -u/--user
3727 body. Values given on command line with -m/--message and -u/--user
3727 override these.
3728 override these.
3728
3729
3729 If --exact is specified, import will set the working directory to
3730 If --exact is specified, import will set the working directory to
3730 the parent of each patch before applying it, and will abort if the
3731 the parent of each patch before applying it, and will abort if the
3731 resulting changeset has a different ID than the one recorded in
3732 resulting changeset has a different ID than the one recorded in
3732 the patch. This may happen due to character set problems or other
3733 the patch. This may happen due to character set problems or other
3733 deficiencies in the text patch format.
3734 deficiencies in the text patch format.
3734
3735
3735 Use --bypass to apply and commit patches directly to the
3736 Use --bypass to apply and commit patches directly to the
3736 repository, not touching the working directory. Without --exact,
3737 repository, not touching the working directory. Without --exact,
3737 patches will be applied on top of the working directory parent
3738 patches will be applied on top of the working directory parent
3738 revision.
3739 revision.
3739
3740
3740 With -s/--similarity, hg will attempt to discover renames and
3741 With -s/--similarity, hg will attempt to discover renames and
3741 copies in the patch in the same way as :hg:`addremove`.
3742 copies in the patch in the same way as :hg:`addremove`.
3742
3743
3743 To read a patch from standard input, use "-" as the patch name. If
3744 To read a patch from standard input, use "-" as the patch name. If
3744 a URL is specified, the patch will be downloaded from it.
3745 a URL is specified, the patch will be downloaded from it.
3745 See :hg:`help dates` for a list of formats valid for -d/--date.
3746 See :hg:`help dates` for a list of formats valid for -d/--date.
3746
3747
3747 .. container:: verbose
3748 .. container:: verbose
3748
3749
3749 Examples:
3750 Examples:
3750
3751
3751 - import a traditional patch from a website and detect renames::
3752 - import a traditional patch from a website and detect renames::
3752
3753
3753 hg import -s 80 http://example.com/bugfix.patch
3754 hg import -s 80 http://example.com/bugfix.patch
3754
3755
3755 - import a changeset from an hgweb server::
3756 - import a changeset from an hgweb server::
3756
3757
3757 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3758 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3758
3759
3759 - import all the patches in an Unix-style mbox::
3760 - import all the patches in an Unix-style mbox::
3760
3761
3761 hg import incoming-patches.mbox
3762 hg import incoming-patches.mbox
3762
3763
3763 - attempt to exactly restore an exported changeset (not always
3764 - attempt to exactly restore an exported changeset (not always
3764 possible)::
3765 possible)::
3765
3766
3766 hg import --exact proposed-fix.patch
3767 hg import --exact proposed-fix.patch
3767
3768
3768 Returns 0 on success.
3769 Returns 0 on success.
3769 """
3770 """
3770
3771
3771 if not patch1:
3772 if not patch1:
3772 raise util.Abort(_('need at least one patch to import'))
3773 raise util.Abort(_('need at least one patch to import'))
3773
3774
3774 patches = (patch1,) + patches
3775 patches = (patch1,) + patches
3775
3776
3776 date = opts.get('date')
3777 date = opts.get('date')
3777 if date:
3778 if date:
3778 opts['date'] = util.parsedate(date)
3779 opts['date'] = util.parsedate(date)
3779
3780
3780 editor = cmdutil.commiteditor
3781 editor = cmdutil.commiteditor
3781 if opts.get('edit'):
3782 if opts.get('edit'):
3782 editor = cmdutil.commitforceeditor
3783 editor = cmdutil.commitforceeditor
3783
3784
3784 update = not opts.get('bypass')
3785 update = not opts.get('bypass')
3785 if not update and opts.get('no_commit'):
3786 if not update and opts.get('no_commit'):
3786 raise util.Abort(_('cannot use --no-commit with --bypass'))
3787 raise util.Abort(_('cannot use --no-commit with --bypass'))
3787 try:
3788 try:
3788 sim = float(opts.get('similarity') or 0)
3789 sim = float(opts.get('similarity') or 0)
3789 except ValueError:
3790 except ValueError:
3790 raise util.Abort(_('similarity must be a number'))
3791 raise util.Abort(_('similarity must be a number'))
3791 if sim < 0 or sim > 100:
3792 if sim < 0 or sim > 100:
3792 raise util.Abort(_('similarity must be between 0 and 100'))
3793 raise util.Abort(_('similarity must be between 0 and 100'))
3793 if sim and not update:
3794 if sim and not update:
3794 raise util.Abort(_('cannot use --similarity with --bypass'))
3795 raise util.Abort(_('cannot use --similarity with --bypass'))
3795
3796
3796 if (opts.get('exact') or not opts.get('force')) and update:
3797 if (opts.get('exact') or not opts.get('force')) and update:
3797 cmdutil.bailifchanged(repo)
3798 cmdutil.bailifchanged(repo)
3798
3799
3799 base = opts["base"]
3800 base = opts["base"]
3800 strip = opts["strip"]
3801 strip = opts["strip"]
3801 wlock = lock = tr = None
3802 wlock = lock = tr = None
3802 msgs = []
3803 msgs = []
3803
3804
3804 def checkexact(repo, n, nodeid):
3805 def checkexact(repo, n, nodeid):
3805 if opts.get('exact') and hex(n) != nodeid:
3806 if opts.get('exact') and hex(n) != nodeid:
3806 repo.rollback()
3807 repo.rollback()
3807 raise util.Abort(_('patch is damaged or loses information'))
3808 raise util.Abort(_('patch is damaged or loses information'))
3808
3809
3809 def tryone(ui, hunk, parents):
3810 def tryone(ui, hunk, parents):
3810 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3811 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3811 patch.extract(ui, hunk)
3812 patch.extract(ui, hunk)
3812
3813
3813 if not tmpname:
3814 if not tmpname:
3814 return (None, None)
3815 return (None, None)
3815 msg = _('applied to working directory')
3816 msg = _('applied to working directory')
3816
3817
3817 try:
3818 try:
3818 cmdline_message = cmdutil.logmessage(ui, opts)
3819 cmdline_message = cmdutil.logmessage(ui, opts)
3819 if cmdline_message:
3820 if cmdline_message:
3820 # pickup the cmdline msg
3821 # pickup the cmdline msg
3821 message = cmdline_message
3822 message = cmdline_message
3822 elif message:
3823 elif message:
3823 # pickup the patch msg
3824 # pickup the patch msg
3824 message = message.strip()
3825 message = message.strip()
3825 else:
3826 else:
3826 # launch the editor
3827 # launch the editor
3827 message = None
3828 message = None
3828 ui.debug('message:\n%s\n' % message)
3829 ui.debug('message:\n%s\n' % message)
3829
3830
3830 if len(parents) == 1:
3831 if len(parents) == 1:
3831 parents.append(repo[nullid])
3832 parents.append(repo[nullid])
3832 if opts.get('exact'):
3833 if opts.get('exact'):
3833 if not nodeid or not p1:
3834 if not nodeid or not p1:
3834 raise util.Abort(_('not a Mercurial patch'))
3835 raise util.Abort(_('not a Mercurial patch'))
3835 p1 = repo[p1]
3836 p1 = repo[p1]
3836 p2 = repo[p2 or nullid]
3837 p2 = repo[p2 or nullid]
3837 elif p2:
3838 elif p2:
3838 try:
3839 try:
3839 p1 = repo[p1]
3840 p1 = repo[p1]
3840 p2 = repo[p2]
3841 p2 = repo[p2]
3841 # Without any options, consider p2 only if the
3842 # Without any options, consider p2 only if the
3842 # patch is being applied on top of the recorded
3843 # patch is being applied on top of the recorded
3843 # first parent.
3844 # first parent.
3844 if p1 != parents[0]:
3845 if p1 != parents[0]:
3845 p1 = parents[0]
3846 p1 = parents[0]
3846 p2 = repo[nullid]
3847 p2 = repo[nullid]
3847 except error.RepoError:
3848 except error.RepoError:
3848 p1, p2 = parents
3849 p1, p2 = parents
3849 else:
3850 else:
3850 p1, p2 = parents
3851 p1, p2 = parents
3851
3852
3852 n = None
3853 n = None
3853 if update:
3854 if update:
3854 if p1 != parents[0]:
3855 if p1 != parents[0]:
3855 hg.clean(repo, p1.node())
3856 hg.clean(repo, p1.node())
3856 if p2 != parents[1]:
3857 if p2 != parents[1]:
3857 repo.setparents(p1.node(), p2.node())
3858 repo.setparents(p1.node(), p2.node())
3858
3859
3859 if opts.get('exact') or opts.get('import_branch'):
3860 if opts.get('exact') or opts.get('import_branch'):
3860 repo.dirstate.setbranch(branch or 'default')
3861 repo.dirstate.setbranch(branch or 'default')
3861
3862
3862 files = set()
3863 files = set()
3863 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3864 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3864 eolmode=None, similarity=sim / 100.0)
3865 eolmode=None, similarity=sim / 100.0)
3865 files = list(files)
3866 files = list(files)
3866 if opts.get('no_commit'):
3867 if opts.get('no_commit'):
3867 if message:
3868 if message:
3868 msgs.append(message)
3869 msgs.append(message)
3869 else:
3870 else:
3870 if opts.get('exact') or p2:
3871 if opts.get('exact') or p2:
3871 # If you got here, you either use --force and know what
3872 # If you got here, you either use --force and know what
3872 # you are doing or used --exact or a merge patch while
3873 # you are doing or used --exact or a merge patch while
3873 # being updated to its first parent.
3874 # being updated to its first parent.
3874 m = None
3875 m = None
3875 else:
3876 else:
3876 m = scmutil.matchfiles(repo, files or [])
3877 m = scmutil.matchfiles(repo, files or [])
3877 n = repo.commit(message, opts.get('user') or user,
3878 n = repo.commit(message, opts.get('user') or user,
3878 opts.get('date') or date, match=m,
3879 opts.get('date') or date, match=m,
3879 editor=editor)
3880 editor=editor)
3880 checkexact(repo, n, nodeid)
3881 checkexact(repo, n, nodeid)
3881 else:
3882 else:
3882 if opts.get('exact') or opts.get('import_branch'):
3883 if opts.get('exact') or opts.get('import_branch'):
3883 branch = branch or 'default'
3884 branch = branch or 'default'
3884 else:
3885 else:
3885 branch = p1.branch()
3886 branch = p1.branch()
3886 store = patch.filestore()
3887 store = patch.filestore()
3887 try:
3888 try:
3888 files = set()
3889 files = set()
3889 try:
3890 try:
3890 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3891 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3891 files, eolmode=None)
3892 files, eolmode=None)
3892 except patch.PatchError, e:
3893 except patch.PatchError, e:
3893 raise util.Abort(str(e))
3894 raise util.Abort(str(e))
3894 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3895 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3895 message,
3896 message,
3896 opts.get('user') or user,
3897 opts.get('user') or user,
3897 opts.get('date') or date,
3898 opts.get('date') or date,
3898 branch, files, store,
3899 branch, files, store,
3899 editor=cmdutil.commiteditor)
3900 editor=cmdutil.commiteditor)
3900 repo.savecommitmessage(memctx.description())
3901 repo.savecommitmessage(memctx.description())
3901 n = memctx.commit()
3902 n = memctx.commit()
3902 checkexact(repo, n, nodeid)
3903 checkexact(repo, n, nodeid)
3903 finally:
3904 finally:
3904 store.close()
3905 store.close()
3905 if n:
3906 if n:
3906 # i18n: refers to a short changeset id
3907 # i18n: refers to a short changeset id
3907 msg = _('created %s') % short(n)
3908 msg = _('created %s') % short(n)
3908 return (msg, n)
3909 return (msg, n)
3909 finally:
3910 finally:
3910 os.unlink(tmpname)
3911 os.unlink(tmpname)
3911
3912
3912 try:
3913 try:
3913 try:
3914 try:
3914 wlock = repo.wlock()
3915 wlock = repo.wlock()
3915 if not opts.get('no_commit'):
3916 if not opts.get('no_commit'):
3916 lock = repo.lock()
3917 lock = repo.lock()
3917 tr = repo.transaction('import')
3918 tr = repo.transaction('import')
3918 parents = repo.parents()
3919 parents = repo.parents()
3919 for patchurl in patches:
3920 for patchurl in patches:
3920 if patchurl == '-':
3921 if patchurl == '-':
3921 ui.status(_('applying patch from stdin\n'))
3922 ui.status(_('applying patch from stdin\n'))
3922 patchfile = ui.fin
3923 patchfile = ui.fin
3923 patchurl = 'stdin' # for error message
3924 patchurl = 'stdin' # for error message
3924 else:
3925 else:
3925 patchurl = os.path.join(base, patchurl)
3926 patchurl = os.path.join(base, patchurl)
3926 ui.status(_('applying %s\n') % patchurl)
3927 ui.status(_('applying %s\n') % patchurl)
3927 patchfile = hg.openpath(ui, patchurl)
3928 patchfile = hg.openpath(ui, patchurl)
3928
3929
3929 haspatch = False
3930 haspatch = False
3930 for hunk in patch.split(patchfile):
3931 for hunk in patch.split(patchfile):
3931 (msg, node) = tryone(ui, hunk, parents)
3932 (msg, node) = tryone(ui, hunk, parents)
3932 if msg:
3933 if msg:
3933 haspatch = True
3934 haspatch = True
3934 ui.note(msg + '\n')
3935 ui.note(msg + '\n')
3935 if update or opts.get('exact'):
3936 if update or opts.get('exact'):
3936 parents = repo.parents()
3937 parents = repo.parents()
3937 else:
3938 else:
3938 parents = [repo[node]]
3939 parents = [repo[node]]
3939
3940
3940 if not haspatch:
3941 if not haspatch:
3941 raise util.Abort(_('%s: no diffs found') % patchurl)
3942 raise util.Abort(_('%s: no diffs found') % patchurl)
3942
3943
3943 if tr:
3944 if tr:
3944 tr.close()
3945 tr.close()
3945 if msgs:
3946 if msgs:
3946 repo.savecommitmessage('\n* * *\n'.join(msgs))
3947 repo.savecommitmessage('\n* * *\n'.join(msgs))
3947 except: # re-raises
3948 except: # re-raises
3948 # wlock.release() indirectly calls dirstate.write(): since
3949 # wlock.release() indirectly calls dirstate.write(): since
3949 # we're crashing, we do not want to change the working dir
3950 # we're crashing, we do not want to change the working dir
3950 # parent after all, so make sure it writes nothing
3951 # parent after all, so make sure it writes nothing
3951 repo.dirstate.invalidate()
3952 repo.dirstate.invalidate()
3952 raise
3953 raise
3953 finally:
3954 finally:
3954 if tr:
3955 if tr:
3955 tr.release()
3956 tr.release()
3956 release(lock, wlock)
3957 release(lock, wlock)
3957
3958
3958 @command('incoming|in',
3959 @command('incoming|in',
3959 [('f', 'force', None,
3960 [('f', 'force', None,
3960 _('run even if remote repository is unrelated')),
3961 _('run even if remote repository is unrelated')),
3961 ('n', 'newest-first', None, _('show newest record first')),
3962 ('n', 'newest-first', None, _('show newest record first')),
3962 ('', 'bundle', '',
3963 ('', 'bundle', '',
3963 _('file to store the bundles into'), _('FILE')),
3964 _('file to store the bundles into'), _('FILE')),
3964 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3965 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3965 ('B', 'bookmarks', False, _("compare bookmarks")),
3966 ('B', 'bookmarks', False, _("compare bookmarks")),
3966 ('b', 'branch', [],
3967 ('b', 'branch', [],
3967 _('a specific branch you would like to pull'), _('BRANCH')),
3968 _('a specific branch you would like to pull'), _('BRANCH')),
3968 ] + logopts + remoteopts + subrepoopts,
3969 ] + logopts + remoteopts + subrepoopts,
3969 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3970 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3970 def incoming(ui, repo, source="default", **opts):
3971 def incoming(ui, repo, source="default", **opts):
3971 """show new changesets found in source
3972 """show new changesets found in source
3972
3973
3973 Show new changesets found in the specified path/URL or the default
3974 Show new changesets found in the specified path/URL or the default
3974 pull location. These are the changesets that would have been pulled
3975 pull location. These are the changesets that would have been pulled
3975 if a pull at the time you issued this command.
3976 if a pull at the time you issued this command.
3976
3977
3977 For remote repository, using --bundle avoids downloading the
3978 For remote repository, using --bundle avoids downloading the
3978 changesets twice if the incoming is followed by a pull.
3979 changesets twice if the incoming is followed by a pull.
3979
3980
3980 See pull for valid source format details.
3981 See pull for valid source format details.
3981
3982
3982 Returns 0 if there are incoming changes, 1 otherwise.
3983 Returns 0 if there are incoming changes, 1 otherwise.
3983 """
3984 """
3984 if opts.get('graph'):
3985 if opts.get('graph'):
3985 cmdutil.checkunsupportedgraphflags([], opts)
3986 cmdutil.checkunsupportedgraphflags([], opts)
3986 def display(other, chlist, displayer):
3987 def display(other, chlist, displayer):
3987 revdag = cmdutil.graphrevs(other, chlist, opts)
3988 revdag = cmdutil.graphrevs(other, chlist, opts)
3988 showparents = [ctx.node() for ctx in repo[None].parents()]
3989 showparents = [ctx.node() for ctx in repo[None].parents()]
3989 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3990 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3990 graphmod.asciiedges)
3991 graphmod.asciiedges)
3991
3992
3992 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3993 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3993 return 0
3994 return 0
3994
3995
3995 if opts.get('bundle') and opts.get('subrepos'):
3996 if opts.get('bundle') and opts.get('subrepos'):
3996 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3997 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3997
3998
3998 if opts.get('bookmarks'):
3999 if opts.get('bookmarks'):
3999 source, branches = hg.parseurl(ui.expandpath(source),
4000 source, branches = hg.parseurl(ui.expandpath(source),
4000 opts.get('branch'))
4001 opts.get('branch'))
4001 other = hg.peer(repo, opts, source)
4002 other = hg.peer(repo, opts, source)
4002 if 'bookmarks' not in other.listkeys('namespaces'):
4003 if 'bookmarks' not in other.listkeys('namespaces'):
4003 ui.warn(_("remote doesn't support bookmarks\n"))
4004 ui.warn(_("remote doesn't support bookmarks\n"))
4004 return 0
4005 return 0
4005 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4006 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4006 return bookmarks.diff(ui, repo, other)
4007 return bookmarks.diff(ui, repo, other)
4007
4008
4008 repo._subtoppath = ui.expandpath(source)
4009 repo._subtoppath = ui.expandpath(source)
4009 try:
4010 try:
4010 return hg.incoming(ui, repo, source, opts)
4011 return hg.incoming(ui, repo, source, opts)
4011 finally:
4012 finally:
4012 del repo._subtoppath
4013 del repo._subtoppath
4013
4014
4014
4015
4015 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4016 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4016 def init(ui, dest=".", **opts):
4017 def init(ui, dest=".", **opts):
4017 """create a new repository in the given directory
4018 """create a new repository in the given directory
4018
4019
4019 Initialize a new repository in the given directory. If the given
4020 Initialize a new repository in the given directory. If the given
4020 directory does not exist, it will be created.
4021 directory does not exist, it will be created.
4021
4022
4022 If no directory is given, the current directory is used.
4023 If no directory is given, the current directory is used.
4023
4024
4024 It is possible to specify an ``ssh://`` URL as the destination.
4025 It is possible to specify an ``ssh://`` URL as the destination.
4025 See :hg:`help urls` for more information.
4026 See :hg:`help urls` for more information.
4026
4027
4027 Returns 0 on success.
4028 Returns 0 on success.
4028 """
4029 """
4029 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4030 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4030
4031
4031 @command('locate',
4032 @command('locate',
4032 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4033 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4033 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4034 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4034 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4035 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4035 ] + walkopts,
4036 ] + walkopts,
4036 _('[OPTION]... [PATTERN]...'))
4037 _('[OPTION]... [PATTERN]...'))
4037 def locate(ui, repo, *pats, **opts):
4038 def locate(ui, repo, *pats, **opts):
4038 """locate files matching specific patterns
4039 """locate files matching specific patterns
4039
4040
4040 Print files under Mercurial control in the working directory whose
4041 Print files under Mercurial control in the working directory whose
4041 names match the given patterns.
4042 names match the given patterns.
4042
4043
4043 By default, this command searches all directories in the working
4044 By default, this command searches all directories in the working
4044 directory. To search just the current directory and its
4045 directory. To search just the current directory and its
4045 subdirectories, use "--include .".
4046 subdirectories, use "--include .".
4046
4047
4047 If no patterns are given to match, this command prints the names
4048 If no patterns are given to match, this command prints the names
4048 of all files under Mercurial control in the working directory.
4049 of all files under Mercurial control in the working directory.
4049
4050
4050 If you want to feed the output of this command into the "xargs"
4051 If you want to feed the output of this command into the "xargs"
4051 command, use the -0 option to both this command and "xargs". This
4052 command, use the -0 option to both this command and "xargs". This
4052 will avoid the problem of "xargs" treating single filenames that
4053 will avoid the problem of "xargs" treating single filenames that
4053 contain whitespace as multiple filenames.
4054 contain whitespace as multiple filenames.
4054
4055
4055 Returns 0 if a match is found, 1 otherwise.
4056 Returns 0 if a match is found, 1 otherwise.
4056 """
4057 """
4057 end = opts.get('print0') and '\0' or '\n'
4058 end = opts.get('print0') and '\0' or '\n'
4058 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4059 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4059
4060
4060 ret = 1
4061 ret = 1
4061 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4062 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4062 m.bad = lambda x, y: False
4063 m.bad = lambda x, y: False
4063 for abs in repo[rev].walk(m):
4064 for abs in repo[rev].walk(m):
4064 if not rev and abs not in repo.dirstate:
4065 if not rev and abs not in repo.dirstate:
4065 continue
4066 continue
4066 if opts.get('fullpath'):
4067 if opts.get('fullpath'):
4067 ui.write(repo.wjoin(abs), end)
4068 ui.write(repo.wjoin(abs), end)
4068 else:
4069 else:
4069 ui.write(((pats and m.rel(abs)) or abs), end)
4070 ui.write(((pats and m.rel(abs)) or abs), end)
4070 ret = 0
4071 ret = 0
4071
4072
4072 return ret
4073 return ret
4073
4074
4074 @command('^log|history',
4075 @command('^log|history',
4075 [('f', 'follow', None,
4076 [('f', 'follow', None,
4076 _('follow changeset history, or file history across copies and renames')),
4077 _('follow changeset history, or file history across copies and renames')),
4077 ('', 'follow-first', None,
4078 ('', 'follow-first', None,
4078 _('only follow the first parent of merge changesets (DEPRECATED)')),
4079 _('only follow the first parent of merge changesets (DEPRECATED)')),
4079 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4080 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4080 ('C', 'copies', None, _('show copied files')),
4081 ('C', 'copies', None, _('show copied files')),
4081 ('k', 'keyword', [],
4082 ('k', 'keyword', [],
4082 _('do case-insensitive search for a given text'), _('TEXT')),
4083 _('do case-insensitive search for a given text'), _('TEXT')),
4083 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4084 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4084 ('', 'removed', None, _('include revisions where files were removed')),
4085 ('', 'removed', None, _('include revisions where files were removed')),
4085 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4086 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4086 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4087 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4087 ('', 'only-branch', [],
4088 ('', 'only-branch', [],
4088 _('show only changesets within the given named branch (DEPRECATED)'),
4089 _('show only changesets within the given named branch (DEPRECATED)'),
4089 _('BRANCH')),
4090 _('BRANCH')),
4090 ('b', 'branch', [],
4091 ('b', 'branch', [],
4091 _('show changesets within the given named branch'), _('BRANCH')),
4092 _('show changesets within the given named branch'), _('BRANCH')),
4092 ('P', 'prune', [],
4093 ('P', 'prune', [],
4093 _('do not display revision or any of its ancestors'), _('REV')),
4094 _('do not display revision or any of its ancestors'), _('REV')),
4094 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4095 ] + logopts + walkopts,
4095 ] + logopts + walkopts,
4096 _('[OPTION]... [FILE]'))
4096 _('[OPTION]... [FILE]'))
4097 def log(ui, repo, *pats, **opts):
4097 def log(ui, repo, *pats, **opts):
4098 """show revision history of entire repository or files
4098 """show revision history of entire repository or files
4099
4099
4100 Print the revision history of the specified files or the entire
4100 Print the revision history of the specified files or the entire
4101 project.
4101 project.
4102
4102
4103 If no revision range is specified, the default is ``tip:0`` unless
4103 If no revision range is specified, the default is ``tip:0`` unless
4104 --follow is set, in which case the working directory parent is
4104 --follow is set, in which case the working directory parent is
4105 used as the starting revision.
4105 used as the starting revision.
4106
4106
4107 File history is shown without following rename or copy history of
4107 File history is shown without following rename or copy history of
4108 files. Use -f/--follow with a filename to follow history across
4108 files. Use -f/--follow with a filename to follow history across
4109 renames and copies. --follow without a filename will only show
4109 renames and copies. --follow without a filename will only show
4110 ancestors or descendants of the starting revision.
4110 ancestors or descendants of the starting revision.
4111
4111
4112 By default this command prints revision number and changeset id,
4112 By default this command prints revision number and changeset id,
4113 tags, non-trivial parents, user, date and time, and a summary for
4113 tags, non-trivial parents, user, date and time, and a summary for
4114 each commit. When the -v/--verbose switch is used, the list of
4114 each commit. When the -v/--verbose switch is used, the list of
4115 changed files and full commit message are shown.
4115 changed files and full commit message are shown.
4116
4116
4117 .. note::
4117 .. note::
4118 log -p/--patch may generate unexpected diff output for merge
4118 log -p/--patch may generate unexpected diff output for merge
4119 changesets, as it will only compare the merge changeset against
4119 changesets, as it will only compare the merge changeset against
4120 its first parent. Also, only files different from BOTH parents
4120 its first parent. Also, only files different from BOTH parents
4121 will appear in files:.
4121 will appear in files:.
4122
4122
4123 .. note::
4123 .. note::
4124 for performance reasons, log FILE may omit duplicate changes
4124 for performance reasons, log FILE may omit duplicate changes
4125 made on branches and will not show deletions. To see all
4125 made on branches and will not show deletions. To see all
4126 changes including duplicates and deletions, use the --removed
4126 changes including duplicates and deletions, use the --removed
4127 switch.
4127 switch.
4128
4128
4129 .. container:: verbose
4129 .. container:: verbose
4130
4130
4131 Some examples:
4131 Some examples:
4132
4132
4133 - changesets with full descriptions and file lists::
4133 - changesets with full descriptions and file lists::
4134
4134
4135 hg log -v
4135 hg log -v
4136
4136
4137 - changesets ancestral to the working directory::
4137 - changesets ancestral to the working directory::
4138
4138
4139 hg log -f
4139 hg log -f
4140
4140
4141 - last 10 commits on the current branch::
4141 - last 10 commits on the current branch::
4142
4142
4143 hg log -l 10 -b .
4143 hg log -l 10 -b .
4144
4144
4145 - changesets showing all modifications of a file, including removals::
4145 - changesets showing all modifications of a file, including removals::
4146
4146
4147 hg log --removed file.c
4147 hg log --removed file.c
4148
4148
4149 - all changesets that touch a directory, with diffs, excluding merges::
4149 - all changesets that touch a directory, with diffs, excluding merges::
4150
4150
4151 hg log -Mp lib/
4151 hg log -Mp lib/
4152
4152
4153 - all revision numbers that match a keyword::
4153 - all revision numbers that match a keyword::
4154
4154
4155 hg log -k bug --template "{rev}\\n"
4155 hg log -k bug --template "{rev}\\n"
4156
4156
4157 - check if a given changeset is included is a tagged release::
4157 - check if a given changeset is included is a tagged release::
4158
4158
4159 hg log -r "a21ccf and ancestor(1.9)"
4159 hg log -r "a21ccf and ancestor(1.9)"
4160
4160
4161 - find all changesets by some user in a date range::
4161 - find all changesets by some user in a date range::
4162
4162
4163 hg log -k alice -d "may 2008 to jul 2008"
4163 hg log -k alice -d "may 2008 to jul 2008"
4164
4164
4165 - summary of all changesets after the last tag::
4165 - summary of all changesets after the last tag::
4166
4166
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4168
4168
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4170
4170
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4172 specifying revisions.
4172 specifying revisions.
4173
4173
4174 See :hg:`help templates` for more about pre-packaged styles and
4174 See :hg:`help templates` for more about pre-packaged styles and
4175 specifying custom templates.
4175 specifying custom templates.
4176
4176
4177 Returns 0 on success.
4177 Returns 0 on success.
4178 """
4178 """
4179 if opts.get('graph'):
4179 if opts.get('graph'):
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4181
4181
4182 matchfn = scmutil.match(repo[None], pats, opts)
4182 matchfn = scmutil.match(repo[None], pats, opts)
4183 limit = cmdutil.loglimit(opts)
4183 limit = cmdutil.loglimit(opts)
4184 count = 0
4184 count = 0
4185
4185
4186 getrenamed, endrev = None, None
4186 getrenamed, endrev = None, None
4187 if opts.get('copies'):
4187 if opts.get('copies'):
4188 if opts.get('rev'):
4188 if opts.get('rev'):
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4191
4191
4192 df = False
4192 df = False
4193 if opts.get("date"):
4193 if opts.get("date"):
4194 df = util.matchdate(opts["date"])
4194 df = util.matchdate(opts["date"])
4195
4195
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4198
4198
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4200 def prep(ctx, fns):
4200 def prep(ctx, fns):
4201 rev = ctx.rev()
4201 rev = ctx.rev()
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4203 if p != nullrev]
4203 if p != nullrev]
4204 if opts.get('no_merges') and len(parents) == 2:
4204 if opts.get('no_merges') and len(parents) == 2:
4205 return
4205 return
4206 if opts.get('only_merges') and len(parents) != 2:
4206 if opts.get('only_merges') and len(parents) != 2:
4207 return
4207 return
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4209 return
4209 return
4210 if not opts.get('hidden') and ctx.hidden():
4211 return
4212 if df and not df(ctx.date()[0]):
4210 if df and not df(ctx.date()[0]):
4213 return
4211 return
4214
4212
4215 lower = encoding.lower
4213 lower = encoding.lower
4216 if opts.get('user'):
4214 if opts.get('user'):
4217 luser = lower(ctx.user())
4215 luser = lower(ctx.user())
4218 for k in [lower(x) for x in opts['user']]:
4216 for k in [lower(x) for x in opts['user']]:
4219 if (k in luser):
4217 if (k in luser):
4220 break
4218 break
4221 else:
4219 else:
4222 return
4220 return
4223 if opts.get('keyword'):
4221 if opts.get('keyword'):
4224 luser = lower(ctx.user())
4222 luser = lower(ctx.user())
4225 ldesc = lower(ctx.description())
4223 ldesc = lower(ctx.description())
4226 lfiles = lower(" ".join(ctx.files()))
4224 lfiles = lower(" ".join(ctx.files()))
4227 for k in [lower(x) for x in opts['keyword']]:
4225 for k in [lower(x) for x in opts['keyword']]:
4228 if (k in luser or k in ldesc or k in lfiles):
4226 if (k in luser or k in ldesc or k in lfiles):
4229 break
4227 break
4230 else:
4228 else:
4231 return
4229 return
4232
4230
4233 copies = None
4231 copies = None
4234 if getrenamed is not None and rev:
4232 if getrenamed is not None and rev:
4235 copies = []
4233 copies = []
4236 for fn in ctx.files():
4234 for fn in ctx.files():
4237 rename = getrenamed(fn, rev)
4235 rename = getrenamed(fn, rev)
4238 if rename:
4236 if rename:
4239 copies.append((fn, rename[0]))
4237 copies.append((fn, rename[0]))
4240
4238
4241 revmatchfn = None
4239 revmatchfn = None
4242 if opts.get('patch') or opts.get('stat'):
4240 if opts.get('patch') or opts.get('stat'):
4243 if opts.get('follow') or opts.get('follow_first'):
4241 if opts.get('follow') or opts.get('follow_first'):
4244 # note: this might be wrong when following through merges
4242 # note: this might be wrong when following through merges
4245 revmatchfn = scmutil.match(repo[None], fns, default='path')
4243 revmatchfn = scmutil.match(repo[None], fns, default='path')
4246 else:
4244 else:
4247 revmatchfn = matchfn
4245 revmatchfn = matchfn
4248
4246
4249 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4247 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4250
4248
4251 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4249 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4252 if count == limit:
4250 if count == limit:
4253 break
4251 break
4254 if displayer.flush(ctx.rev()):
4252 if displayer.flush(ctx.rev()):
4255 count += 1
4253 count += 1
4256 displayer.close()
4254 displayer.close()
4257
4255
4258 @command('manifest',
4256 @command('manifest',
4259 [('r', 'rev', '', _('revision to display'), _('REV')),
4257 [('r', 'rev', '', _('revision to display'), _('REV')),
4260 ('', 'all', False, _("list files from all revisions"))],
4258 ('', 'all', False, _("list files from all revisions"))],
4261 _('[-r REV]'))
4259 _('[-r REV]'))
4262 def manifest(ui, repo, node=None, rev=None, **opts):
4260 def manifest(ui, repo, node=None, rev=None, **opts):
4263 """output the current or given revision of the project manifest
4261 """output the current or given revision of the project manifest
4264
4262
4265 Print a list of version controlled files for the given revision.
4263 Print a list of version controlled files for the given revision.
4266 If no revision is given, the first parent of the working directory
4264 If no revision is given, the first parent of the working directory
4267 is used, or the null revision if no revision is checked out.
4265 is used, or the null revision if no revision is checked out.
4268
4266
4269 With -v, print file permissions, symlink and executable bits.
4267 With -v, print file permissions, symlink and executable bits.
4270 With --debug, print file revision hashes.
4268 With --debug, print file revision hashes.
4271
4269
4272 If option --all is specified, the list of all files from all revisions
4270 If option --all is specified, the list of all files from all revisions
4273 is printed. This includes deleted and renamed files.
4271 is printed. This includes deleted and renamed files.
4274
4272
4275 Returns 0 on success.
4273 Returns 0 on success.
4276 """
4274 """
4277
4275
4278 fm = ui.formatter('manifest', opts)
4276 fm = ui.formatter('manifest', opts)
4279
4277
4280 if opts.get('all'):
4278 if opts.get('all'):
4281 if rev or node:
4279 if rev or node:
4282 raise util.Abort(_("can't specify a revision with --all"))
4280 raise util.Abort(_("can't specify a revision with --all"))
4283
4281
4284 res = []
4282 res = []
4285 prefix = "data/"
4283 prefix = "data/"
4286 suffix = ".i"
4284 suffix = ".i"
4287 plen = len(prefix)
4285 plen = len(prefix)
4288 slen = len(suffix)
4286 slen = len(suffix)
4289 lock = repo.lock()
4287 lock = repo.lock()
4290 try:
4288 try:
4291 for fn, b, size in repo.store.datafiles():
4289 for fn, b, size in repo.store.datafiles():
4292 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4293 res.append(fn[plen:-slen])
4291 res.append(fn[plen:-slen])
4294 finally:
4292 finally:
4295 lock.release()
4293 lock.release()
4296 for f in res:
4294 for f in res:
4297 fm.startitem()
4295 fm.startitem()
4298 fm.write("path", '%s\n', f)
4296 fm.write("path", '%s\n', f)
4299 fm.end()
4297 fm.end()
4300 return
4298 return
4301
4299
4302 if rev and node:
4300 if rev and node:
4303 raise util.Abort(_("please specify just one revision"))
4301 raise util.Abort(_("please specify just one revision"))
4304
4302
4305 if not node:
4303 if not node:
4306 node = rev
4304 node = rev
4307
4305
4308 char = {'l': '@', 'x': '*', '': ''}
4306 char = {'l': '@', 'x': '*', '': ''}
4309 mode = {'l': '644', 'x': '755', '': '644'}
4307 mode = {'l': '644', 'x': '755', '': '644'}
4310 ctx = scmutil.revsingle(repo, node)
4308 ctx = scmutil.revsingle(repo, node)
4311 mf = ctx.manifest()
4309 mf = ctx.manifest()
4312 for f in ctx:
4310 for f in ctx:
4313 fm.startitem()
4311 fm.startitem()
4314 fl = ctx[f].flags()
4312 fl = ctx[f].flags()
4315 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4313 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4316 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4314 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4317 fm.write('path', '%s\n', f)
4315 fm.write('path', '%s\n', f)
4318 fm.end()
4316 fm.end()
4319
4317
4320 @command('^merge',
4318 @command('^merge',
4321 [('f', 'force', None, _('force a merge with outstanding changes')),
4319 [('f', 'force', None, _('force a merge with outstanding changes')),
4322 ('r', 'rev', '', _('revision to merge'), _('REV')),
4320 ('r', 'rev', '', _('revision to merge'), _('REV')),
4323 ('P', 'preview', None,
4321 ('P', 'preview', None,
4324 _('review revisions to merge (no merge is performed)'))
4322 _('review revisions to merge (no merge is performed)'))
4325 ] + mergetoolopts,
4323 ] + mergetoolopts,
4326 _('[-P] [-f] [[-r] REV]'))
4324 _('[-P] [-f] [[-r] REV]'))
4327 def merge(ui, repo, node=None, **opts):
4325 def merge(ui, repo, node=None, **opts):
4328 """merge working directory with another revision
4326 """merge working directory with another revision
4329
4327
4330 The current working directory is updated with all changes made in
4328 The current working directory is updated with all changes made in
4331 the requested revision since the last common predecessor revision.
4329 the requested revision since the last common predecessor revision.
4332
4330
4333 Files that changed between either parent are marked as changed for
4331 Files that changed between either parent are marked as changed for
4334 the next commit and a commit must be performed before any further
4332 the next commit and a commit must be performed before any further
4335 updates to the repository are allowed. The next commit will have
4333 updates to the repository are allowed. The next commit will have
4336 two parents.
4334 two parents.
4337
4335
4338 ``--tool`` can be used to specify the merge tool used for file
4336 ``--tool`` can be used to specify the merge tool used for file
4339 merges. It overrides the HGMERGE environment variable and your
4337 merges. It overrides the HGMERGE environment variable and your
4340 configuration files. See :hg:`help merge-tools` for options.
4338 configuration files. See :hg:`help merge-tools` for options.
4341
4339
4342 If no revision is specified, the working directory's parent is a
4340 If no revision is specified, the working directory's parent is a
4343 head revision, and the current branch contains exactly one other
4341 head revision, and the current branch contains exactly one other
4344 head, the other head is merged with by default. Otherwise, an
4342 head, the other head is merged with by default. Otherwise, an
4345 explicit revision with which to merge with must be provided.
4343 explicit revision with which to merge with must be provided.
4346
4344
4347 :hg:`resolve` must be used to resolve unresolved files.
4345 :hg:`resolve` must be used to resolve unresolved files.
4348
4346
4349 To undo an uncommitted merge, use :hg:`update --clean .` which
4347 To undo an uncommitted merge, use :hg:`update --clean .` which
4350 will check out a clean copy of the original merge parent, losing
4348 will check out a clean copy of the original merge parent, losing
4351 all changes.
4349 all changes.
4352
4350
4353 Returns 0 on success, 1 if there are unresolved files.
4351 Returns 0 on success, 1 if there are unresolved files.
4354 """
4352 """
4355
4353
4356 if opts.get('rev') and node:
4354 if opts.get('rev') and node:
4357 raise util.Abort(_("please specify just one revision"))
4355 raise util.Abort(_("please specify just one revision"))
4358 if not node:
4356 if not node:
4359 node = opts.get('rev')
4357 node = opts.get('rev')
4360
4358
4361 if node:
4359 if node:
4362 node = scmutil.revsingle(repo, node).node()
4360 node = scmutil.revsingle(repo, node).node()
4363
4361
4364 if not node and repo._bookmarkcurrent:
4362 if not node and repo._bookmarkcurrent:
4365 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4363 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4366 curhead = repo[repo._bookmarkcurrent].node()
4364 curhead = repo[repo._bookmarkcurrent].node()
4367 if len(bmheads) == 2:
4365 if len(bmheads) == 2:
4368 if curhead == bmheads[0]:
4366 if curhead == bmheads[0]:
4369 node = bmheads[1]
4367 node = bmheads[1]
4370 else:
4368 else:
4371 node = bmheads[0]
4369 node = bmheads[0]
4372 elif len(bmheads) > 2:
4370 elif len(bmheads) > 2:
4373 raise util.Abort(_("multiple matching bookmarks to merge - "
4371 raise util.Abort(_("multiple matching bookmarks to merge - "
4374 "please merge with an explicit rev or bookmark"),
4372 "please merge with an explicit rev or bookmark"),
4375 hint=_("run 'hg heads' to see all heads"))
4373 hint=_("run 'hg heads' to see all heads"))
4376 elif len(bmheads) <= 1:
4374 elif len(bmheads) <= 1:
4377 raise util.Abort(_("no matching bookmark to merge - "
4375 raise util.Abort(_("no matching bookmark to merge - "
4378 "please merge with an explicit rev or bookmark"),
4376 "please merge with an explicit rev or bookmark"),
4379 hint=_("run 'hg heads' to see all heads"))
4377 hint=_("run 'hg heads' to see all heads"))
4380
4378
4381 if not node and not repo._bookmarkcurrent:
4379 if not node and not repo._bookmarkcurrent:
4382 branch = repo[None].branch()
4380 branch = repo[None].branch()
4383 bheads = repo.branchheads(branch)
4381 bheads = repo.branchheads(branch)
4384 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4382 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4385
4383
4386 if len(nbhs) > 2:
4384 if len(nbhs) > 2:
4387 raise util.Abort(_("branch '%s' has %d heads - "
4385 raise util.Abort(_("branch '%s' has %d heads - "
4388 "please merge with an explicit rev")
4386 "please merge with an explicit rev")
4389 % (branch, len(bheads)),
4387 % (branch, len(bheads)),
4390 hint=_("run 'hg heads .' to see heads"))
4388 hint=_("run 'hg heads .' to see heads"))
4391
4389
4392 parent = repo.dirstate.p1()
4390 parent = repo.dirstate.p1()
4393 if len(nbhs) <= 1:
4391 if len(nbhs) <= 1:
4394 if len(bheads) > 1:
4392 if len(bheads) > 1:
4395 raise util.Abort(_("heads are bookmarked - "
4393 raise util.Abort(_("heads are bookmarked - "
4396 "please merge with an explicit rev"),
4394 "please merge with an explicit rev"),
4397 hint=_("run 'hg heads' to see all heads"))
4395 hint=_("run 'hg heads' to see all heads"))
4398 if len(repo.heads()) > 1:
4396 if len(repo.heads()) > 1:
4399 raise util.Abort(_("branch '%s' has one head - "
4397 raise util.Abort(_("branch '%s' has one head - "
4400 "please merge with an explicit rev")
4398 "please merge with an explicit rev")
4401 % branch,
4399 % branch,
4402 hint=_("run 'hg heads' to see all heads"))
4400 hint=_("run 'hg heads' to see all heads"))
4403 msg, hint = _('nothing to merge'), None
4401 msg, hint = _('nothing to merge'), None
4404 if parent != repo.lookup(branch):
4402 if parent != repo.lookup(branch):
4405 hint = _("use 'hg update' instead")
4403 hint = _("use 'hg update' instead")
4406 raise util.Abort(msg, hint=hint)
4404 raise util.Abort(msg, hint=hint)
4407
4405
4408 if parent not in bheads:
4406 if parent not in bheads:
4409 raise util.Abort(_('working directory not at a head revision'),
4407 raise util.Abort(_('working directory not at a head revision'),
4410 hint=_("use 'hg update' or merge with an "
4408 hint=_("use 'hg update' or merge with an "
4411 "explicit revision"))
4409 "explicit revision"))
4412 if parent == nbhs[0]:
4410 if parent == nbhs[0]:
4413 node = nbhs[-1]
4411 node = nbhs[-1]
4414 else:
4412 else:
4415 node = nbhs[0]
4413 node = nbhs[0]
4416
4414
4417 if opts.get('preview'):
4415 if opts.get('preview'):
4418 # find nodes that are ancestors of p2 but not of p1
4416 # find nodes that are ancestors of p2 but not of p1
4419 p1 = repo.lookup('.')
4417 p1 = repo.lookup('.')
4420 p2 = repo.lookup(node)
4418 p2 = repo.lookup(node)
4421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4419 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4422
4420
4423 displayer = cmdutil.show_changeset(ui, repo, opts)
4421 displayer = cmdutil.show_changeset(ui, repo, opts)
4424 for node in nodes:
4422 for node in nodes:
4425 displayer.show(repo[node])
4423 displayer.show(repo[node])
4426 displayer.close()
4424 displayer.close()
4427 return 0
4425 return 0
4428
4426
4429 try:
4427 try:
4430 # ui.forcemerge is an internal variable, do not document
4428 # ui.forcemerge is an internal variable, do not document
4431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4429 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4432 return hg.merge(repo, node, force=opts.get('force'))
4430 return hg.merge(repo, node, force=opts.get('force'))
4433 finally:
4431 finally:
4434 ui.setconfig('ui', 'forcemerge', '')
4432 ui.setconfig('ui', 'forcemerge', '')
4435
4433
4436 @command('outgoing|out',
4434 @command('outgoing|out',
4437 [('f', 'force', None, _('run even when the destination is unrelated')),
4435 [('f', 'force', None, _('run even when the destination is unrelated')),
4438 ('r', 'rev', [],
4436 ('r', 'rev', [],
4439 _('a changeset intended to be included in the destination'), _('REV')),
4437 _('a changeset intended to be included in the destination'), _('REV')),
4440 ('n', 'newest-first', None, _('show newest record first')),
4438 ('n', 'newest-first', None, _('show newest record first')),
4441 ('B', 'bookmarks', False, _('compare bookmarks')),
4439 ('B', 'bookmarks', False, _('compare bookmarks')),
4442 ('b', 'branch', [], _('a specific branch you would like to push'),
4440 ('b', 'branch', [], _('a specific branch you would like to push'),
4443 _('BRANCH')),
4441 _('BRANCH')),
4444 ] + logopts + remoteopts + subrepoopts,
4442 ] + logopts + remoteopts + subrepoopts,
4445 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4443 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4446 def outgoing(ui, repo, dest=None, **opts):
4444 def outgoing(ui, repo, dest=None, **opts):
4447 """show changesets not found in the destination
4445 """show changesets not found in the destination
4448
4446
4449 Show changesets not found in the specified destination repository
4447 Show changesets not found in the specified destination repository
4450 or the default push location. These are the changesets that would
4448 or the default push location. These are the changesets that would
4451 be pushed if a push was requested.
4449 be pushed if a push was requested.
4452
4450
4453 See pull for details of valid destination formats.
4451 See pull for details of valid destination formats.
4454
4452
4455 Returns 0 if there are outgoing changes, 1 otherwise.
4453 Returns 0 if there are outgoing changes, 1 otherwise.
4456 """
4454 """
4457 if opts.get('graph'):
4455 if opts.get('graph'):
4458 cmdutil.checkunsupportedgraphflags([], opts)
4456 cmdutil.checkunsupportedgraphflags([], opts)
4459 o = hg._outgoing(ui, repo, dest, opts)
4457 o = hg._outgoing(ui, repo, dest, opts)
4460 if o is None:
4458 if o is None:
4461 return
4459 return
4462
4460
4463 revdag = cmdutil.graphrevs(repo, o, opts)
4461 revdag = cmdutil.graphrevs(repo, o, opts)
4464 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4462 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4465 showparents = [ctx.node() for ctx in repo[None].parents()]
4463 showparents = [ctx.node() for ctx in repo[None].parents()]
4466 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4464 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4467 graphmod.asciiedges)
4465 graphmod.asciiedges)
4468 return 0
4466 return 0
4469
4467
4470 if opts.get('bookmarks'):
4468 if opts.get('bookmarks'):
4471 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4469 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4472 dest, branches = hg.parseurl(dest, opts.get('branch'))
4470 dest, branches = hg.parseurl(dest, opts.get('branch'))
4473 other = hg.peer(repo, opts, dest)
4471 other = hg.peer(repo, opts, dest)
4474 if 'bookmarks' not in other.listkeys('namespaces'):
4472 if 'bookmarks' not in other.listkeys('namespaces'):
4475 ui.warn(_("remote doesn't support bookmarks\n"))
4473 ui.warn(_("remote doesn't support bookmarks\n"))
4476 return 0
4474 return 0
4477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4475 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4478 return bookmarks.diff(ui, other, repo)
4476 return bookmarks.diff(ui, other, repo)
4479
4477
4480 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4478 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4481 try:
4479 try:
4482 return hg.outgoing(ui, repo, dest, opts)
4480 return hg.outgoing(ui, repo, dest, opts)
4483 finally:
4481 finally:
4484 del repo._subtoppath
4482 del repo._subtoppath
4485
4483
4486 @command('parents',
4484 @command('parents',
4487 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4485 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4488 ] + templateopts,
4486 ] + templateopts,
4489 _('[-r REV] [FILE]'))
4487 _('[-r REV] [FILE]'))
4490 def parents(ui, repo, file_=None, **opts):
4488 def parents(ui, repo, file_=None, **opts):
4491 """show the parents of the working directory or revision
4489 """show the parents of the working directory or revision
4492
4490
4493 Print the working directory's parent revisions. If a revision is
4491 Print the working directory's parent revisions. If a revision is
4494 given via -r/--rev, the parent of that revision will be printed.
4492 given via -r/--rev, the parent of that revision will be printed.
4495 If a file argument is given, the revision in which the file was
4493 If a file argument is given, the revision in which the file was
4496 last changed (before the working directory revision or the
4494 last changed (before the working directory revision or the
4497 argument to --rev if given) is printed.
4495 argument to --rev if given) is printed.
4498
4496
4499 Returns 0 on success.
4497 Returns 0 on success.
4500 """
4498 """
4501
4499
4502 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4500 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4503
4501
4504 if file_:
4502 if file_:
4505 m = scmutil.match(ctx, (file_,), opts)
4503 m = scmutil.match(ctx, (file_,), opts)
4506 if m.anypats() or len(m.files()) != 1:
4504 if m.anypats() or len(m.files()) != 1:
4507 raise util.Abort(_('can only specify an explicit filename'))
4505 raise util.Abort(_('can only specify an explicit filename'))
4508 file_ = m.files()[0]
4506 file_ = m.files()[0]
4509 filenodes = []
4507 filenodes = []
4510 for cp in ctx.parents():
4508 for cp in ctx.parents():
4511 if not cp:
4509 if not cp:
4512 continue
4510 continue
4513 try:
4511 try:
4514 filenodes.append(cp.filenode(file_))
4512 filenodes.append(cp.filenode(file_))
4515 except error.LookupError:
4513 except error.LookupError:
4516 pass
4514 pass
4517 if not filenodes:
4515 if not filenodes:
4518 raise util.Abort(_("'%s' not found in manifest!") % file_)
4516 raise util.Abort(_("'%s' not found in manifest!") % file_)
4519 fl = repo.file(file_)
4517 fl = repo.file(file_)
4520 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4518 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4521 else:
4519 else:
4522 p = [cp.node() for cp in ctx.parents()]
4520 p = [cp.node() for cp in ctx.parents()]
4523
4521
4524 displayer = cmdutil.show_changeset(ui, repo, opts)
4522 displayer = cmdutil.show_changeset(ui, repo, opts)
4525 for n in p:
4523 for n in p:
4526 if n != nullid:
4524 if n != nullid:
4527 displayer.show(repo[n])
4525 displayer.show(repo[n])
4528 displayer.close()
4526 displayer.close()
4529
4527
4530 @command('paths', [], _('[NAME]'))
4528 @command('paths', [], _('[NAME]'))
4531 def paths(ui, repo, search=None):
4529 def paths(ui, repo, search=None):
4532 """show aliases for remote repositories
4530 """show aliases for remote repositories
4533
4531
4534 Show definition of symbolic path name NAME. If no name is given,
4532 Show definition of symbolic path name NAME. If no name is given,
4535 show definition of all available names.
4533 show definition of all available names.
4536
4534
4537 Option -q/--quiet suppresses all output when searching for NAME
4535 Option -q/--quiet suppresses all output when searching for NAME
4538 and shows only the path names when listing all definitions.
4536 and shows only the path names when listing all definitions.
4539
4537
4540 Path names are defined in the [paths] section of your
4538 Path names are defined in the [paths] section of your
4541 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4539 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4542 repository, ``.hg/hgrc`` is used, too.
4540 repository, ``.hg/hgrc`` is used, too.
4543
4541
4544 The path names ``default`` and ``default-push`` have a special
4542 The path names ``default`` and ``default-push`` have a special
4545 meaning. When performing a push or pull operation, they are used
4543 meaning. When performing a push or pull operation, they are used
4546 as fallbacks if no location is specified on the command-line.
4544 as fallbacks if no location is specified on the command-line.
4547 When ``default-push`` is set, it will be used for push and
4545 When ``default-push`` is set, it will be used for push and
4548 ``default`` will be used for pull; otherwise ``default`` is used
4546 ``default`` will be used for pull; otherwise ``default`` is used
4549 as the fallback for both. When cloning a repository, the clone
4547 as the fallback for both. When cloning a repository, the clone
4550 source is written as ``default`` in ``.hg/hgrc``. Note that
4548 source is written as ``default`` in ``.hg/hgrc``. Note that
4551 ``default`` and ``default-push`` apply to all inbound (e.g.
4549 ``default`` and ``default-push`` apply to all inbound (e.g.
4552 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4550 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4553 :hg:`bundle`) operations.
4551 :hg:`bundle`) operations.
4554
4552
4555 See :hg:`help urls` for more information.
4553 See :hg:`help urls` for more information.
4556
4554
4557 Returns 0 on success.
4555 Returns 0 on success.
4558 """
4556 """
4559 if search:
4557 if search:
4560 for name, path in ui.configitems("paths"):
4558 for name, path in ui.configitems("paths"):
4561 if name == search:
4559 if name == search:
4562 ui.status("%s\n" % util.hidepassword(path))
4560 ui.status("%s\n" % util.hidepassword(path))
4563 return
4561 return
4564 if not ui.quiet:
4562 if not ui.quiet:
4565 ui.warn(_("not found!\n"))
4563 ui.warn(_("not found!\n"))
4566 return 1
4564 return 1
4567 else:
4565 else:
4568 for name, path in ui.configitems("paths"):
4566 for name, path in ui.configitems("paths"):
4569 if ui.quiet:
4567 if ui.quiet:
4570 ui.write("%s\n" % name)
4568 ui.write("%s\n" % name)
4571 else:
4569 else:
4572 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4570 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4573
4571
4574 @command('phase',
4572 @command('phase',
4575 [('p', 'public', False, _('set changeset phase to public')),
4573 [('p', 'public', False, _('set changeset phase to public')),
4576 ('d', 'draft', False, _('set changeset phase to draft')),
4574 ('d', 'draft', False, _('set changeset phase to draft')),
4577 ('s', 'secret', False, _('set changeset phase to secret')),
4575 ('s', 'secret', False, _('set changeset phase to secret')),
4578 ('f', 'force', False, _('allow to move boundary backward')),
4576 ('f', 'force', False, _('allow to move boundary backward')),
4579 ('r', 'rev', [], _('target revision'), _('REV')),
4577 ('r', 'rev', [], _('target revision'), _('REV')),
4580 ],
4578 ],
4581 _('[-p|-d|-s] [-f] [-r] REV...'))
4579 _('[-p|-d|-s] [-f] [-r] REV...'))
4582 def phase(ui, repo, *revs, **opts):
4580 def phase(ui, repo, *revs, **opts):
4583 """set or show the current phase name
4581 """set or show the current phase name
4584
4582
4585 With no argument, show the phase name of specified revisions.
4583 With no argument, show the phase name of specified revisions.
4586
4584
4587 With one of -p/--public, -d/--draft or -s/--secret, change the
4585 With one of -p/--public, -d/--draft or -s/--secret, change the
4588 phase value of the specified revisions.
4586 phase value of the specified revisions.
4589
4587
4590 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4588 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4591 lower phase to an higher phase. Phases are ordered as follows::
4589 lower phase to an higher phase. Phases are ordered as follows::
4592
4590
4593 public < draft < secret
4591 public < draft < secret
4594
4592
4595 Return 0 on success, 1 if no phases were changed or some could not
4593 Return 0 on success, 1 if no phases were changed or some could not
4596 be changed.
4594 be changed.
4597 """
4595 """
4598 # search for a unique phase argument
4596 # search for a unique phase argument
4599 targetphase = None
4597 targetphase = None
4600 for idx, name in enumerate(phases.phasenames):
4598 for idx, name in enumerate(phases.phasenames):
4601 if opts[name]:
4599 if opts[name]:
4602 if targetphase is not None:
4600 if targetphase is not None:
4603 raise util.Abort(_('only one phase can be specified'))
4601 raise util.Abort(_('only one phase can be specified'))
4604 targetphase = idx
4602 targetphase = idx
4605
4603
4606 # look for specified revision
4604 # look for specified revision
4607 revs = list(revs)
4605 revs = list(revs)
4608 revs.extend(opts['rev'])
4606 revs.extend(opts['rev'])
4609 if not revs:
4607 if not revs:
4610 raise util.Abort(_('no revisions specified'))
4608 raise util.Abort(_('no revisions specified'))
4611
4609
4612 revs = scmutil.revrange(repo, revs)
4610 revs = scmutil.revrange(repo, revs)
4613
4611
4614 lock = None
4612 lock = None
4615 ret = 0
4613 ret = 0
4616 if targetphase is None:
4614 if targetphase is None:
4617 # display
4615 # display
4618 for r in revs:
4616 for r in revs:
4619 ctx = repo[r]
4617 ctx = repo[r]
4620 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4618 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4621 else:
4619 else:
4622 lock = repo.lock()
4620 lock = repo.lock()
4623 try:
4621 try:
4624 # set phase
4622 # set phase
4625 if not revs:
4623 if not revs:
4626 raise util.Abort(_('empty revision set'))
4624 raise util.Abort(_('empty revision set'))
4627 nodes = [repo[r].node() for r in revs]
4625 nodes = [repo[r].node() for r in revs]
4628 olddata = repo._phasecache.getphaserevs(repo)[:]
4626 olddata = repo._phasecache.getphaserevs(repo)[:]
4629 phases.advanceboundary(repo, targetphase, nodes)
4627 phases.advanceboundary(repo, targetphase, nodes)
4630 if opts['force']:
4628 if opts['force']:
4631 phases.retractboundary(repo, targetphase, nodes)
4629 phases.retractboundary(repo, targetphase, nodes)
4632 finally:
4630 finally:
4633 lock.release()
4631 lock.release()
4634 # moving revision from public to draft may hide them
4632 # moving revision from public to draft may hide them
4635 # We have to check result on an unfiltered repository
4633 # We have to check result on an unfiltered repository
4636 unfi = repo.unfiltered()
4634 unfi = repo.unfiltered()
4637 newdata = repo._phasecache.getphaserevs(unfi)
4635 newdata = repo._phasecache.getphaserevs(unfi)
4638 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4636 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4639 cl = unfi.changelog
4637 cl = unfi.changelog
4640 rejected = [n for n in nodes
4638 rejected = [n for n in nodes
4641 if newdata[cl.rev(n)] < targetphase]
4639 if newdata[cl.rev(n)] < targetphase]
4642 if rejected:
4640 if rejected:
4643 ui.warn(_('cannot move %i changesets to a more permissive '
4641 ui.warn(_('cannot move %i changesets to a more permissive '
4644 'phase, use --force\n') % len(rejected))
4642 'phase, use --force\n') % len(rejected))
4645 ret = 1
4643 ret = 1
4646 if changes:
4644 if changes:
4647 msg = _('phase changed for %i changesets\n') % changes
4645 msg = _('phase changed for %i changesets\n') % changes
4648 if ret:
4646 if ret:
4649 ui.status(msg)
4647 ui.status(msg)
4650 else:
4648 else:
4651 ui.note(msg)
4649 ui.note(msg)
4652 else:
4650 else:
4653 ui.warn(_('no phases changed\n'))
4651 ui.warn(_('no phases changed\n'))
4654 ret = 1
4652 ret = 1
4655 return ret
4653 return ret
4656
4654
4657 def postincoming(ui, repo, modheads, optupdate, checkout):
4655 def postincoming(ui, repo, modheads, optupdate, checkout):
4658 if modheads == 0:
4656 if modheads == 0:
4659 return
4657 return
4660 if optupdate:
4658 if optupdate:
4661 movemarkfrom = repo['.'].node()
4659 movemarkfrom = repo['.'].node()
4662 try:
4660 try:
4663 ret = hg.update(repo, checkout)
4661 ret = hg.update(repo, checkout)
4664 except util.Abort, inst:
4662 except util.Abort, inst:
4665 ui.warn(_("not updating: %s\n") % str(inst))
4663 ui.warn(_("not updating: %s\n") % str(inst))
4666 return 0
4664 return 0
4667 if not ret and not checkout:
4665 if not ret and not checkout:
4668 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4666 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4669 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4667 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4670 return ret
4668 return ret
4671 if modheads > 1:
4669 if modheads > 1:
4672 currentbranchheads = len(repo.branchheads())
4670 currentbranchheads = len(repo.branchheads())
4673 if currentbranchheads == modheads:
4671 if currentbranchheads == modheads:
4674 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4672 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4675 elif currentbranchheads > 1:
4673 elif currentbranchheads > 1:
4676 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4674 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4677 "merge)\n"))
4675 "merge)\n"))
4678 else:
4676 else:
4679 ui.status(_("(run 'hg heads' to see heads)\n"))
4677 ui.status(_("(run 'hg heads' to see heads)\n"))
4680 else:
4678 else:
4681 ui.status(_("(run 'hg update' to get a working copy)\n"))
4679 ui.status(_("(run 'hg update' to get a working copy)\n"))
4682
4680
4683 @command('^pull',
4681 @command('^pull',
4684 [('u', 'update', None,
4682 [('u', 'update', None,
4685 _('update to new branch head if changesets were pulled')),
4683 _('update to new branch head if changesets were pulled')),
4686 ('f', 'force', None, _('run even when remote repository is unrelated')),
4684 ('f', 'force', None, _('run even when remote repository is unrelated')),
4687 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4685 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4688 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4686 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4689 ('b', 'branch', [], _('a specific branch you would like to pull'),
4687 ('b', 'branch', [], _('a specific branch you would like to pull'),
4690 _('BRANCH')),
4688 _('BRANCH')),
4691 ] + remoteopts,
4689 ] + remoteopts,
4692 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4690 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4693 def pull(ui, repo, source="default", **opts):
4691 def pull(ui, repo, source="default", **opts):
4694 """pull changes from the specified source
4692 """pull changes from the specified source
4695
4693
4696 Pull changes from a remote repository to a local one.
4694 Pull changes from a remote repository to a local one.
4697
4695
4698 This finds all changes from the repository at the specified path
4696 This finds all changes from the repository at the specified path
4699 or URL and adds them to a local repository (the current one unless
4697 or URL and adds them to a local repository (the current one unless
4700 -R is specified). By default, this does not update the copy of the
4698 -R is specified). By default, this does not update the copy of the
4701 project in the working directory.
4699 project in the working directory.
4702
4700
4703 Use :hg:`incoming` if you want to see what would have been added
4701 Use :hg:`incoming` if you want to see what would have been added
4704 by a pull at the time you issued this command. If you then decide
4702 by a pull at the time you issued this command. If you then decide
4705 to add those changes to the repository, you should use :hg:`pull
4703 to add those changes to the repository, you should use :hg:`pull
4706 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4704 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4707
4705
4708 If SOURCE is omitted, the 'default' path will be used.
4706 If SOURCE is omitted, the 'default' path will be used.
4709 See :hg:`help urls` for more information.
4707 See :hg:`help urls` for more information.
4710
4708
4711 Returns 0 on success, 1 if an update had unresolved files.
4709 Returns 0 on success, 1 if an update had unresolved files.
4712 """
4710 """
4713 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4711 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4714 other = hg.peer(repo, opts, source)
4712 other = hg.peer(repo, opts, source)
4715 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4713 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4716 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4714 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4717
4715
4718 if opts.get('bookmark'):
4716 if opts.get('bookmark'):
4719 if not revs:
4717 if not revs:
4720 revs = []
4718 revs = []
4721 rb = other.listkeys('bookmarks')
4719 rb = other.listkeys('bookmarks')
4722 for b in opts['bookmark']:
4720 for b in opts['bookmark']:
4723 if b not in rb:
4721 if b not in rb:
4724 raise util.Abort(_('remote bookmark %s not found!') % b)
4722 raise util.Abort(_('remote bookmark %s not found!') % b)
4725 revs.append(rb[b])
4723 revs.append(rb[b])
4726
4724
4727 if revs:
4725 if revs:
4728 try:
4726 try:
4729 revs = [other.lookup(rev) for rev in revs]
4727 revs = [other.lookup(rev) for rev in revs]
4730 except error.CapabilityError:
4728 except error.CapabilityError:
4731 err = _("other repository doesn't support revision lookup, "
4729 err = _("other repository doesn't support revision lookup, "
4732 "so a rev cannot be specified.")
4730 "so a rev cannot be specified.")
4733 raise util.Abort(err)
4731 raise util.Abort(err)
4734
4732
4735 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4733 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4736 bookmarks.updatefromremote(ui, repo, other, source)
4734 bookmarks.updatefromremote(ui, repo, other, source)
4737 if checkout:
4735 if checkout:
4738 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4736 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4739 repo._subtoppath = source
4737 repo._subtoppath = source
4740 try:
4738 try:
4741 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4739 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4742
4740
4743 finally:
4741 finally:
4744 del repo._subtoppath
4742 del repo._subtoppath
4745
4743
4746 # update specified bookmarks
4744 # update specified bookmarks
4747 if opts.get('bookmark'):
4745 if opts.get('bookmark'):
4748 marks = repo._bookmarks
4746 marks = repo._bookmarks
4749 for b in opts['bookmark']:
4747 for b in opts['bookmark']:
4750 # explicit pull overrides local bookmark if any
4748 # explicit pull overrides local bookmark if any
4751 ui.status(_("importing bookmark %s\n") % b)
4749 ui.status(_("importing bookmark %s\n") % b)
4752 marks[b] = repo[rb[b]].node()
4750 marks[b] = repo[rb[b]].node()
4753 marks.write()
4751 marks.write()
4754
4752
4755 return ret
4753 return ret
4756
4754
4757 @command('^push',
4755 @command('^push',
4758 [('f', 'force', None, _('force push')),
4756 [('f', 'force', None, _('force push')),
4759 ('r', 'rev', [],
4757 ('r', 'rev', [],
4760 _('a changeset intended to be included in the destination'),
4758 _('a changeset intended to be included in the destination'),
4761 _('REV')),
4759 _('REV')),
4762 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4760 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4763 ('b', 'branch', [],
4761 ('b', 'branch', [],
4764 _('a specific branch you would like to push'), _('BRANCH')),
4762 _('a specific branch you would like to push'), _('BRANCH')),
4765 ('', 'new-branch', False, _('allow pushing a new branch')),
4763 ('', 'new-branch', False, _('allow pushing a new branch')),
4766 ] + remoteopts,
4764 ] + remoteopts,
4767 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4765 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4768 def push(ui, repo, dest=None, **opts):
4766 def push(ui, repo, dest=None, **opts):
4769 """push changes to the specified destination
4767 """push changes to the specified destination
4770
4768
4771 Push changesets from the local repository to the specified
4769 Push changesets from the local repository to the specified
4772 destination.
4770 destination.
4773
4771
4774 This operation is symmetrical to pull: it is identical to a pull
4772 This operation is symmetrical to pull: it is identical to a pull
4775 in the destination repository from the current one.
4773 in the destination repository from the current one.
4776
4774
4777 By default, push will not allow creation of new heads at the
4775 By default, push will not allow creation of new heads at the
4778 destination, since multiple heads would make it unclear which head
4776 destination, since multiple heads would make it unclear which head
4779 to use. In this situation, it is recommended to pull and merge
4777 to use. In this situation, it is recommended to pull and merge
4780 before pushing.
4778 before pushing.
4781
4779
4782 Use --new-branch if you want to allow push to create a new named
4780 Use --new-branch if you want to allow push to create a new named
4783 branch that is not present at the destination. This allows you to
4781 branch that is not present at the destination. This allows you to
4784 only create a new branch without forcing other changes.
4782 only create a new branch without forcing other changes.
4785
4783
4786 Use -f/--force to override the default behavior and push all
4784 Use -f/--force to override the default behavior and push all
4787 changesets on all branches.
4785 changesets on all branches.
4788
4786
4789 If -r/--rev is used, the specified revision and all its ancestors
4787 If -r/--rev is used, the specified revision and all its ancestors
4790 will be pushed to the remote repository.
4788 will be pushed to the remote repository.
4791
4789
4792 If -B/--bookmark is used, the specified bookmarked revision, its
4790 If -B/--bookmark is used, the specified bookmarked revision, its
4793 ancestors, and the bookmark will be pushed to the remote
4791 ancestors, and the bookmark will be pushed to the remote
4794 repository.
4792 repository.
4795
4793
4796 Please see :hg:`help urls` for important details about ``ssh://``
4794 Please see :hg:`help urls` for important details about ``ssh://``
4797 URLs. If DESTINATION is omitted, a default path will be used.
4795 URLs. If DESTINATION is omitted, a default path will be used.
4798
4796
4799 Returns 0 if push was successful, 1 if nothing to push.
4797 Returns 0 if push was successful, 1 if nothing to push.
4800 """
4798 """
4801
4799
4802 if opts.get('bookmark'):
4800 if opts.get('bookmark'):
4803 for b in opts['bookmark']:
4801 for b in opts['bookmark']:
4804 # translate -B options to -r so changesets get pushed
4802 # translate -B options to -r so changesets get pushed
4805 if b in repo._bookmarks:
4803 if b in repo._bookmarks:
4806 opts.setdefault('rev', []).append(b)
4804 opts.setdefault('rev', []).append(b)
4807 else:
4805 else:
4808 # if we try to push a deleted bookmark, translate it to null
4806 # if we try to push a deleted bookmark, translate it to null
4809 # this lets simultaneous -r, -b options continue working
4807 # this lets simultaneous -r, -b options continue working
4810 opts.setdefault('rev', []).append("null")
4808 opts.setdefault('rev', []).append("null")
4811
4809
4812 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4810 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4813 dest, branches = hg.parseurl(dest, opts.get('branch'))
4811 dest, branches = hg.parseurl(dest, opts.get('branch'))
4814 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4812 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4815 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4813 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4816 other = hg.peer(repo, opts, dest)
4814 other = hg.peer(repo, opts, dest)
4817 if revs:
4815 if revs:
4818 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4816 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4819
4817
4820 repo._subtoppath = dest
4818 repo._subtoppath = dest
4821 try:
4819 try:
4822 # push subrepos depth-first for coherent ordering
4820 # push subrepos depth-first for coherent ordering
4823 c = repo['']
4821 c = repo['']
4824 subs = c.substate # only repos that are committed
4822 subs = c.substate # only repos that are committed
4825 for s in sorted(subs):
4823 for s in sorted(subs):
4826 if c.sub(s).push(opts) == 0:
4824 if c.sub(s).push(opts) == 0:
4827 return False
4825 return False
4828 finally:
4826 finally:
4829 del repo._subtoppath
4827 del repo._subtoppath
4830 result = repo.push(other, opts.get('force'), revs=revs,
4828 result = repo.push(other, opts.get('force'), revs=revs,
4831 newbranch=opts.get('new_branch'))
4829 newbranch=opts.get('new_branch'))
4832
4830
4833 result = not result
4831 result = not result
4834
4832
4835 if opts.get('bookmark'):
4833 if opts.get('bookmark'):
4836 rb = other.listkeys('bookmarks')
4834 rb = other.listkeys('bookmarks')
4837 for b in opts['bookmark']:
4835 for b in opts['bookmark']:
4838 # explicit push overrides remote bookmark if any
4836 # explicit push overrides remote bookmark if any
4839 if b in repo._bookmarks:
4837 if b in repo._bookmarks:
4840 ui.status(_("exporting bookmark %s\n") % b)
4838 ui.status(_("exporting bookmark %s\n") % b)
4841 new = repo[b].hex()
4839 new = repo[b].hex()
4842 elif b in rb:
4840 elif b in rb:
4843 ui.status(_("deleting remote bookmark %s\n") % b)
4841 ui.status(_("deleting remote bookmark %s\n") % b)
4844 new = '' # delete
4842 new = '' # delete
4845 else:
4843 else:
4846 ui.warn(_('bookmark %s does not exist on the local '
4844 ui.warn(_('bookmark %s does not exist on the local '
4847 'or remote repository!\n') % b)
4845 'or remote repository!\n') % b)
4848 return 2
4846 return 2
4849 old = rb.get(b, '')
4847 old = rb.get(b, '')
4850 r = other.pushkey('bookmarks', b, old, new)
4848 r = other.pushkey('bookmarks', b, old, new)
4851 if not r:
4849 if not r:
4852 ui.warn(_('updating bookmark %s failed!\n') % b)
4850 ui.warn(_('updating bookmark %s failed!\n') % b)
4853 if not result:
4851 if not result:
4854 result = 2
4852 result = 2
4855
4853
4856 return result
4854 return result
4857
4855
4858 @command('recover', [])
4856 @command('recover', [])
4859 def recover(ui, repo):
4857 def recover(ui, repo):
4860 """roll back an interrupted transaction
4858 """roll back an interrupted transaction
4861
4859
4862 Recover from an interrupted commit or pull.
4860 Recover from an interrupted commit or pull.
4863
4861
4864 This command tries to fix the repository status after an
4862 This command tries to fix the repository status after an
4865 interrupted operation. It should only be necessary when Mercurial
4863 interrupted operation. It should only be necessary when Mercurial
4866 suggests it.
4864 suggests it.
4867
4865
4868 Returns 0 if successful, 1 if nothing to recover or verify fails.
4866 Returns 0 if successful, 1 if nothing to recover or verify fails.
4869 """
4867 """
4870 if repo.recover():
4868 if repo.recover():
4871 return hg.verify(repo)
4869 return hg.verify(repo)
4872 return 1
4870 return 1
4873
4871
4874 @command('^remove|rm',
4872 @command('^remove|rm',
4875 [('A', 'after', None, _('record delete for missing files')),
4873 [('A', 'after', None, _('record delete for missing files')),
4876 ('f', 'force', None,
4874 ('f', 'force', None,
4877 _('remove (and delete) file even if added or modified')),
4875 _('remove (and delete) file even if added or modified')),
4878 ] + walkopts,
4876 ] + walkopts,
4879 _('[OPTION]... FILE...'))
4877 _('[OPTION]... FILE...'))
4880 def remove(ui, repo, *pats, **opts):
4878 def remove(ui, repo, *pats, **opts):
4881 """remove the specified files on the next commit
4879 """remove the specified files on the next commit
4882
4880
4883 Schedule the indicated files for removal from the current branch.
4881 Schedule the indicated files for removal from the current branch.
4884
4882
4885 This command schedules the files to be removed at the next commit.
4883 This command schedules the files to be removed at the next commit.
4886 To undo a remove before that, see :hg:`revert`. To undo added
4884 To undo a remove before that, see :hg:`revert`. To undo added
4887 files, see :hg:`forget`.
4885 files, see :hg:`forget`.
4888
4886
4889 .. container:: verbose
4887 .. container:: verbose
4890
4888
4891 -A/--after can be used to remove only files that have already
4889 -A/--after can be used to remove only files that have already
4892 been deleted, -f/--force can be used to force deletion, and -Af
4890 been deleted, -f/--force can be used to force deletion, and -Af
4893 can be used to remove files from the next revision without
4891 can be used to remove files from the next revision without
4894 deleting them from the working directory.
4892 deleting them from the working directory.
4895
4893
4896 The following table details the behavior of remove for different
4894 The following table details the behavior of remove for different
4897 file states (columns) and option combinations (rows). The file
4895 file states (columns) and option combinations (rows). The file
4898 states are Added [A], Clean [C], Modified [M] and Missing [!]
4896 states are Added [A], Clean [C], Modified [M] and Missing [!]
4899 (as reported by :hg:`status`). The actions are Warn, Remove
4897 (as reported by :hg:`status`). The actions are Warn, Remove
4900 (from branch) and Delete (from disk):
4898 (from branch) and Delete (from disk):
4901
4899
4902 ======= == == == ==
4900 ======= == == == ==
4903 A C M !
4901 A C M !
4904 ======= == == == ==
4902 ======= == == == ==
4905 none W RD W R
4903 none W RD W R
4906 -f R RD RD R
4904 -f R RD RD R
4907 -A W W W R
4905 -A W W W R
4908 -Af R R R R
4906 -Af R R R R
4909 ======= == == == ==
4907 ======= == == == ==
4910
4908
4911 Note that remove never deletes files in Added [A] state from the
4909 Note that remove never deletes files in Added [A] state from the
4912 working directory, not even if option --force is specified.
4910 working directory, not even if option --force is specified.
4913
4911
4914 Returns 0 on success, 1 if any warnings encountered.
4912 Returns 0 on success, 1 if any warnings encountered.
4915 """
4913 """
4916
4914
4917 ret = 0
4915 ret = 0
4918 after, force = opts.get('after'), opts.get('force')
4916 after, force = opts.get('after'), opts.get('force')
4919 if not pats and not after:
4917 if not pats and not after:
4920 raise util.Abort(_('no files specified'))
4918 raise util.Abort(_('no files specified'))
4921
4919
4922 m = scmutil.match(repo[None], pats, opts)
4920 m = scmutil.match(repo[None], pats, opts)
4923 s = repo.status(match=m, clean=True)
4921 s = repo.status(match=m, clean=True)
4924 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4922 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4925
4923
4926 # warn about failure to delete explicit files/dirs
4924 # warn about failure to delete explicit files/dirs
4927 wctx = repo[None]
4925 wctx = repo[None]
4928 for f in m.files():
4926 for f in m.files():
4929 if f in repo.dirstate or f in wctx.dirs():
4927 if f in repo.dirstate or f in wctx.dirs():
4930 continue
4928 continue
4931 if os.path.exists(m.rel(f)):
4929 if os.path.exists(m.rel(f)):
4932 if os.path.isdir(m.rel(f)):
4930 if os.path.isdir(m.rel(f)):
4933 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4931 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4934 else:
4932 else:
4935 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4933 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4936 # missing files will generate a warning elsewhere
4934 # missing files will generate a warning elsewhere
4937 ret = 1
4935 ret = 1
4938
4936
4939 if force:
4937 if force:
4940 list = modified + deleted + clean + added
4938 list = modified + deleted + clean + added
4941 elif after:
4939 elif after:
4942 list = deleted
4940 list = deleted
4943 for f in modified + added + clean:
4941 for f in modified + added + clean:
4944 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4942 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4945 ret = 1
4943 ret = 1
4946 else:
4944 else:
4947 list = deleted + clean
4945 list = deleted + clean
4948 for f in modified:
4946 for f in modified:
4949 ui.warn(_('not removing %s: file is modified (use -f'
4947 ui.warn(_('not removing %s: file is modified (use -f'
4950 ' to force removal)\n') % m.rel(f))
4948 ' to force removal)\n') % m.rel(f))
4951 ret = 1
4949 ret = 1
4952 for f in added:
4950 for f in added:
4953 ui.warn(_('not removing %s: file has been marked for add'
4951 ui.warn(_('not removing %s: file has been marked for add'
4954 ' (use forget to undo)\n') % m.rel(f))
4952 ' (use forget to undo)\n') % m.rel(f))
4955 ret = 1
4953 ret = 1
4956
4954
4957 for f in sorted(list):
4955 for f in sorted(list):
4958 if ui.verbose or not m.exact(f):
4956 if ui.verbose or not m.exact(f):
4959 ui.status(_('removing %s\n') % m.rel(f))
4957 ui.status(_('removing %s\n') % m.rel(f))
4960
4958
4961 wlock = repo.wlock()
4959 wlock = repo.wlock()
4962 try:
4960 try:
4963 if not after:
4961 if not after:
4964 for f in list:
4962 for f in list:
4965 if f in added:
4963 if f in added:
4966 continue # we never unlink added files on remove
4964 continue # we never unlink added files on remove
4967 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4965 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4968 repo[None].forget(list)
4966 repo[None].forget(list)
4969 finally:
4967 finally:
4970 wlock.release()
4968 wlock.release()
4971
4969
4972 return ret
4970 return ret
4973
4971
4974 @command('rename|move|mv',
4972 @command('rename|move|mv',
4975 [('A', 'after', None, _('record a rename that has already occurred')),
4973 [('A', 'after', None, _('record a rename that has already occurred')),
4976 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4974 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4977 ] + walkopts + dryrunopts,
4975 ] + walkopts + dryrunopts,
4978 _('[OPTION]... SOURCE... DEST'))
4976 _('[OPTION]... SOURCE... DEST'))
4979 def rename(ui, repo, *pats, **opts):
4977 def rename(ui, repo, *pats, **opts):
4980 """rename files; equivalent of copy + remove
4978 """rename files; equivalent of copy + remove
4981
4979
4982 Mark dest as copies of sources; mark sources for deletion. If dest
4980 Mark dest as copies of sources; mark sources for deletion. If dest
4983 is a directory, copies are put in that directory. If dest is a
4981 is a directory, copies are put in that directory. If dest is a
4984 file, there can only be one source.
4982 file, there can only be one source.
4985
4983
4986 By default, this command copies the contents of files as they
4984 By default, this command copies the contents of files as they
4987 exist in the working directory. If invoked with -A/--after, the
4985 exist in the working directory. If invoked with -A/--after, the
4988 operation is recorded, but no copying is performed.
4986 operation is recorded, but no copying is performed.
4989
4987
4990 This command takes effect at the next commit. To undo a rename
4988 This command takes effect at the next commit. To undo a rename
4991 before that, see :hg:`revert`.
4989 before that, see :hg:`revert`.
4992
4990
4993 Returns 0 on success, 1 if errors are encountered.
4991 Returns 0 on success, 1 if errors are encountered.
4994 """
4992 """
4995 wlock = repo.wlock(False)
4993 wlock = repo.wlock(False)
4996 try:
4994 try:
4997 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4995 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4998 finally:
4996 finally:
4999 wlock.release()
4997 wlock.release()
5000
4998
5001 @command('resolve',
4999 @command('resolve',
5002 [('a', 'all', None, _('select all unresolved files')),
5000 [('a', 'all', None, _('select all unresolved files')),
5003 ('l', 'list', None, _('list state of files needing merge')),
5001 ('l', 'list', None, _('list state of files needing merge')),
5004 ('m', 'mark', None, _('mark files as resolved')),
5002 ('m', 'mark', None, _('mark files as resolved')),
5005 ('u', 'unmark', None, _('mark files as unresolved')),
5003 ('u', 'unmark', None, _('mark files as unresolved')),
5006 ('n', 'no-status', None, _('hide status prefix'))]
5004 ('n', 'no-status', None, _('hide status prefix'))]
5007 + mergetoolopts + walkopts,
5005 + mergetoolopts + walkopts,
5008 _('[OPTION]... [FILE]...'))
5006 _('[OPTION]... [FILE]...'))
5009 def resolve(ui, repo, *pats, **opts):
5007 def resolve(ui, repo, *pats, **opts):
5010 """redo merges or set/view the merge status of files
5008 """redo merges or set/view the merge status of files
5011
5009
5012 Merges with unresolved conflicts are often the result of
5010 Merges with unresolved conflicts are often the result of
5013 non-interactive merging using the ``internal:merge`` configuration
5011 non-interactive merging using the ``internal:merge`` configuration
5014 setting, or a command-line merge tool like ``diff3``. The resolve
5012 setting, or a command-line merge tool like ``diff3``. The resolve
5015 command is used to manage the files involved in a merge, after
5013 command is used to manage the files involved in a merge, after
5016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5014 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5017 working directory must have two parents). See :hg:`help
5015 working directory must have two parents). See :hg:`help
5018 merge-tools` for information on configuring merge tools.
5016 merge-tools` for information on configuring merge tools.
5019
5017
5020 The resolve command can be used in the following ways:
5018 The resolve command can be used in the following ways:
5021
5019
5022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5020 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5023 files, discarding any previous merge attempts. Re-merging is not
5021 files, discarding any previous merge attempts. Re-merging is not
5024 performed for files already marked as resolved. Use ``--all/-a``
5022 performed for files already marked as resolved. Use ``--all/-a``
5025 to select all unresolved files. ``--tool`` can be used to specify
5023 to select all unresolved files. ``--tool`` can be used to specify
5026 the merge tool used for the given files. It overrides the HGMERGE
5024 the merge tool used for the given files. It overrides the HGMERGE
5027 environment variable and your configuration files. Previous file
5025 environment variable and your configuration files. Previous file
5028 contents are saved with a ``.orig`` suffix.
5026 contents are saved with a ``.orig`` suffix.
5029
5027
5030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5028 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5031 (e.g. after having manually fixed-up the files). The default is
5029 (e.g. after having manually fixed-up the files). The default is
5032 to mark all unresolved files.
5030 to mark all unresolved files.
5033
5031
5034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5032 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5035 default is to mark all resolved files.
5033 default is to mark all resolved files.
5036
5034
5037 - :hg:`resolve -l`: list files which had or still have conflicts.
5035 - :hg:`resolve -l`: list files which had or still have conflicts.
5038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5036 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5039
5037
5040 Note that Mercurial will not let you commit files with unresolved
5038 Note that Mercurial will not let you commit files with unresolved
5041 merge conflicts. You must use :hg:`resolve -m ...` before you can
5039 merge conflicts. You must use :hg:`resolve -m ...` before you can
5042 commit after a conflicting merge.
5040 commit after a conflicting merge.
5043
5041
5044 Returns 0 on success, 1 if any files fail a resolve attempt.
5042 Returns 0 on success, 1 if any files fail a resolve attempt.
5045 """
5043 """
5046
5044
5047 all, mark, unmark, show, nostatus = \
5045 all, mark, unmark, show, nostatus = \
5048 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5046 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5049
5047
5050 if (show and (mark or unmark)) or (mark and unmark):
5048 if (show and (mark or unmark)) or (mark and unmark):
5051 raise util.Abort(_("too many options specified"))
5049 raise util.Abort(_("too many options specified"))
5052 if pats and all:
5050 if pats and all:
5053 raise util.Abort(_("can't specify --all and patterns"))
5051 raise util.Abort(_("can't specify --all and patterns"))
5054 if not (all or pats or show or mark or unmark):
5052 if not (all or pats or show or mark or unmark):
5055 raise util.Abort(_('no files or directories specified; '
5053 raise util.Abort(_('no files or directories specified; '
5056 'use --all to remerge all files'))
5054 'use --all to remerge all files'))
5057
5055
5058 ms = mergemod.mergestate(repo)
5056 ms = mergemod.mergestate(repo)
5059 m = scmutil.match(repo[None], pats, opts)
5057 m = scmutil.match(repo[None], pats, opts)
5060 ret = 0
5058 ret = 0
5061
5059
5062 for f in ms:
5060 for f in ms:
5063 if m(f):
5061 if m(f):
5064 if show:
5062 if show:
5065 if nostatus:
5063 if nostatus:
5066 ui.write("%s\n" % f)
5064 ui.write("%s\n" % f)
5067 else:
5065 else:
5068 ui.write("%s %s\n" % (ms[f].upper(), f),
5066 ui.write("%s %s\n" % (ms[f].upper(), f),
5069 label='resolve.' +
5067 label='resolve.' +
5070 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5068 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5071 elif mark:
5069 elif mark:
5072 ms.mark(f, "r")
5070 ms.mark(f, "r")
5073 elif unmark:
5071 elif unmark:
5074 ms.mark(f, "u")
5072 ms.mark(f, "u")
5075 else:
5073 else:
5076 wctx = repo[None]
5074 wctx = repo[None]
5077 mctx = wctx.parents()[-1]
5075 mctx = wctx.parents()[-1]
5078
5076
5079 # backup pre-resolve (merge uses .orig for its own purposes)
5077 # backup pre-resolve (merge uses .orig for its own purposes)
5080 a = repo.wjoin(f)
5078 a = repo.wjoin(f)
5081 util.copyfile(a, a + ".resolve")
5079 util.copyfile(a, a + ".resolve")
5082
5080
5083 try:
5081 try:
5084 # resolve file
5082 # resolve file
5085 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5083 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5086 if ms.resolve(f, wctx, mctx):
5084 if ms.resolve(f, wctx, mctx):
5087 ret = 1
5085 ret = 1
5088 finally:
5086 finally:
5089 ui.setconfig('ui', 'forcemerge', '')
5087 ui.setconfig('ui', 'forcemerge', '')
5090 ms.commit()
5088 ms.commit()
5091
5089
5092 # replace filemerge's .orig file with our resolve file
5090 # replace filemerge's .orig file with our resolve file
5093 util.rename(a + ".resolve", a + ".orig")
5091 util.rename(a + ".resolve", a + ".orig")
5094
5092
5095 ms.commit()
5093 ms.commit()
5096 return ret
5094 return ret
5097
5095
5098 @command('revert',
5096 @command('revert',
5099 [('a', 'all', None, _('revert all changes when no arguments given')),
5097 [('a', 'all', None, _('revert all changes when no arguments given')),
5100 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5098 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5101 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5099 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5102 ('C', 'no-backup', None, _('do not save backup copies of files')),
5100 ('C', 'no-backup', None, _('do not save backup copies of files')),
5103 ] + walkopts + dryrunopts,
5101 ] + walkopts + dryrunopts,
5104 _('[OPTION]... [-r REV] [NAME]...'))
5102 _('[OPTION]... [-r REV] [NAME]...'))
5105 def revert(ui, repo, *pats, **opts):
5103 def revert(ui, repo, *pats, **opts):
5106 """restore files to their checkout state
5104 """restore files to their checkout state
5107
5105
5108 .. note::
5106 .. note::
5109
5107
5110 To check out earlier revisions, you should use :hg:`update REV`.
5108 To check out earlier revisions, you should use :hg:`update REV`.
5111 To cancel an uncommitted merge (and lose your changes), use
5109 To cancel an uncommitted merge (and lose your changes), use
5112 :hg:`update --clean .`.
5110 :hg:`update --clean .`.
5113
5111
5114 With no revision specified, revert the specified files or directories
5112 With no revision specified, revert the specified files or directories
5115 to the contents they had in the parent of the working directory.
5113 to the contents they had in the parent of the working directory.
5116 This restores the contents of files to an unmodified
5114 This restores the contents of files to an unmodified
5117 state and unschedules adds, removes, copies, and renames. If the
5115 state and unschedules adds, removes, copies, and renames. If the
5118 working directory has two parents, you must explicitly specify a
5116 working directory has two parents, you must explicitly specify a
5119 revision.
5117 revision.
5120
5118
5121 Using the -r/--rev or -d/--date options, revert the given files or
5119 Using the -r/--rev or -d/--date options, revert the given files or
5122 directories to their states as of a specific revision. Because
5120 directories to their states as of a specific revision. Because
5123 revert does not change the working directory parents, this will
5121 revert does not change the working directory parents, this will
5124 cause these files to appear modified. This can be helpful to "back
5122 cause these files to appear modified. This can be helpful to "back
5125 out" some or all of an earlier change. See :hg:`backout` for a
5123 out" some or all of an earlier change. See :hg:`backout` for a
5126 related method.
5124 related method.
5127
5125
5128 Modified files are saved with a .orig suffix before reverting.
5126 Modified files are saved with a .orig suffix before reverting.
5129 To disable these backups, use --no-backup.
5127 To disable these backups, use --no-backup.
5130
5128
5131 See :hg:`help dates` for a list of formats valid for -d/--date.
5129 See :hg:`help dates` for a list of formats valid for -d/--date.
5132
5130
5133 Returns 0 on success.
5131 Returns 0 on success.
5134 """
5132 """
5135
5133
5136 if opts.get("date"):
5134 if opts.get("date"):
5137 if opts.get("rev"):
5135 if opts.get("rev"):
5138 raise util.Abort(_("you can't specify a revision and a date"))
5136 raise util.Abort(_("you can't specify a revision and a date"))
5139 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5137 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5140
5138
5141 parent, p2 = repo.dirstate.parents()
5139 parent, p2 = repo.dirstate.parents()
5142 if not opts.get('rev') and p2 != nullid:
5140 if not opts.get('rev') and p2 != nullid:
5143 # revert after merge is a trap for new users (issue2915)
5141 # revert after merge is a trap for new users (issue2915)
5144 raise util.Abort(_('uncommitted merge with no revision specified'),
5142 raise util.Abort(_('uncommitted merge with no revision specified'),
5145 hint=_('use "hg update" or see "hg help revert"'))
5143 hint=_('use "hg update" or see "hg help revert"'))
5146
5144
5147 ctx = scmutil.revsingle(repo, opts.get('rev'))
5145 ctx = scmutil.revsingle(repo, opts.get('rev'))
5148
5146
5149 if not pats and not opts.get('all'):
5147 if not pats and not opts.get('all'):
5150 msg = _("no files or directories specified")
5148 msg = _("no files or directories specified")
5151 if p2 != nullid:
5149 if p2 != nullid:
5152 hint = _("uncommitted merge, use --all to discard all changes,"
5150 hint = _("uncommitted merge, use --all to discard all changes,"
5153 " or 'hg update -C .' to abort the merge")
5151 " or 'hg update -C .' to abort the merge")
5154 raise util.Abort(msg, hint=hint)
5152 raise util.Abort(msg, hint=hint)
5155 dirty = util.any(repo.status())
5153 dirty = util.any(repo.status())
5156 node = ctx.node()
5154 node = ctx.node()
5157 if node != parent:
5155 if node != parent:
5158 if dirty:
5156 if dirty:
5159 hint = _("uncommitted changes, use --all to discard all"
5157 hint = _("uncommitted changes, use --all to discard all"
5160 " changes, or 'hg update %s' to update") % ctx.rev()
5158 " changes, or 'hg update %s' to update") % ctx.rev()
5161 else:
5159 else:
5162 hint = _("use --all to revert all files,"
5160 hint = _("use --all to revert all files,"
5163 " or 'hg update %s' to update") % ctx.rev()
5161 " or 'hg update %s' to update") % ctx.rev()
5164 elif dirty:
5162 elif dirty:
5165 hint = _("uncommitted changes, use --all to discard all changes")
5163 hint = _("uncommitted changes, use --all to discard all changes")
5166 else:
5164 else:
5167 hint = _("use --all to revert all files")
5165 hint = _("use --all to revert all files")
5168 raise util.Abort(msg, hint=hint)
5166 raise util.Abort(msg, hint=hint)
5169
5167
5170 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5168 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5171
5169
5172 @command('rollback', dryrunopts +
5170 @command('rollback', dryrunopts +
5173 [('f', 'force', False, _('ignore safety measures'))])
5171 [('f', 'force', False, _('ignore safety measures'))])
5174 def rollback(ui, repo, **opts):
5172 def rollback(ui, repo, **opts):
5175 """roll back the last transaction (dangerous)
5173 """roll back the last transaction (dangerous)
5176
5174
5177 This command should be used with care. There is only one level of
5175 This command should be used with care. There is only one level of
5178 rollback, and there is no way to undo a rollback. It will also
5176 rollback, and there is no way to undo a rollback. It will also
5179 restore the dirstate at the time of the last transaction, losing
5177 restore the dirstate at the time of the last transaction, losing
5180 any dirstate changes since that time. This command does not alter
5178 any dirstate changes since that time. This command does not alter
5181 the working directory.
5179 the working directory.
5182
5180
5183 Transactions are used to encapsulate the effects of all commands
5181 Transactions are used to encapsulate the effects of all commands
5184 that create new changesets or propagate existing changesets into a
5182 that create new changesets or propagate existing changesets into a
5185 repository.
5183 repository.
5186
5184
5187 .. container:: verbose
5185 .. container:: verbose
5188
5186
5189 For example, the following commands are transactional, and their
5187 For example, the following commands are transactional, and their
5190 effects can be rolled back:
5188 effects can be rolled back:
5191
5189
5192 - commit
5190 - commit
5193 - import
5191 - import
5194 - pull
5192 - pull
5195 - push (with this repository as the destination)
5193 - push (with this repository as the destination)
5196 - unbundle
5194 - unbundle
5197
5195
5198 To avoid permanent data loss, rollback will refuse to rollback a
5196 To avoid permanent data loss, rollback will refuse to rollback a
5199 commit transaction if it isn't checked out. Use --force to
5197 commit transaction if it isn't checked out. Use --force to
5200 override this protection.
5198 override this protection.
5201
5199
5202 This command is not intended for use on public repositories. Once
5200 This command is not intended for use on public repositories. Once
5203 changes are visible for pull by other users, rolling a transaction
5201 changes are visible for pull by other users, rolling a transaction
5204 back locally is ineffective (someone else may already have pulled
5202 back locally is ineffective (someone else may already have pulled
5205 the changes). Furthermore, a race is possible with readers of the
5203 the changes). Furthermore, a race is possible with readers of the
5206 repository; for example an in-progress pull from the repository
5204 repository; for example an in-progress pull from the repository
5207 may fail if a rollback is performed.
5205 may fail if a rollback is performed.
5208
5206
5209 Returns 0 on success, 1 if no rollback data is available.
5207 Returns 0 on success, 1 if no rollback data is available.
5210 """
5208 """
5211 return repo.rollback(dryrun=opts.get('dry_run'),
5209 return repo.rollback(dryrun=opts.get('dry_run'),
5212 force=opts.get('force'))
5210 force=opts.get('force'))
5213
5211
5214 @command('root', [])
5212 @command('root', [])
5215 def root(ui, repo):
5213 def root(ui, repo):
5216 """print the root (top) of the current working directory
5214 """print the root (top) of the current working directory
5217
5215
5218 Print the root directory of the current repository.
5216 Print the root directory of the current repository.
5219
5217
5220 Returns 0 on success.
5218 Returns 0 on success.
5221 """
5219 """
5222 ui.write(repo.root + "\n")
5220 ui.write(repo.root + "\n")
5223
5221
5224 @command('^serve',
5222 @command('^serve',
5225 [('A', 'accesslog', '', _('name of access log file to write to'),
5223 [('A', 'accesslog', '', _('name of access log file to write to'),
5226 _('FILE')),
5224 _('FILE')),
5227 ('d', 'daemon', None, _('run server in background')),
5225 ('d', 'daemon', None, _('run server in background')),
5228 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5226 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5229 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5227 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5230 # use string type, then we can check if something was passed
5228 # use string type, then we can check if something was passed
5231 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5229 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5232 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5230 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5233 _('ADDR')),
5231 _('ADDR')),
5234 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5232 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5235 _('PREFIX')),
5233 _('PREFIX')),
5236 ('n', 'name', '',
5234 ('n', 'name', '',
5237 _('name to show in web pages (default: working directory)'), _('NAME')),
5235 _('name to show in web pages (default: working directory)'), _('NAME')),
5238 ('', 'web-conf', '',
5236 ('', 'web-conf', '',
5239 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5237 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5240 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5238 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5241 _('FILE')),
5239 _('FILE')),
5242 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5240 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5243 ('', 'stdio', None, _('for remote clients')),
5241 ('', 'stdio', None, _('for remote clients')),
5244 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5242 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5245 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5243 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5246 ('', 'style', '', _('template style to use'), _('STYLE')),
5244 ('', 'style', '', _('template style to use'), _('STYLE')),
5247 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5245 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5248 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5246 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5249 _('[OPTION]...'))
5247 _('[OPTION]...'))
5250 def serve(ui, repo, **opts):
5248 def serve(ui, repo, **opts):
5251 """start stand-alone webserver
5249 """start stand-alone webserver
5252
5250
5253 Start a local HTTP repository browser and pull server. You can use
5251 Start a local HTTP repository browser and pull server. You can use
5254 this for ad-hoc sharing and browsing of repositories. It is
5252 this for ad-hoc sharing and browsing of repositories. It is
5255 recommended to use a real web server to serve a repository for
5253 recommended to use a real web server to serve a repository for
5256 longer periods of time.
5254 longer periods of time.
5257
5255
5258 Please note that the server does not implement access control.
5256 Please note that the server does not implement access control.
5259 This means that, by default, anybody can read from the server and
5257 This means that, by default, anybody can read from the server and
5260 nobody can write to it by default. Set the ``web.allow_push``
5258 nobody can write to it by default. Set the ``web.allow_push``
5261 option to ``*`` to allow everybody to push to the server. You
5259 option to ``*`` to allow everybody to push to the server. You
5262 should use a real web server if you need to authenticate users.
5260 should use a real web server if you need to authenticate users.
5263
5261
5264 By default, the server logs accesses to stdout and errors to
5262 By default, the server logs accesses to stdout and errors to
5265 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5263 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5266 files.
5264 files.
5267
5265
5268 To have the server choose a free port number to listen on, specify
5266 To have the server choose a free port number to listen on, specify
5269 a port number of 0; in this case, the server will print the port
5267 a port number of 0; in this case, the server will print the port
5270 number it uses.
5268 number it uses.
5271
5269
5272 Returns 0 on success.
5270 Returns 0 on success.
5273 """
5271 """
5274
5272
5275 if opts["stdio"] and opts["cmdserver"]:
5273 if opts["stdio"] and opts["cmdserver"]:
5276 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5274 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5277
5275
5278 def checkrepo():
5276 def checkrepo():
5279 if repo is None:
5277 if repo is None:
5280 raise error.RepoError(_("there is no Mercurial repository here"
5278 raise error.RepoError(_("there is no Mercurial repository here"
5281 " (.hg not found)"))
5279 " (.hg not found)"))
5282
5280
5283 if opts["stdio"]:
5281 if opts["stdio"]:
5284 checkrepo()
5282 checkrepo()
5285 s = sshserver.sshserver(ui, repo)
5283 s = sshserver.sshserver(ui, repo)
5286 s.serve_forever()
5284 s.serve_forever()
5287
5285
5288 if opts["cmdserver"]:
5286 if opts["cmdserver"]:
5289 checkrepo()
5287 checkrepo()
5290 s = commandserver.server(ui, repo, opts["cmdserver"])
5288 s = commandserver.server(ui, repo, opts["cmdserver"])
5291 return s.serve()
5289 return s.serve()
5292
5290
5293 # this way we can check if something was given in the command-line
5291 # this way we can check if something was given in the command-line
5294 if opts.get('port'):
5292 if opts.get('port'):
5295 opts['port'] = util.getport(opts.get('port'))
5293 opts['port'] = util.getport(opts.get('port'))
5296
5294
5297 baseui = repo and repo.baseui or ui
5295 baseui = repo and repo.baseui or ui
5298 optlist = ("name templates style address port prefix ipv6"
5296 optlist = ("name templates style address port prefix ipv6"
5299 " accesslog errorlog certificate encoding")
5297 " accesslog errorlog certificate encoding")
5300 for o in optlist.split():
5298 for o in optlist.split():
5301 val = opts.get(o, '')
5299 val = opts.get(o, '')
5302 if val in (None, ''): # should check against default options instead
5300 if val in (None, ''): # should check against default options instead
5303 continue
5301 continue
5304 baseui.setconfig("web", o, val)
5302 baseui.setconfig("web", o, val)
5305 if repo and repo.ui != baseui:
5303 if repo and repo.ui != baseui:
5306 repo.ui.setconfig("web", o, val)
5304 repo.ui.setconfig("web", o, val)
5307
5305
5308 o = opts.get('web_conf') or opts.get('webdir_conf')
5306 o = opts.get('web_conf') or opts.get('webdir_conf')
5309 if not o:
5307 if not o:
5310 if not repo:
5308 if not repo:
5311 raise error.RepoError(_("there is no Mercurial repository"
5309 raise error.RepoError(_("there is no Mercurial repository"
5312 " here (.hg not found)"))
5310 " here (.hg not found)"))
5313 o = repo.root
5311 o = repo.root
5314
5312
5315 app = hgweb.hgweb(o, baseui=ui)
5313 app = hgweb.hgweb(o, baseui=ui)
5316
5314
5317 class service(object):
5315 class service(object):
5318 def init(self):
5316 def init(self):
5319 util.setsignalhandler()
5317 util.setsignalhandler()
5320 self.httpd = hgweb.server.create_server(ui, app)
5318 self.httpd = hgweb.server.create_server(ui, app)
5321
5319
5322 if opts['port'] and not ui.verbose:
5320 if opts['port'] and not ui.verbose:
5323 return
5321 return
5324
5322
5325 if self.httpd.prefix:
5323 if self.httpd.prefix:
5326 prefix = self.httpd.prefix.strip('/') + '/'
5324 prefix = self.httpd.prefix.strip('/') + '/'
5327 else:
5325 else:
5328 prefix = ''
5326 prefix = ''
5329
5327
5330 port = ':%d' % self.httpd.port
5328 port = ':%d' % self.httpd.port
5331 if port == ':80':
5329 if port == ':80':
5332 port = ''
5330 port = ''
5333
5331
5334 bindaddr = self.httpd.addr
5332 bindaddr = self.httpd.addr
5335 if bindaddr == '0.0.0.0':
5333 if bindaddr == '0.0.0.0':
5336 bindaddr = '*'
5334 bindaddr = '*'
5337 elif ':' in bindaddr: # IPv6
5335 elif ':' in bindaddr: # IPv6
5338 bindaddr = '[%s]' % bindaddr
5336 bindaddr = '[%s]' % bindaddr
5339
5337
5340 fqaddr = self.httpd.fqaddr
5338 fqaddr = self.httpd.fqaddr
5341 if ':' in fqaddr:
5339 if ':' in fqaddr:
5342 fqaddr = '[%s]' % fqaddr
5340 fqaddr = '[%s]' % fqaddr
5343 if opts['port']:
5341 if opts['port']:
5344 write = ui.status
5342 write = ui.status
5345 else:
5343 else:
5346 write = ui.write
5344 write = ui.write
5347 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5345 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5348 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5346 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5349
5347
5350 def run(self):
5348 def run(self):
5351 self.httpd.serve_forever()
5349 self.httpd.serve_forever()
5352
5350
5353 service = service()
5351 service = service()
5354
5352
5355 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5353 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5356
5354
5357 @command('showconfig|debugconfig',
5355 @command('showconfig|debugconfig',
5358 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5356 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5359 _('[-u] [NAME]...'))
5357 _('[-u] [NAME]...'))
5360 def showconfig(ui, repo, *values, **opts):
5358 def showconfig(ui, repo, *values, **opts):
5361 """show combined config settings from all hgrc files
5359 """show combined config settings from all hgrc files
5362
5360
5363 With no arguments, print names and values of all config items.
5361 With no arguments, print names and values of all config items.
5364
5362
5365 With one argument of the form section.name, print just the value
5363 With one argument of the form section.name, print just the value
5366 of that config item.
5364 of that config item.
5367
5365
5368 With multiple arguments, print names and values of all config
5366 With multiple arguments, print names and values of all config
5369 items with matching section names.
5367 items with matching section names.
5370
5368
5371 With --debug, the source (filename and line number) is printed
5369 With --debug, the source (filename and line number) is printed
5372 for each config item.
5370 for each config item.
5373
5371
5374 Returns 0 on success.
5372 Returns 0 on success.
5375 """
5373 """
5376
5374
5377 for f in scmutil.rcpath():
5375 for f in scmutil.rcpath():
5378 ui.debug('read config from: %s\n' % f)
5376 ui.debug('read config from: %s\n' % f)
5379 untrusted = bool(opts.get('untrusted'))
5377 untrusted = bool(opts.get('untrusted'))
5380 if values:
5378 if values:
5381 sections = [v for v in values if '.' not in v]
5379 sections = [v for v in values if '.' not in v]
5382 items = [v for v in values if '.' in v]
5380 items = [v for v in values if '.' in v]
5383 if len(items) > 1 or items and sections:
5381 if len(items) > 1 or items and sections:
5384 raise util.Abort(_('only one config item permitted'))
5382 raise util.Abort(_('only one config item permitted'))
5385 for section, name, value in ui.walkconfig(untrusted=untrusted):
5383 for section, name, value in ui.walkconfig(untrusted=untrusted):
5386 value = str(value).replace('\n', '\\n')
5384 value = str(value).replace('\n', '\\n')
5387 sectname = section + '.' + name
5385 sectname = section + '.' + name
5388 if values:
5386 if values:
5389 for v in values:
5387 for v in values:
5390 if v == section:
5388 if v == section:
5391 ui.debug('%s: ' %
5389 ui.debug('%s: ' %
5392 ui.configsource(section, name, untrusted))
5390 ui.configsource(section, name, untrusted))
5393 ui.write('%s=%s\n' % (sectname, value))
5391 ui.write('%s=%s\n' % (sectname, value))
5394 elif v == sectname:
5392 elif v == sectname:
5395 ui.debug('%s: ' %
5393 ui.debug('%s: ' %
5396 ui.configsource(section, name, untrusted))
5394 ui.configsource(section, name, untrusted))
5397 ui.write(value, '\n')
5395 ui.write(value, '\n')
5398 else:
5396 else:
5399 ui.debug('%s: ' %
5397 ui.debug('%s: ' %
5400 ui.configsource(section, name, untrusted))
5398 ui.configsource(section, name, untrusted))
5401 ui.write('%s=%s\n' % (sectname, value))
5399 ui.write('%s=%s\n' % (sectname, value))
5402
5400
5403 @command('^status|st',
5401 @command('^status|st',
5404 [('A', 'all', None, _('show status of all files')),
5402 [('A', 'all', None, _('show status of all files')),
5405 ('m', 'modified', None, _('show only modified files')),
5403 ('m', 'modified', None, _('show only modified files')),
5406 ('a', 'added', None, _('show only added files')),
5404 ('a', 'added', None, _('show only added files')),
5407 ('r', 'removed', None, _('show only removed files')),
5405 ('r', 'removed', None, _('show only removed files')),
5408 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5406 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5409 ('c', 'clean', None, _('show only files without changes')),
5407 ('c', 'clean', None, _('show only files without changes')),
5410 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5408 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5411 ('i', 'ignored', None, _('show only ignored files')),
5409 ('i', 'ignored', None, _('show only ignored files')),
5412 ('n', 'no-status', None, _('hide status prefix')),
5410 ('n', 'no-status', None, _('hide status prefix')),
5413 ('C', 'copies', None, _('show source of copied files')),
5411 ('C', 'copies', None, _('show source of copied files')),
5414 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5412 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5415 ('', 'rev', [], _('show difference from revision'), _('REV')),
5413 ('', 'rev', [], _('show difference from revision'), _('REV')),
5416 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5414 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5417 ] + walkopts + subrepoopts,
5415 ] + walkopts + subrepoopts,
5418 _('[OPTION]... [FILE]...'))
5416 _('[OPTION]... [FILE]...'))
5419 def status(ui, repo, *pats, **opts):
5417 def status(ui, repo, *pats, **opts):
5420 """show changed files in the working directory
5418 """show changed files in the working directory
5421
5419
5422 Show status of files in the repository. If names are given, only
5420 Show status of files in the repository. If names are given, only
5423 files that match are shown. Files that are clean or ignored or
5421 files that match are shown. Files that are clean or ignored or
5424 the source of a copy/move operation, are not listed unless
5422 the source of a copy/move operation, are not listed unless
5425 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5423 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5426 Unless options described with "show only ..." are given, the
5424 Unless options described with "show only ..." are given, the
5427 options -mardu are used.
5425 options -mardu are used.
5428
5426
5429 Option -q/--quiet hides untracked (unknown and ignored) files
5427 Option -q/--quiet hides untracked (unknown and ignored) files
5430 unless explicitly requested with -u/--unknown or -i/--ignored.
5428 unless explicitly requested with -u/--unknown or -i/--ignored.
5431
5429
5432 .. note::
5430 .. note::
5433 status may appear to disagree with diff if permissions have
5431 status may appear to disagree with diff if permissions have
5434 changed or a merge has occurred. The standard diff format does
5432 changed or a merge has occurred. The standard diff format does
5435 not report permission changes and diff only reports changes
5433 not report permission changes and diff only reports changes
5436 relative to one merge parent.
5434 relative to one merge parent.
5437
5435
5438 If one revision is given, it is used as the base revision.
5436 If one revision is given, it is used as the base revision.
5439 If two revisions are given, the differences between them are
5437 If two revisions are given, the differences between them are
5440 shown. The --change option can also be used as a shortcut to list
5438 shown. The --change option can also be used as a shortcut to list
5441 the changed files of a revision from its first parent.
5439 the changed files of a revision from its first parent.
5442
5440
5443 The codes used to show the status of files are::
5441 The codes used to show the status of files are::
5444
5442
5445 M = modified
5443 M = modified
5446 A = added
5444 A = added
5447 R = removed
5445 R = removed
5448 C = clean
5446 C = clean
5449 ! = missing (deleted by non-hg command, but still tracked)
5447 ! = missing (deleted by non-hg command, but still tracked)
5450 ? = not tracked
5448 ? = not tracked
5451 I = ignored
5449 I = ignored
5452 = origin of the previous file listed as A (added)
5450 = origin of the previous file listed as A (added)
5453
5451
5454 .. container:: verbose
5452 .. container:: verbose
5455
5453
5456 Examples:
5454 Examples:
5457
5455
5458 - show changes in the working directory relative to a
5456 - show changes in the working directory relative to a
5459 changeset::
5457 changeset::
5460
5458
5461 hg status --rev 9353
5459 hg status --rev 9353
5462
5460
5463 - show all changes including copies in an existing changeset::
5461 - show all changes including copies in an existing changeset::
5464
5462
5465 hg status --copies --change 9353
5463 hg status --copies --change 9353
5466
5464
5467 - get a NUL separated list of added files, suitable for xargs::
5465 - get a NUL separated list of added files, suitable for xargs::
5468
5466
5469 hg status -an0
5467 hg status -an0
5470
5468
5471 Returns 0 on success.
5469 Returns 0 on success.
5472 """
5470 """
5473
5471
5474 revs = opts.get('rev')
5472 revs = opts.get('rev')
5475 change = opts.get('change')
5473 change = opts.get('change')
5476
5474
5477 if revs and change:
5475 if revs and change:
5478 msg = _('cannot specify --rev and --change at the same time')
5476 msg = _('cannot specify --rev and --change at the same time')
5479 raise util.Abort(msg)
5477 raise util.Abort(msg)
5480 elif change:
5478 elif change:
5481 node2 = scmutil.revsingle(repo, change, None).node()
5479 node2 = scmutil.revsingle(repo, change, None).node()
5482 node1 = repo[node2].p1().node()
5480 node1 = repo[node2].p1().node()
5483 else:
5481 else:
5484 node1, node2 = scmutil.revpair(repo, revs)
5482 node1, node2 = scmutil.revpair(repo, revs)
5485
5483
5486 cwd = (pats and repo.getcwd()) or ''
5484 cwd = (pats and repo.getcwd()) or ''
5487 end = opts.get('print0') and '\0' or '\n'
5485 end = opts.get('print0') and '\0' or '\n'
5488 copy = {}
5486 copy = {}
5489 states = 'modified added removed deleted unknown ignored clean'.split()
5487 states = 'modified added removed deleted unknown ignored clean'.split()
5490 show = [k for k in states if opts.get(k)]
5488 show = [k for k in states if opts.get(k)]
5491 if opts.get('all'):
5489 if opts.get('all'):
5492 show += ui.quiet and (states[:4] + ['clean']) or states
5490 show += ui.quiet and (states[:4] + ['clean']) or states
5493 if not show:
5491 if not show:
5494 show = ui.quiet and states[:4] or states[:5]
5492 show = ui.quiet and states[:4] or states[:5]
5495
5493
5496 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5494 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5497 'ignored' in show, 'clean' in show, 'unknown' in show,
5495 'ignored' in show, 'clean' in show, 'unknown' in show,
5498 opts.get('subrepos'))
5496 opts.get('subrepos'))
5499 changestates = zip(states, 'MAR!?IC', stat)
5497 changestates = zip(states, 'MAR!?IC', stat)
5500
5498
5501 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5499 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5502 copy = copies.pathcopies(repo[node1], repo[node2])
5500 copy = copies.pathcopies(repo[node1], repo[node2])
5503
5501
5504 fm = ui.formatter('status', opts)
5502 fm = ui.formatter('status', opts)
5505 fmt = '%s' + end
5503 fmt = '%s' + end
5506 showchar = not opts.get('no_status')
5504 showchar = not opts.get('no_status')
5507
5505
5508 for state, char, files in changestates:
5506 for state, char, files in changestates:
5509 if state in show:
5507 if state in show:
5510 label = 'status.' + state
5508 label = 'status.' + state
5511 for f in files:
5509 for f in files:
5512 fm.startitem()
5510 fm.startitem()
5513 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5511 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5514 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5512 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5515 if f in copy:
5513 if f in copy:
5516 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5514 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5517 label='status.copied')
5515 label='status.copied')
5518 fm.end()
5516 fm.end()
5519
5517
5520 @command('^summary|sum',
5518 @command('^summary|sum',
5521 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5519 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5522 def summary(ui, repo, **opts):
5520 def summary(ui, repo, **opts):
5523 """summarize working directory state
5521 """summarize working directory state
5524
5522
5525 This generates a brief summary of the working directory state,
5523 This generates a brief summary of the working directory state,
5526 including parents, branch, commit status, and available updates.
5524 including parents, branch, commit status, and available updates.
5527
5525
5528 With the --remote option, this will check the default paths for
5526 With the --remote option, this will check the default paths for
5529 incoming and outgoing changes. This can be time-consuming.
5527 incoming and outgoing changes. This can be time-consuming.
5530
5528
5531 Returns 0 on success.
5529 Returns 0 on success.
5532 """
5530 """
5533
5531
5534 ctx = repo[None]
5532 ctx = repo[None]
5535 parents = ctx.parents()
5533 parents = ctx.parents()
5536 pnode = parents[0].node()
5534 pnode = parents[0].node()
5537 marks = []
5535 marks = []
5538
5536
5539 for p in parents:
5537 for p in parents:
5540 # label with log.changeset (instead of log.parent) since this
5538 # label with log.changeset (instead of log.parent) since this
5541 # shows a working directory parent *changeset*:
5539 # shows a working directory parent *changeset*:
5542 # i18n: column positioning for "hg summary"
5540 # i18n: column positioning for "hg summary"
5543 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5541 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5544 label='log.changeset changeset.%s' % p.phasestr())
5542 label='log.changeset changeset.%s' % p.phasestr())
5545 ui.write(' '.join(p.tags()), label='log.tag')
5543 ui.write(' '.join(p.tags()), label='log.tag')
5546 if p.bookmarks():
5544 if p.bookmarks():
5547 marks.extend(p.bookmarks())
5545 marks.extend(p.bookmarks())
5548 if p.rev() == -1:
5546 if p.rev() == -1:
5549 if not len(repo):
5547 if not len(repo):
5550 ui.write(_(' (empty repository)'))
5548 ui.write(_(' (empty repository)'))
5551 else:
5549 else:
5552 ui.write(_(' (no revision checked out)'))
5550 ui.write(_(' (no revision checked out)'))
5553 ui.write('\n')
5551 ui.write('\n')
5554 if p.description():
5552 if p.description():
5555 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5553 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5556 label='log.summary')
5554 label='log.summary')
5557
5555
5558 branch = ctx.branch()
5556 branch = ctx.branch()
5559 bheads = repo.branchheads(branch)
5557 bheads = repo.branchheads(branch)
5560 # i18n: column positioning for "hg summary"
5558 # i18n: column positioning for "hg summary"
5561 m = _('branch: %s\n') % branch
5559 m = _('branch: %s\n') % branch
5562 if branch != 'default':
5560 if branch != 'default':
5563 ui.write(m, label='log.branch')
5561 ui.write(m, label='log.branch')
5564 else:
5562 else:
5565 ui.status(m, label='log.branch')
5563 ui.status(m, label='log.branch')
5566
5564
5567 if marks:
5565 if marks:
5568 current = repo._bookmarkcurrent
5566 current = repo._bookmarkcurrent
5569 # i18n: column positioning for "hg summary"
5567 # i18n: column positioning for "hg summary"
5570 ui.write(_('bookmarks:'), label='log.bookmark')
5568 ui.write(_('bookmarks:'), label='log.bookmark')
5571 if current is not None:
5569 if current is not None:
5572 try:
5570 try:
5573 marks.remove(current)
5571 marks.remove(current)
5574 ui.write(' *' + current, label='bookmarks.current')
5572 ui.write(' *' + current, label='bookmarks.current')
5575 except ValueError:
5573 except ValueError:
5576 # current bookmark not in parent ctx marks
5574 # current bookmark not in parent ctx marks
5577 pass
5575 pass
5578 for m in marks:
5576 for m in marks:
5579 ui.write(' ' + m, label='log.bookmark')
5577 ui.write(' ' + m, label='log.bookmark')
5580 ui.write('\n', label='log.bookmark')
5578 ui.write('\n', label='log.bookmark')
5581
5579
5582 st = list(repo.status(unknown=True))[:6]
5580 st = list(repo.status(unknown=True))[:6]
5583
5581
5584 c = repo.dirstate.copies()
5582 c = repo.dirstate.copies()
5585 copied, renamed = [], []
5583 copied, renamed = [], []
5586 for d, s in c.iteritems():
5584 for d, s in c.iteritems():
5587 if s in st[2]:
5585 if s in st[2]:
5588 st[2].remove(s)
5586 st[2].remove(s)
5589 renamed.append(d)
5587 renamed.append(d)
5590 else:
5588 else:
5591 copied.append(d)
5589 copied.append(d)
5592 if d in st[1]:
5590 if d in st[1]:
5593 st[1].remove(d)
5591 st[1].remove(d)
5594 st.insert(3, renamed)
5592 st.insert(3, renamed)
5595 st.insert(4, copied)
5593 st.insert(4, copied)
5596
5594
5597 ms = mergemod.mergestate(repo)
5595 ms = mergemod.mergestate(repo)
5598 st.append([f for f in ms if ms[f] == 'u'])
5596 st.append([f for f in ms if ms[f] == 'u'])
5599
5597
5600 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5598 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5601 st.append(subs)
5599 st.append(subs)
5602
5600
5603 labels = [ui.label(_('%d modified'), 'status.modified'),
5601 labels = [ui.label(_('%d modified'), 'status.modified'),
5604 ui.label(_('%d added'), 'status.added'),
5602 ui.label(_('%d added'), 'status.added'),
5605 ui.label(_('%d removed'), 'status.removed'),
5603 ui.label(_('%d removed'), 'status.removed'),
5606 ui.label(_('%d renamed'), 'status.copied'),
5604 ui.label(_('%d renamed'), 'status.copied'),
5607 ui.label(_('%d copied'), 'status.copied'),
5605 ui.label(_('%d copied'), 'status.copied'),
5608 ui.label(_('%d deleted'), 'status.deleted'),
5606 ui.label(_('%d deleted'), 'status.deleted'),
5609 ui.label(_('%d unknown'), 'status.unknown'),
5607 ui.label(_('%d unknown'), 'status.unknown'),
5610 ui.label(_('%d ignored'), 'status.ignored'),
5608 ui.label(_('%d ignored'), 'status.ignored'),
5611 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5609 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5612 ui.label(_('%d subrepos'), 'status.modified')]
5610 ui.label(_('%d subrepos'), 'status.modified')]
5613 t = []
5611 t = []
5614 for s, l in zip(st, labels):
5612 for s, l in zip(st, labels):
5615 if s:
5613 if s:
5616 t.append(l % len(s))
5614 t.append(l % len(s))
5617
5615
5618 t = ', '.join(t)
5616 t = ', '.join(t)
5619 cleanworkdir = False
5617 cleanworkdir = False
5620
5618
5621 if len(parents) > 1:
5619 if len(parents) > 1:
5622 t += _(' (merge)')
5620 t += _(' (merge)')
5623 elif branch != parents[0].branch():
5621 elif branch != parents[0].branch():
5624 t += _(' (new branch)')
5622 t += _(' (new branch)')
5625 elif (parents[0].closesbranch() and
5623 elif (parents[0].closesbranch() and
5626 pnode in repo.branchheads(branch, closed=True)):
5624 pnode in repo.branchheads(branch, closed=True)):
5627 t += _(' (head closed)')
5625 t += _(' (head closed)')
5628 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5626 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5629 t += _(' (clean)')
5627 t += _(' (clean)')
5630 cleanworkdir = True
5628 cleanworkdir = True
5631 elif pnode not in bheads:
5629 elif pnode not in bheads:
5632 t += _(' (new branch head)')
5630 t += _(' (new branch head)')
5633
5631
5634 if cleanworkdir:
5632 if cleanworkdir:
5635 # i18n: column positioning for "hg summary"
5633 # i18n: column positioning for "hg summary"
5636 ui.status(_('commit: %s\n') % t.strip())
5634 ui.status(_('commit: %s\n') % t.strip())
5637 else:
5635 else:
5638 # i18n: column positioning for "hg summary"
5636 # i18n: column positioning for "hg summary"
5639 ui.write(_('commit: %s\n') % t.strip())
5637 ui.write(_('commit: %s\n') % t.strip())
5640
5638
5641 # all ancestors of branch heads - all ancestors of parent = new csets
5639 # all ancestors of branch heads - all ancestors of parent = new csets
5642 new = [0] * len(repo)
5640 new = [0] * len(repo)
5643 cl = repo.changelog
5641 cl = repo.changelog
5644 for a in [cl.rev(n) for n in bheads]:
5642 for a in [cl.rev(n) for n in bheads]:
5645 new[a] = 1
5643 new[a] = 1
5646 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5644 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5647 new[a] = 1
5645 new[a] = 1
5648 for a in [p.rev() for p in parents]:
5646 for a in [p.rev() for p in parents]:
5649 if a >= 0:
5647 if a >= 0:
5650 new[a] = 0
5648 new[a] = 0
5651 for a in cl.ancestors([p.rev() for p in parents]):
5649 for a in cl.ancestors([p.rev() for p in parents]):
5652 new[a] = 0
5650 new[a] = 0
5653 new = sum(new)
5651 new = sum(new)
5654
5652
5655 if new == 0:
5653 if new == 0:
5656 # i18n: column positioning for "hg summary"
5654 # i18n: column positioning for "hg summary"
5657 ui.status(_('update: (current)\n'))
5655 ui.status(_('update: (current)\n'))
5658 elif pnode not in bheads:
5656 elif pnode not in bheads:
5659 # i18n: column positioning for "hg summary"
5657 # i18n: column positioning for "hg summary"
5660 ui.write(_('update: %d new changesets (update)\n') % new)
5658 ui.write(_('update: %d new changesets (update)\n') % new)
5661 else:
5659 else:
5662 # i18n: column positioning for "hg summary"
5660 # i18n: column positioning for "hg summary"
5663 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5661 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5664 (new, len(bheads)))
5662 (new, len(bheads)))
5665
5663
5666 if opts.get('remote'):
5664 if opts.get('remote'):
5667 t = []
5665 t = []
5668 source, branches = hg.parseurl(ui.expandpath('default'))
5666 source, branches = hg.parseurl(ui.expandpath('default'))
5669 other = hg.peer(repo, {}, source)
5667 other = hg.peer(repo, {}, source)
5670 revs, checkout = hg.addbranchrevs(repo, other, branches,
5668 revs, checkout = hg.addbranchrevs(repo, other, branches,
5671 opts.get('rev'))
5669 opts.get('rev'))
5672 ui.debug('comparing with %s\n' % util.hidepassword(source))
5670 ui.debug('comparing with %s\n' % util.hidepassword(source))
5673 repo.ui.pushbuffer()
5671 repo.ui.pushbuffer()
5674 commoninc = discovery.findcommonincoming(repo, other)
5672 commoninc = discovery.findcommonincoming(repo, other)
5675 _common, incoming, _rheads = commoninc
5673 _common, incoming, _rheads = commoninc
5676 repo.ui.popbuffer()
5674 repo.ui.popbuffer()
5677 if incoming:
5675 if incoming:
5678 t.append(_('1 or more incoming'))
5676 t.append(_('1 or more incoming'))
5679
5677
5680 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5678 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5681 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5679 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5682 if source != dest:
5680 if source != dest:
5683 other = hg.peer(repo, {}, dest)
5681 other = hg.peer(repo, {}, dest)
5684 commoninc = None
5682 commoninc = None
5685 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5683 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5686 repo.ui.pushbuffer()
5684 repo.ui.pushbuffer()
5687 outgoing = discovery.findcommonoutgoing(repo, other,
5685 outgoing = discovery.findcommonoutgoing(repo, other,
5688 commoninc=commoninc)
5686 commoninc=commoninc)
5689 repo.ui.popbuffer()
5687 repo.ui.popbuffer()
5690 o = outgoing.missing
5688 o = outgoing.missing
5691 if o:
5689 if o:
5692 t.append(_('%d outgoing') % len(o))
5690 t.append(_('%d outgoing') % len(o))
5693 if 'bookmarks' in other.listkeys('namespaces'):
5691 if 'bookmarks' in other.listkeys('namespaces'):
5694 lmarks = repo.listkeys('bookmarks')
5692 lmarks = repo.listkeys('bookmarks')
5695 rmarks = other.listkeys('bookmarks')
5693 rmarks = other.listkeys('bookmarks')
5696 diff = set(rmarks) - set(lmarks)
5694 diff = set(rmarks) - set(lmarks)
5697 if len(diff) > 0:
5695 if len(diff) > 0:
5698 t.append(_('%d incoming bookmarks') % len(diff))
5696 t.append(_('%d incoming bookmarks') % len(diff))
5699 diff = set(lmarks) - set(rmarks)
5697 diff = set(lmarks) - set(rmarks)
5700 if len(diff) > 0:
5698 if len(diff) > 0:
5701 t.append(_('%d outgoing bookmarks') % len(diff))
5699 t.append(_('%d outgoing bookmarks') % len(diff))
5702
5700
5703 if t:
5701 if t:
5704 # i18n: column positioning for "hg summary"
5702 # i18n: column positioning for "hg summary"
5705 ui.write(_('remote: %s\n') % (', '.join(t)))
5703 ui.write(_('remote: %s\n') % (', '.join(t)))
5706 else:
5704 else:
5707 # i18n: column positioning for "hg summary"
5705 # i18n: column positioning for "hg summary"
5708 ui.status(_('remote: (synced)\n'))
5706 ui.status(_('remote: (synced)\n'))
5709
5707
5710 @command('tag',
5708 @command('tag',
5711 [('f', 'force', None, _('force tag')),
5709 [('f', 'force', None, _('force tag')),
5712 ('l', 'local', None, _('make the tag local')),
5710 ('l', 'local', None, _('make the tag local')),
5713 ('r', 'rev', '', _('revision to tag'), _('REV')),
5711 ('r', 'rev', '', _('revision to tag'), _('REV')),
5714 ('', 'remove', None, _('remove a tag')),
5712 ('', 'remove', None, _('remove a tag')),
5715 # -l/--local is already there, commitopts cannot be used
5713 # -l/--local is already there, commitopts cannot be used
5716 ('e', 'edit', None, _('edit commit message')),
5714 ('e', 'edit', None, _('edit commit message')),
5717 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5715 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5718 ] + commitopts2,
5716 ] + commitopts2,
5719 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5717 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5720 def tag(ui, repo, name1, *names, **opts):
5718 def tag(ui, repo, name1, *names, **opts):
5721 """add one or more tags for the current or given revision
5719 """add one or more tags for the current or given revision
5722
5720
5723 Name a particular revision using <name>.
5721 Name a particular revision using <name>.
5724
5722
5725 Tags are used to name particular revisions of the repository and are
5723 Tags are used to name particular revisions of the repository and are
5726 very useful to compare different revisions, to go back to significant
5724 very useful to compare different revisions, to go back to significant
5727 earlier versions or to mark branch points as releases, etc. Changing
5725 earlier versions or to mark branch points as releases, etc. Changing
5728 an existing tag is normally disallowed; use -f/--force to override.
5726 an existing tag is normally disallowed; use -f/--force to override.
5729
5727
5730 If no revision is given, the parent of the working directory is
5728 If no revision is given, the parent of the working directory is
5731 used, or tip if no revision is checked out.
5729 used, or tip if no revision is checked out.
5732
5730
5733 To facilitate version control, distribution, and merging of tags,
5731 To facilitate version control, distribution, and merging of tags,
5734 they are stored as a file named ".hgtags" which is managed similarly
5732 they are stored as a file named ".hgtags" which is managed similarly
5735 to other project files and can be hand-edited if necessary. This
5733 to other project files and can be hand-edited if necessary. This
5736 also means that tagging creates a new commit. The file
5734 also means that tagging creates a new commit. The file
5737 ".hg/localtags" is used for local tags (not shared among
5735 ".hg/localtags" is used for local tags (not shared among
5738 repositories).
5736 repositories).
5739
5737
5740 Tag commits are usually made at the head of a branch. If the parent
5738 Tag commits are usually made at the head of a branch. If the parent
5741 of the working directory is not a branch head, :hg:`tag` aborts; use
5739 of the working directory is not a branch head, :hg:`tag` aborts; use
5742 -f/--force to force the tag commit to be based on a non-head
5740 -f/--force to force the tag commit to be based on a non-head
5743 changeset.
5741 changeset.
5744
5742
5745 See :hg:`help dates` for a list of formats valid for -d/--date.
5743 See :hg:`help dates` for a list of formats valid for -d/--date.
5746
5744
5747 Since tag names have priority over branch names during revision
5745 Since tag names have priority over branch names during revision
5748 lookup, using an existing branch name as a tag name is discouraged.
5746 lookup, using an existing branch name as a tag name is discouraged.
5749
5747
5750 Returns 0 on success.
5748 Returns 0 on success.
5751 """
5749 """
5752 wlock = lock = None
5750 wlock = lock = None
5753 try:
5751 try:
5754 wlock = repo.wlock()
5752 wlock = repo.wlock()
5755 lock = repo.lock()
5753 lock = repo.lock()
5756 rev_ = "."
5754 rev_ = "."
5757 names = [t.strip() for t in (name1,) + names]
5755 names = [t.strip() for t in (name1,) + names]
5758 if len(names) != len(set(names)):
5756 if len(names) != len(set(names)):
5759 raise util.Abort(_('tag names must be unique'))
5757 raise util.Abort(_('tag names must be unique'))
5760 for n in names:
5758 for n in names:
5761 scmutil.checknewlabel(repo, n, 'tag')
5759 scmutil.checknewlabel(repo, n, 'tag')
5762 if not n:
5760 if not n:
5763 raise util.Abort(_('tag names cannot consist entirely of '
5761 raise util.Abort(_('tag names cannot consist entirely of '
5764 'whitespace'))
5762 'whitespace'))
5765 if opts.get('rev') and opts.get('remove'):
5763 if opts.get('rev') and opts.get('remove'):
5766 raise util.Abort(_("--rev and --remove are incompatible"))
5764 raise util.Abort(_("--rev and --remove are incompatible"))
5767 if opts.get('rev'):
5765 if opts.get('rev'):
5768 rev_ = opts['rev']
5766 rev_ = opts['rev']
5769 message = opts.get('message')
5767 message = opts.get('message')
5770 if opts.get('remove'):
5768 if opts.get('remove'):
5771 expectedtype = opts.get('local') and 'local' or 'global'
5769 expectedtype = opts.get('local') and 'local' or 'global'
5772 for n in names:
5770 for n in names:
5773 if not repo.tagtype(n):
5771 if not repo.tagtype(n):
5774 raise util.Abort(_("tag '%s' does not exist") % n)
5772 raise util.Abort(_("tag '%s' does not exist") % n)
5775 if repo.tagtype(n) != expectedtype:
5773 if repo.tagtype(n) != expectedtype:
5776 if expectedtype == 'global':
5774 if expectedtype == 'global':
5777 raise util.Abort(_("tag '%s' is not a global tag") % n)
5775 raise util.Abort(_("tag '%s' is not a global tag") % n)
5778 else:
5776 else:
5779 raise util.Abort(_("tag '%s' is not a local tag") % n)
5777 raise util.Abort(_("tag '%s' is not a local tag") % n)
5780 rev_ = nullid
5778 rev_ = nullid
5781 if not message:
5779 if not message:
5782 # we don't translate commit messages
5780 # we don't translate commit messages
5783 message = 'Removed tag %s' % ', '.join(names)
5781 message = 'Removed tag %s' % ', '.join(names)
5784 elif not opts.get('force'):
5782 elif not opts.get('force'):
5785 for n in names:
5783 for n in names:
5786 if n in repo.tags():
5784 if n in repo.tags():
5787 raise util.Abort(_("tag '%s' already exists "
5785 raise util.Abort(_("tag '%s' already exists "
5788 "(use -f to force)") % n)
5786 "(use -f to force)") % n)
5789 if not opts.get('local'):
5787 if not opts.get('local'):
5790 p1, p2 = repo.dirstate.parents()
5788 p1, p2 = repo.dirstate.parents()
5791 if p2 != nullid:
5789 if p2 != nullid:
5792 raise util.Abort(_('uncommitted merge'))
5790 raise util.Abort(_('uncommitted merge'))
5793 bheads = repo.branchheads()
5791 bheads = repo.branchheads()
5794 if not opts.get('force') and bheads and p1 not in bheads:
5792 if not opts.get('force') and bheads and p1 not in bheads:
5795 raise util.Abort(_('not at a branch head (use -f to force)'))
5793 raise util.Abort(_('not at a branch head (use -f to force)'))
5796 r = scmutil.revsingle(repo, rev_).node()
5794 r = scmutil.revsingle(repo, rev_).node()
5797
5795
5798 if not message:
5796 if not message:
5799 # we don't translate commit messages
5797 # we don't translate commit messages
5800 message = ('Added tag %s for changeset %s' %
5798 message = ('Added tag %s for changeset %s' %
5801 (', '.join(names), short(r)))
5799 (', '.join(names), short(r)))
5802
5800
5803 date = opts.get('date')
5801 date = opts.get('date')
5804 if date:
5802 if date:
5805 date = util.parsedate(date)
5803 date = util.parsedate(date)
5806
5804
5807 if opts.get('edit'):
5805 if opts.get('edit'):
5808 message = ui.edit(message, ui.username())
5806 message = ui.edit(message, ui.username())
5809
5807
5810 # don't allow tagging the null rev
5808 # don't allow tagging the null rev
5811 if (not opts.get('remove') and
5809 if (not opts.get('remove') and
5812 scmutil.revsingle(repo, rev_).rev() == nullrev):
5810 scmutil.revsingle(repo, rev_).rev() == nullrev):
5813 raise util.Abort(_("null revision specified"))
5811 raise util.Abort(_("null revision specified"))
5814
5812
5815 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5813 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5816 finally:
5814 finally:
5817 release(lock, wlock)
5815 release(lock, wlock)
5818
5816
5819 @command('tags', [], '')
5817 @command('tags', [], '')
5820 def tags(ui, repo, **opts):
5818 def tags(ui, repo, **opts):
5821 """list repository tags
5819 """list repository tags
5822
5820
5823 This lists both regular and local tags. When the -v/--verbose
5821 This lists both regular and local tags. When the -v/--verbose
5824 switch is used, a third column "local" is printed for local tags.
5822 switch is used, a third column "local" is printed for local tags.
5825
5823
5826 Returns 0 on success.
5824 Returns 0 on success.
5827 """
5825 """
5828
5826
5829 fm = ui.formatter('tags', opts)
5827 fm = ui.formatter('tags', opts)
5830 hexfunc = ui.debugflag and hex or short
5828 hexfunc = ui.debugflag and hex or short
5831 tagtype = ""
5829 tagtype = ""
5832
5830
5833 for t, n in reversed(repo.tagslist()):
5831 for t, n in reversed(repo.tagslist()):
5834 hn = hexfunc(n)
5832 hn = hexfunc(n)
5835 label = 'tags.normal'
5833 label = 'tags.normal'
5836 tagtype = ''
5834 tagtype = ''
5837 if repo.tagtype(t) == 'local':
5835 if repo.tagtype(t) == 'local':
5838 label = 'tags.local'
5836 label = 'tags.local'
5839 tagtype = 'local'
5837 tagtype = 'local'
5840
5838
5841 fm.startitem()
5839 fm.startitem()
5842 fm.write('tag', '%s', t, label=label)
5840 fm.write('tag', '%s', t, label=label)
5843 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5841 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5844 fm.condwrite(not ui.quiet, 'rev id', fmt,
5842 fm.condwrite(not ui.quiet, 'rev id', fmt,
5845 repo.changelog.rev(n), hn, label=label)
5843 repo.changelog.rev(n), hn, label=label)
5846 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5844 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5847 tagtype, label=label)
5845 tagtype, label=label)
5848 fm.plain('\n')
5846 fm.plain('\n')
5849 fm.end()
5847 fm.end()
5850
5848
5851 @command('tip',
5849 @command('tip',
5852 [('p', 'patch', None, _('show patch')),
5850 [('p', 'patch', None, _('show patch')),
5853 ('g', 'git', None, _('use git extended diff format')),
5851 ('g', 'git', None, _('use git extended diff format')),
5854 ] + templateopts,
5852 ] + templateopts,
5855 _('[-p] [-g]'))
5853 _('[-p] [-g]'))
5856 def tip(ui, repo, **opts):
5854 def tip(ui, repo, **opts):
5857 """show the tip revision
5855 """show the tip revision
5858
5856
5859 The tip revision (usually just called the tip) is the changeset
5857 The tip revision (usually just called the tip) is the changeset
5860 most recently added to the repository (and therefore the most
5858 most recently added to the repository (and therefore the most
5861 recently changed head).
5859 recently changed head).
5862
5860
5863 If you have just made a commit, that commit will be the tip. If
5861 If you have just made a commit, that commit will be the tip. If
5864 you have just pulled changes from another repository, the tip of
5862 you have just pulled changes from another repository, the tip of
5865 that repository becomes the current tip. The "tip" tag is special
5863 that repository becomes the current tip. The "tip" tag is special
5866 and cannot be renamed or assigned to a different changeset.
5864 and cannot be renamed or assigned to a different changeset.
5867
5865
5868 Returns 0 on success.
5866 Returns 0 on success.
5869 """
5867 """
5870 displayer = cmdutil.show_changeset(ui, repo, opts)
5868 displayer = cmdutil.show_changeset(ui, repo, opts)
5871 displayer.show(repo[len(repo) - 1])
5869 displayer.show(repo[len(repo) - 1])
5872 displayer.close()
5870 displayer.close()
5873
5871
5874 @command('unbundle',
5872 @command('unbundle',
5875 [('u', 'update', None,
5873 [('u', 'update', None,
5876 _('update to new branch head if changesets were unbundled'))],
5874 _('update to new branch head if changesets were unbundled'))],
5877 _('[-u] FILE...'))
5875 _('[-u] FILE...'))
5878 def unbundle(ui, repo, fname1, *fnames, **opts):
5876 def unbundle(ui, repo, fname1, *fnames, **opts):
5879 """apply one or more changegroup files
5877 """apply one or more changegroup files
5880
5878
5881 Apply one or more compressed changegroup files generated by the
5879 Apply one or more compressed changegroup files generated by the
5882 bundle command.
5880 bundle command.
5883
5881
5884 Returns 0 on success, 1 if an update has unresolved files.
5882 Returns 0 on success, 1 if an update has unresolved files.
5885 """
5883 """
5886 fnames = (fname1,) + fnames
5884 fnames = (fname1,) + fnames
5887
5885
5888 lock = repo.lock()
5886 lock = repo.lock()
5889 wc = repo['.']
5887 wc = repo['.']
5890 try:
5888 try:
5891 for fname in fnames:
5889 for fname in fnames:
5892 f = hg.openpath(ui, fname)
5890 f = hg.openpath(ui, fname)
5893 gen = changegroup.readbundle(f, fname)
5891 gen = changegroup.readbundle(f, fname)
5894 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5892 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5895 finally:
5893 finally:
5896 lock.release()
5894 lock.release()
5897 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5895 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5898 return postincoming(ui, repo, modheads, opts.get('update'), None)
5896 return postincoming(ui, repo, modheads, opts.get('update'), None)
5899
5897
5900 @command('^update|up|checkout|co',
5898 @command('^update|up|checkout|co',
5901 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5899 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5902 ('c', 'check', None,
5900 ('c', 'check', None,
5903 _('update across branches if no uncommitted changes')),
5901 _('update across branches if no uncommitted changes')),
5904 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5902 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5905 ('r', 'rev', '', _('revision'), _('REV'))],
5903 ('r', 'rev', '', _('revision'), _('REV'))],
5906 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5904 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5907 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5905 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5908 """update working directory (or switch revisions)
5906 """update working directory (or switch revisions)
5909
5907
5910 Update the repository's working directory to the specified
5908 Update the repository's working directory to the specified
5911 changeset. If no changeset is specified, update to the tip of the
5909 changeset. If no changeset is specified, update to the tip of the
5912 current named branch and move the current bookmark (see :hg:`help
5910 current named branch and move the current bookmark (see :hg:`help
5913 bookmarks`).
5911 bookmarks`).
5914
5912
5915 Update sets the working directory's parent revision to the specified
5913 Update sets the working directory's parent revision to the specified
5916 changeset (see :hg:`help parents`).
5914 changeset (see :hg:`help parents`).
5917
5915
5918 If the changeset is not a descendant or ancestor of the working
5916 If the changeset is not a descendant or ancestor of the working
5919 directory's parent, the update is aborted. With the -c/--check
5917 directory's parent, the update is aborted. With the -c/--check
5920 option, the working directory is checked for uncommitted changes; if
5918 option, the working directory is checked for uncommitted changes; if
5921 none are found, the working directory is updated to the specified
5919 none are found, the working directory is updated to the specified
5922 changeset.
5920 changeset.
5923
5921
5924 .. container:: verbose
5922 .. container:: verbose
5925
5923
5926 The following rules apply when the working directory contains
5924 The following rules apply when the working directory contains
5927 uncommitted changes:
5925 uncommitted changes:
5928
5926
5929 1. If neither -c/--check nor -C/--clean is specified, and if
5927 1. If neither -c/--check nor -C/--clean is specified, and if
5930 the requested changeset is an ancestor or descendant of
5928 the requested changeset is an ancestor or descendant of
5931 the working directory's parent, the uncommitted changes
5929 the working directory's parent, the uncommitted changes
5932 are merged into the requested changeset and the merged
5930 are merged into the requested changeset and the merged
5933 result is left uncommitted. If the requested changeset is
5931 result is left uncommitted. If the requested changeset is
5934 not an ancestor or descendant (that is, it is on another
5932 not an ancestor or descendant (that is, it is on another
5935 branch), the update is aborted and the uncommitted changes
5933 branch), the update is aborted and the uncommitted changes
5936 are preserved.
5934 are preserved.
5937
5935
5938 2. With the -c/--check option, the update is aborted and the
5936 2. With the -c/--check option, the update is aborted and the
5939 uncommitted changes are preserved.
5937 uncommitted changes are preserved.
5940
5938
5941 3. With the -C/--clean option, uncommitted changes are discarded and
5939 3. With the -C/--clean option, uncommitted changes are discarded and
5942 the working directory is updated to the requested changeset.
5940 the working directory is updated to the requested changeset.
5943
5941
5944 To cancel an uncommitted merge (and lose your changes), use
5942 To cancel an uncommitted merge (and lose your changes), use
5945 :hg:`update --clean .`.
5943 :hg:`update --clean .`.
5946
5944
5947 Use null as the changeset to remove the working directory (like
5945 Use null as the changeset to remove the working directory (like
5948 :hg:`clone -U`).
5946 :hg:`clone -U`).
5949
5947
5950 If you want to revert just one file to an older revision, use
5948 If you want to revert just one file to an older revision, use
5951 :hg:`revert [-r REV] NAME`.
5949 :hg:`revert [-r REV] NAME`.
5952
5950
5953 See :hg:`help dates` for a list of formats valid for -d/--date.
5951 See :hg:`help dates` for a list of formats valid for -d/--date.
5954
5952
5955 Returns 0 on success, 1 if there are unresolved files.
5953 Returns 0 on success, 1 if there are unresolved files.
5956 """
5954 """
5957 if rev and node:
5955 if rev and node:
5958 raise util.Abort(_("please specify just one revision"))
5956 raise util.Abort(_("please specify just one revision"))
5959
5957
5960 if rev is None or rev == '':
5958 if rev is None or rev == '':
5961 rev = node
5959 rev = node
5962
5960
5963 # with no argument, we also move the current bookmark, if any
5961 # with no argument, we also move the current bookmark, if any
5964 movemarkfrom = None
5962 movemarkfrom = None
5965 if rev is None:
5963 if rev is None:
5966 movemarkfrom = repo['.'].node()
5964 movemarkfrom = repo['.'].node()
5967
5965
5968 # if we defined a bookmark, we have to remember the original bookmark name
5966 # if we defined a bookmark, we have to remember the original bookmark name
5969 brev = rev
5967 brev = rev
5970 rev = scmutil.revsingle(repo, rev, rev).rev()
5968 rev = scmutil.revsingle(repo, rev, rev).rev()
5971
5969
5972 if check and clean:
5970 if check and clean:
5973 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5971 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5974
5972
5975 if date:
5973 if date:
5976 if rev is not None:
5974 if rev is not None:
5977 raise util.Abort(_("you can't specify a revision and a date"))
5975 raise util.Abort(_("you can't specify a revision and a date"))
5978 rev = cmdutil.finddate(ui, repo, date)
5976 rev = cmdutil.finddate(ui, repo, date)
5979
5977
5980 if check:
5978 if check:
5981 c = repo[None]
5979 c = repo[None]
5982 if c.dirty(merge=False, branch=False, missing=True):
5980 if c.dirty(merge=False, branch=False, missing=True):
5983 raise util.Abort(_("uncommitted local changes"))
5981 raise util.Abort(_("uncommitted local changes"))
5984 if rev is None:
5982 if rev is None:
5985 rev = repo[repo[None].branch()].rev()
5983 rev = repo[repo[None].branch()].rev()
5986 mergemod._checkunknown(repo, repo[None], repo[rev])
5984 mergemod._checkunknown(repo, repo[None], repo[rev])
5987
5985
5988 if clean:
5986 if clean:
5989 ret = hg.clean(repo, rev)
5987 ret = hg.clean(repo, rev)
5990 else:
5988 else:
5991 ret = hg.update(repo, rev)
5989 ret = hg.update(repo, rev)
5992
5990
5993 if not ret and movemarkfrom:
5991 if not ret and movemarkfrom:
5994 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5992 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5995 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5993 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5996 elif brev in repo._bookmarks:
5994 elif brev in repo._bookmarks:
5997 bookmarks.setcurrent(repo, brev)
5995 bookmarks.setcurrent(repo, brev)
5998 elif brev:
5996 elif brev:
5999 bookmarks.unsetcurrent(repo)
5997 bookmarks.unsetcurrent(repo)
6000
5998
6001 return ret
5999 return ret
6002
6000
6003 @command('verify', [])
6001 @command('verify', [])
6004 def verify(ui, repo):
6002 def verify(ui, repo):
6005 """verify the integrity of the repository
6003 """verify the integrity of the repository
6006
6004
6007 Verify the integrity of the current repository.
6005 Verify the integrity of the current repository.
6008
6006
6009 This will perform an extensive check of the repository's
6007 This will perform an extensive check of the repository's
6010 integrity, validating the hashes and checksums of each entry in
6008 integrity, validating the hashes and checksums of each entry in
6011 the changelog, manifest, and tracked files, as well as the
6009 the changelog, manifest, and tracked files, as well as the
6012 integrity of their crosslinks and indices.
6010 integrity of their crosslinks and indices.
6013
6011
6014 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6012 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6015 for more information about recovery from corruption of the
6013 for more information about recovery from corruption of the
6016 repository.
6014 repository.
6017
6015
6018 Returns 0 on success, 1 if errors are encountered.
6016 Returns 0 on success, 1 if errors are encountered.
6019 """
6017 """
6020 return hg.verify(repo)
6018 return hg.verify(repo)
6021
6019
6022 @command('version', [])
6020 @command('version', [])
6023 def version_(ui):
6021 def version_(ui):
6024 """output version and copyright information"""
6022 """output version and copyright information"""
6025 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6023 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6026 % util.version())
6024 % util.version())
6027 ui.status(_(
6025 ui.status(_(
6028 "(see http://mercurial.selenic.com for more information)\n"
6026 "(see http://mercurial.selenic.com for more information)\n"
6029 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6027 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6030 "This is free software; see the source for copying conditions. "
6028 "This is free software; see the source for copying conditions. "
6031 "There is NO\nwarranty; "
6029 "There is NO\nwarranty; "
6032 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6030 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6033 ))
6031 ))
6034
6032
6035 norepo = ("clone init version help debugcommands debugcomplete"
6033 norepo = ("clone init version help debugcommands debugcomplete"
6036 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6034 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6037 " debugknown debuggetbundle debugbundle")
6035 " debugknown debuggetbundle debugbundle")
6038 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6036 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6039 " debugdata debugindex debugindexdot debugrevlog")
6037 " debugdata debugindex debugindexdot debugrevlog")
6040 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6038 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6041 " remove resolve status debugwalk")
6039 " remove resolve status debugwalk")
@@ -1,831 +1,835 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching 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 i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 class request(object):
14 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 ferr=None):
16 ferr=None):
17 self.args = args
17 self.args = args
18 self.ui = ui
18 self.ui = ui
19 self.repo = repo
19 self.repo = repo
20
20
21 # input/output/error streams
21 # input/output/error streams
22 self.fin = fin
22 self.fin = fin
23 self.fout = fout
23 self.fout = fout
24 self.ferr = ferr
24 self.ferr = ferr
25
25
26 def run():
26 def run():
27 "run the command in sys.argv"
27 "run the command in sys.argv"
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29
29
30 def dispatch(req):
30 def dispatch(req):
31 "run the command specified in req.args"
31 "run the command specified in req.args"
32 if req.ferr:
32 if req.ferr:
33 ferr = req.ferr
33 ferr = req.ferr
34 elif req.ui:
34 elif req.ui:
35 ferr = req.ui.ferr
35 ferr = req.ui.ferr
36 else:
36 else:
37 ferr = sys.stderr
37 ferr = sys.stderr
38
38
39 try:
39 try:
40 if not req.ui:
40 if not req.ui:
41 req.ui = uimod.ui()
41 req.ui = uimod.ui()
42 if '--traceback' in req.args:
42 if '--traceback' in req.args:
43 req.ui.setconfig('ui', 'traceback', 'on')
43 req.ui.setconfig('ui', 'traceback', 'on')
44
44
45 # set ui streams from the request
45 # set ui streams from the request
46 if req.fin:
46 if req.fin:
47 req.ui.fin = req.fin
47 req.ui.fin = req.fin
48 if req.fout:
48 if req.fout:
49 req.ui.fout = req.fout
49 req.ui.fout = req.fout
50 if req.ferr:
50 if req.ferr:
51 req.ui.ferr = req.ferr
51 req.ui.ferr = req.ferr
52 except util.Abort, inst:
52 except util.Abort, inst:
53 ferr.write(_("abort: %s\n") % inst)
53 ferr.write(_("abort: %s\n") % inst)
54 if inst.hint:
54 if inst.hint:
55 ferr.write(_("(%s)\n") % inst.hint)
55 ferr.write(_("(%s)\n") % inst.hint)
56 return -1
56 return -1
57 except error.ParseError, inst:
57 except error.ParseError, inst:
58 if len(inst.args) > 1:
58 if len(inst.args) > 1:
59 ferr.write(_("hg: parse error at %s: %s\n") %
59 ferr.write(_("hg: parse error at %s: %s\n") %
60 (inst.args[1], inst.args[0]))
60 (inst.args[1], inst.args[0]))
61 else:
61 else:
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 return -1
63 return -1
64
64
65 return _runcatch(req)
65 return _runcatch(req)
66
66
67 def _runcatch(req):
67 def _runcatch(req):
68 def catchterm(*args):
68 def catchterm(*args):
69 raise error.SignalInterrupt
69 raise error.SignalInterrupt
70
70
71 ui = req.ui
71 ui = req.ui
72 try:
72 try:
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
74 num = getattr(signal, name, None)
74 num = getattr(signal, name, None)
75 if num:
75 if num:
76 signal.signal(num, catchterm)
76 signal.signal(num, catchterm)
77 except ValueError:
77 except ValueError:
78 pass # happens if called in a thread
78 pass # happens if called in a thread
79
79
80 try:
80 try:
81 try:
81 try:
82 # enter the debugger before command execution
82 # enter the debugger before command execution
83 if '--debugger' in req.args:
83 if '--debugger' in req.args:
84 ui.warn(_("entering debugger - "
84 ui.warn(_("entering debugger - "
85 "type c to continue starting hg or h for help\n"))
85 "type c to continue starting hg or h for help\n"))
86 pdb.set_trace()
86 pdb.set_trace()
87 try:
87 try:
88 return _dispatch(req)
88 return _dispatch(req)
89 finally:
89 finally:
90 ui.flush()
90 ui.flush()
91 except: # re-raises
91 except: # re-raises
92 # enter the debugger when we hit an exception
92 # enter the debugger when we hit an exception
93 if '--debugger' in req.args:
93 if '--debugger' in req.args:
94 traceback.print_exc()
94 traceback.print_exc()
95 pdb.post_mortem(sys.exc_info()[2])
95 pdb.post_mortem(sys.exc_info()[2])
96 ui.traceback()
96 ui.traceback()
97 raise
97 raise
98
98
99 # Global exception handling, alphabetically
99 # Global exception handling, alphabetically
100 # Mercurial-specific first, followed by built-in and library exceptions
100 # Mercurial-specific first, followed by built-in and library exceptions
101 except error.AmbiguousCommand, inst:
101 except error.AmbiguousCommand, inst:
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
103 (inst.args[0], " ".join(inst.args[1])))
103 (inst.args[0], " ".join(inst.args[1])))
104 except error.ParseError, inst:
104 except error.ParseError, inst:
105 if len(inst.args) > 1:
105 if len(inst.args) > 1:
106 ui.warn(_("hg: parse error at %s: %s\n") %
106 ui.warn(_("hg: parse error at %s: %s\n") %
107 (inst.args[1], inst.args[0]))
107 (inst.args[1], inst.args[0]))
108 else:
108 else:
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
110 return -1
110 return -1
111 except error.LockHeld, inst:
111 except error.LockHeld, inst:
112 if inst.errno == errno.ETIMEDOUT:
112 if inst.errno == errno.ETIMEDOUT:
113 reason = _('timed out waiting for lock held by %s') % inst.locker
113 reason = _('timed out waiting for lock held by %s') % inst.locker
114 else:
114 else:
115 reason = _('lock held by %s') % inst.locker
115 reason = _('lock held by %s') % inst.locker
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
117 except error.LockUnavailable, inst:
117 except error.LockUnavailable, inst:
118 ui.warn(_("abort: could not lock %s: %s\n") %
118 ui.warn(_("abort: could not lock %s: %s\n") %
119 (inst.desc or inst.filename, inst.strerror))
119 (inst.desc or inst.filename, inst.strerror))
120 except error.CommandError, inst:
120 except error.CommandError, inst:
121 if inst.args[0]:
121 if inst.args[0]:
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
123 commands.help_(ui, inst.args[0], full=False, command=True)
123 commands.help_(ui, inst.args[0], full=False, command=True)
124 else:
124 else:
125 ui.warn(_("hg: %s\n") % inst.args[1])
125 ui.warn(_("hg: %s\n") % inst.args[1])
126 commands.help_(ui, 'shortlist')
126 commands.help_(ui, 'shortlist')
127 except error.OutOfBandError, inst:
127 except error.OutOfBandError, inst:
128 ui.warn(_("abort: remote error:\n"))
128 ui.warn(_("abort: remote error:\n"))
129 ui.warn(''.join(inst.args))
129 ui.warn(''.join(inst.args))
130 except error.RepoError, inst:
130 except error.RepoError, inst:
131 ui.warn(_("abort: %s!\n") % inst)
131 ui.warn(_("abort: %s!\n") % inst)
132 if inst.hint:
132 if inst.hint:
133 ui.warn(_("(%s)\n") % inst.hint)
133 ui.warn(_("(%s)\n") % inst.hint)
134 except error.ResponseError, inst:
134 except error.ResponseError, inst:
135 ui.warn(_("abort: %s") % inst.args[0])
135 ui.warn(_("abort: %s") % inst.args[0])
136 if not isinstance(inst.args[1], basestring):
136 if not isinstance(inst.args[1], basestring):
137 ui.warn(" %r\n" % (inst.args[1],))
137 ui.warn(" %r\n" % (inst.args[1],))
138 elif not inst.args[1]:
138 elif not inst.args[1]:
139 ui.warn(_(" empty string\n"))
139 ui.warn(_(" empty string\n"))
140 else:
140 else:
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
142 except error.RevlogError, inst:
142 except error.RevlogError, inst:
143 ui.warn(_("abort: %s!\n") % inst)
143 ui.warn(_("abort: %s!\n") % inst)
144 except error.SignalInterrupt:
144 except error.SignalInterrupt:
145 ui.warn(_("killed!\n"))
145 ui.warn(_("killed!\n"))
146 except error.UnknownCommand, inst:
146 except error.UnknownCommand, inst:
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
148 try:
148 try:
149 # check if the command is in a disabled extension
149 # check if the command is in a disabled extension
150 # (but don't check for extensions themselves)
150 # (but don't check for extensions themselves)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
152 except error.UnknownCommand:
152 except error.UnknownCommand:
153 commands.help_(ui, 'shortlist')
153 commands.help_(ui, 'shortlist')
154 except util.Abort, inst:
154 except util.Abort, inst:
155 ui.warn(_("abort: %s\n") % inst)
155 ui.warn(_("abort: %s\n") % inst)
156 if inst.hint:
156 if inst.hint:
157 ui.warn(_("(%s)\n") % inst.hint)
157 ui.warn(_("(%s)\n") % inst.hint)
158 except ImportError, inst:
158 except ImportError, inst:
159 ui.warn(_("abort: %s!\n") % inst)
159 ui.warn(_("abort: %s!\n") % inst)
160 m = str(inst).split()[-1]
160 m = str(inst).split()[-1]
161 if m in "mpatch bdiff".split():
161 if m in "mpatch bdiff".split():
162 ui.warn(_("(did you forget to compile extensions?)\n"))
162 ui.warn(_("(did you forget to compile extensions?)\n"))
163 elif m in "zlib".split():
163 elif m in "zlib".split():
164 ui.warn(_("(is your Python install correct?)\n"))
164 ui.warn(_("(is your Python install correct?)\n"))
165 except IOError, inst:
165 except IOError, inst:
166 if util.safehasattr(inst, "code"):
166 if util.safehasattr(inst, "code"):
167 ui.warn(_("abort: %s\n") % inst)
167 ui.warn(_("abort: %s\n") % inst)
168 elif util.safehasattr(inst, "reason"):
168 elif util.safehasattr(inst, "reason"):
169 try: # usually it is in the form (errno, strerror)
169 try: # usually it is in the form (errno, strerror)
170 reason = inst.reason.args[1]
170 reason = inst.reason.args[1]
171 except (AttributeError, IndexError):
171 except (AttributeError, IndexError):
172 # it might be anything, for example a string
172 # it might be anything, for example a string
173 reason = inst.reason
173 reason = inst.reason
174 ui.warn(_("abort: error: %s\n") % reason)
174 ui.warn(_("abort: error: %s\n") % reason)
175 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
175 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
176 if ui.debugflag:
176 if ui.debugflag:
177 ui.warn(_("broken pipe\n"))
177 ui.warn(_("broken pipe\n"))
178 elif getattr(inst, "strerror", None):
178 elif getattr(inst, "strerror", None):
179 if getattr(inst, "filename", None):
179 if getattr(inst, "filename", None):
180 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
180 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
181 else:
181 else:
182 ui.warn(_("abort: %s\n") % inst.strerror)
182 ui.warn(_("abort: %s\n") % inst.strerror)
183 else:
183 else:
184 raise
184 raise
185 except OSError, inst:
185 except OSError, inst:
186 if getattr(inst, "filename", None) is not None:
186 if getattr(inst, "filename", None) is not None:
187 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
187 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
188 else:
188 else:
189 ui.warn(_("abort: %s\n") % inst.strerror)
189 ui.warn(_("abort: %s\n") % inst.strerror)
190 except KeyboardInterrupt:
190 except KeyboardInterrupt:
191 try:
191 try:
192 ui.warn(_("interrupted!\n"))
192 ui.warn(_("interrupted!\n"))
193 except IOError, inst:
193 except IOError, inst:
194 if inst.errno == errno.EPIPE:
194 if inst.errno == errno.EPIPE:
195 if ui.debugflag:
195 if ui.debugflag:
196 ui.warn(_("\nbroken pipe\n"))
196 ui.warn(_("\nbroken pipe\n"))
197 else:
197 else:
198 raise
198 raise
199 except MemoryError:
199 except MemoryError:
200 ui.warn(_("abort: out of memory\n"))
200 ui.warn(_("abort: out of memory\n"))
201 except SystemExit, inst:
201 except SystemExit, inst:
202 # Commands shouldn't sys.exit directly, but give a return code.
202 # Commands shouldn't sys.exit directly, but give a return code.
203 # Just in case catch this and and pass exit code to caller.
203 # Just in case catch this and and pass exit code to caller.
204 return inst.code
204 return inst.code
205 except socket.error, inst:
205 except socket.error, inst:
206 ui.warn(_("abort: %s\n") % inst.args[-1])
206 ui.warn(_("abort: %s\n") % inst.args[-1])
207 except: # re-raises
207 except: # re-raises
208 myver = util.version()
208 myver = util.version()
209 # For compatibility checking, we discard the portion of the hg
209 # For compatibility checking, we discard the portion of the hg
210 # version after the + on the assumption that if a "normal
210 # version after the + on the assumption that if a "normal
211 # user" is running a build with a + in it the packager
211 # user" is running a build with a + in it the packager
212 # probably built from fairly close to a tag and anyone with a
212 # probably built from fairly close to a tag and anyone with a
213 # 'make local' copy of hg (where the version number can be out
213 # 'make local' copy of hg (where the version number can be out
214 # of date) will be clueful enough to notice the implausible
214 # of date) will be clueful enough to notice the implausible
215 # version number and try updating.
215 # version number and try updating.
216 compare = myver.split('+')[0]
216 compare = myver.split('+')[0]
217 ct = tuplever(compare)
217 ct = tuplever(compare)
218 worst = None, ct, ''
218 worst = None, ct, ''
219 for name, mod in extensions.extensions():
219 for name, mod in extensions.extensions():
220 testedwith = getattr(mod, 'testedwith', '')
220 testedwith = getattr(mod, 'testedwith', '')
221 report = getattr(mod, 'buglink', _('the extension author.'))
221 report = getattr(mod, 'buglink', _('the extension author.'))
222 if not testedwith.strip():
222 if not testedwith.strip():
223 # We found an untested extension. It's likely the culprit.
223 # We found an untested extension. It's likely the culprit.
224 worst = name, 'unknown', report
224 worst = name, 'unknown', report
225 break
225 break
226 if compare not in testedwith.split() and testedwith != 'internal':
226 if compare not in testedwith.split() and testedwith != 'internal':
227 tested = [tuplever(v) for v in testedwith.split()]
227 tested = [tuplever(v) for v in testedwith.split()]
228 lower = [t for t in tested if t < ct]
228 lower = [t for t in tested if t < ct]
229 nearest = max(lower or tested)
229 nearest = max(lower or tested)
230 if worst[0] is None or nearest < worst[1]:
230 if worst[0] is None or nearest < worst[1]:
231 worst = name, nearest, report
231 worst = name, nearest, report
232 if worst[0] is not None:
232 if worst[0] is not None:
233 name, testedwith, report = worst
233 name, testedwith, report = worst
234 if not isinstance(testedwith, str):
234 if not isinstance(testedwith, str):
235 testedwith = '.'.join([str(c) for c in testedwith])
235 testedwith = '.'.join([str(c) for c in testedwith])
236 warning = (_('** Unknown exception encountered with '
236 warning = (_('** Unknown exception encountered with '
237 'possibly-broken third-party extension %s\n'
237 'possibly-broken third-party extension %s\n'
238 '** which supports versions %s of Mercurial.\n'
238 '** which supports versions %s of Mercurial.\n'
239 '** Please disable %s and try your action again.\n'
239 '** Please disable %s and try your action again.\n'
240 '** If that fixes the bug please report it to %s\n')
240 '** If that fixes the bug please report it to %s\n')
241 % (name, testedwith, name, report))
241 % (name, testedwith, name, report))
242 else:
242 else:
243 warning = (_("** unknown exception encountered, "
243 warning = (_("** unknown exception encountered, "
244 "please report by visiting\n") +
244 "please report by visiting\n") +
245 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
245 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
246 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
246 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
247 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
247 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
248 (_("** Extensions loaded: %s\n") %
248 (_("** Extensions loaded: %s\n") %
249 ", ".join([x[0] for x in extensions.extensions()])))
249 ", ".join([x[0] for x in extensions.extensions()])))
250 ui.warn(warning)
250 ui.warn(warning)
251 raise
251 raise
252
252
253 return -1
253 return -1
254
254
255 def tuplever(v):
255 def tuplever(v):
256 try:
256 try:
257 return tuple([int(i) for i in v.split('.')])
257 return tuple([int(i) for i in v.split('.')])
258 except ValueError:
258 except ValueError:
259 return tuple()
259 return tuple()
260
260
261 def aliasargs(fn, givenargs):
261 def aliasargs(fn, givenargs):
262 args = getattr(fn, 'args', [])
262 args = getattr(fn, 'args', [])
263 if args:
263 if args:
264 cmd = ' '.join(map(util.shellquote, args))
264 cmd = ' '.join(map(util.shellquote, args))
265
265
266 nums = []
266 nums = []
267 def replacer(m):
267 def replacer(m):
268 num = int(m.group(1)) - 1
268 num = int(m.group(1)) - 1
269 nums.append(num)
269 nums.append(num)
270 if num < len(givenargs):
270 if num < len(givenargs):
271 return givenargs[num]
271 return givenargs[num]
272 raise util.Abort(_('too few arguments for command alias'))
272 raise util.Abort(_('too few arguments for command alias'))
273 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
273 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
274 givenargs = [x for i, x in enumerate(givenargs)
274 givenargs = [x for i, x in enumerate(givenargs)
275 if i not in nums]
275 if i not in nums]
276 args = shlex.split(cmd)
276 args = shlex.split(cmd)
277 return args + givenargs
277 return args + givenargs
278
278
279 class cmdalias(object):
279 class cmdalias(object):
280 def __init__(self, name, definition, cmdtable):
280 def __init__(self, name, definition, cmdtable):
281 self.name = self.cmd = name
281 self.name = self.cmd = name
282 self.cmdname = ''
282 self.cmdname = ''
283 self.definition = definition
283 self.definition = definition
284 self.args = []
284 self.args = []
285 self.opts = []
285 self.opts = []
286 self.help = ''
286 self.help = ''
287 self.norepo = True
287 self.norepo = True
288 self.optionalrepo = False
288 self.optionalrepo = False
289 self.badalias = False
289 self.badalias = False
290
290
291 try:
291 try:
292 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
292 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
293 for alias, e in cmdtable.iteritems():
293 for alias, e in cmdtable.iteritems():
294 if e is entry:
294 if e is entry:
295 self.cmd = alias
295 self.cmd = alias
296 break
296 break
297 self.shadows = True
297 self.shadows = True
298 except error.UnknownCommand:
298 except error.UnknownCommand:
299 self.shadows = False
299 self.shadows = False
300
300
301 if not self.definition:
301 if not self.definition:
302 def fn(ui, *args):
302 def fn(ui, *args):
303 ui.warn(_("no definition for alias '%s'\n") % self.name)
303 ui.warn(_("no definition for alias '%s'\n") % self.name)
304 return 1
304 return 1
305 self.fn = fn
305 self.fn = fn
306 self.badalias = True
306 self.badalias = True
307 return
307 return
308
308
309 if self.definition.startswith('!'):
309 if self.definition.startswith('!'):
310 self.shell = True
310 self.shell = True
311 def fn(ui, *args):
311 def fn(ui, *args):
312 env = {'HG_ARGS': ' '.join((self.name,) + args)}
312 env = {'HG_ARGS': ' '.join((self.name,) + args)}
313 def _checkvar(m):
313 def _checkvar(m):
314 if m.groups()[0] == '$':
314 if m.groups()[0] == '$':
315 return m.group()
315 return m.group()
316 elif int(m.groups()[0]) <= len(args):
316 elif int(m.groups()[0]) <= len(args):
317 return m.group()
317 return m.group()
318 else:
318 else:
319 ui.debug("No argument found for substitution "
319 ui.debug("No argument found for substitution "
320 "of %i variable in alias '%s' definition."
320 "of %i variable in alias '%s' definition."
321 % (int(m.groups()[0]), self.name))
321 % (int(m.groups()[0]), self.name))
322 return ''
322 return ''
323 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
323 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
324 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
324 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
325 replace['0'] = self.name
325 replace['0'] = self.name
326 replace['@'] = ' '.join(args)
326 replace['@'] = ' '.join(args)
327 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
327 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
328 return util.system(cmd, environ=env, out=ui.fout)
328 return util.system(cmd, environ=env, out=ui.fout)
329 self.fn = fn
329 self.fn = fn
330 return
330 return
331
331
332 args = shlex.split(self.definition)
332 args = shlex.split(self.definition)
333 self.cmdname = cmd = args.pop(0)
333 self.cmdname = cmd = args.pop(0)
334 args = map(util.expandpath, args)
334 args = map(util.expandpath, args)
335
335
336 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
336 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
337 if _earlygetopt([invalidarg], args):
337 if _earlygetopt([invalidarg], args):
338 def fn(ui, *args):
338 def fn(ui, *args):
339 ui.warn(_("error in definition for alias '%s': %s may only "
339 ui.warn(_("error in definition for alias '%s': %s may only "
340 "be given on the command line\n")
340 "be given on the command line\n")
341 % (self.name, invalidarg))
341 % (self.name, invalidarg))
342 return 1
342 return 1
343
343
344 self.fn = fn
344 self.fn = fn
345 self.badalias = True
345 self.badalias = True
346 return
346 return
347
347
348 try:
348 try:
349 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
349 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
350 if len(tableentry) > 2:
350 if len(tableentry) > 2:
351 self.fn, self.opts, self.help = tableentry
351 self.fn, self.opts, self.help = tableentry
352 else:
352 else:
353 self.fn, self.opts = tableentry
353 self.fn, self.opts = tableentry
354
354
355 self.args = aliasargs(self.fn, args)
355 self.args = aliasargs(self.fn, args)
356 if cmd not in commands.norepo.split(' '):
356 if cmd not in commands.norepo.split(' '):
357 self.norepo = False
357 self.norepo = False
358 if cmd in commands.optionalrepo.split(' '):
358 if cmd in commands.optionalrepo.split(' '):
359 self.optionalrepo = True
359 self.optionalrepo = True
360 if self.help.startswith("hg " + cmd):
360 if self.help.startswith("hg " + cmd):
361 # drop prefix in old-style help lines so hg shows the alias
361 # drop prefix in old-style help lines so hg shows the alias
362 self.help = self.help[4 + len(cmd):]
362 self.help = self.help[4 + len(cmd):]
363 self.__doc__ = self.fn.__doc__
363 self.__doc__ = self.fn.__doc__
364
364
365 except error.UnknownCommand:
365 except error.UnknownCommand:
366 def fn(ui, *args):
366 def fn(ui, *args):
367 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
367 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
368 % (self.name, cmd))
368 % (self.name, cmd))
369 try:
369 try:
370 # check if the command is in a disabled extension
370 # check if the command is in a disabled extension
371 commands.help_(ui, cmd, unknowncmd=True)
371 commands.help_(ui, cmd, unknowncmd=True)
372 except error.UnknownCommand:
372 except error.UnknownCommand:
373 pass
373 pass
374 return 1
374 return 1
375 self.fn = fn
375 self.fn = fn
376 self.badalias = True
376 self.badalias = True
377 except error.AmbiguousCommand:
377 except error.AmbiguousCommand:
378 def fn(ui, *args):
378 def fn(ui, *args):
379 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
379 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
380 % (self.name, cmd))
380 % (self.name, cmd))
381 return 1
381 return 1
382 self.fn = fn
382 self.fn = fn
383 self.badalias = True
383 self.badalias = True
384
384
385 def __call__(self, ui, *args, **opts):
385 def __call__(self, ui, *args, **opts):
386 if self.shadows:
386 if self.shadows:
387 ui.debug("alias '%s' shadows command '%s'\n" %
387 ui.debug("alias '%s' shadows command '%s'\n" %
388 (self.name, self.cmdname))
388 (self.name, self.cmdname))
389
389
390 if util.safehasattr(self, 'shell'):
390 if util.safehasattr(self, 'shell'):
391 return self.fn(ui, *args, **opts)
391 return self.fn(ui, *args, **opts)
392 else:
392 else:
393 try:
393 try:
394 util.checksignature(self.fn)(ui, *args, **opts)
394 util.checksignature(self.fn)(ui, *args, **opts)
395 except error.SignatureError:
395 except error.SignatureError:
396 args = ' '.join([self.cmdname] + self.args)
396 args = ' '.join([self.cmdname] + self.args)
397 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
397 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
398 raise
398 raise
399
399
400 def addaliases(ui, cmdtable):
400 def addaliases(ui, cmdtable):
401 # aliases are processed after extensions have been loaded, so they
401 # aliases are processed after extensions have been loaded, so they
402 # may use extension commands. Aliases can also use other alias definitions,
402 # may use extension commands. Aliases can also use other alias definitions,
403 # but only if they have been defined prior to the current definition.
403 # but only if they have been defined prior to the current definition.
404 for alias, definition in ui.configitems('alias'):
404 for alias, definition in ui.configitems('alias'):
405 aliasdef = cmdalias(alias, definition, cmdtable)
405 aliasdef = cmdalias(alias, definition, cmdtable)
406
406
407 try:
407 try:
408 olddef = cmdtable[aliasdef.cmd][0]
408 olddef = cmdtable[aliasdef.cmd][0]
409 if olddef.definition == aliasdef.definition:
409 if olddef.definition == aliasdef.definition:
410 continue
410 continue
411 except (KeyError, AttributeError):
411 except (KeyError, AttributeError):
412 # definition might not exist or it might not be a cmdalias
412 # definition might not exist or it might not be a cmdalias
413 pass
413 pass
414
414
415 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
415 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
416 if aliasdef.norepo:
416 if aliasdef.norepo:
417 commands.norepo += ' %s' % alias
417 commands.norepo += ' %s' % alias
418 if aliasdef.optionalrepo:
418 if aliasdef.optionalrepo:
419 commands.optionalrepo += ' %s' % alias
419 commands.optionalrepo += ' %s' % alias
420
420
421 def _parse(ui, args):
421 def _parse(ui, args):
422 options = {}
422 options = {}
423 cmdoptions = {}
423 cmdoptions = {}
424
424
425 try:
425 try:
426 args = fancyopts.fancyopts(args, commands.globalopts, options)
426 args = fancyopts.fancyopts(args, commands.globalopts, options)
427 except fancyopts.getopt.GetoptError, inst:
427 except fancyopts.getopt.GetoptError, inst:
428 raise error.CommandError(None, inst)
428 raise error.CommandError(None, inst)
429
429
430 if args:
430 if args:
431 cmd, args = args[0], args[1:]
431 cmd, args = args[0], args[1:]
432 aliases, entry = cmdutil.findcmd(cmd, commands.table,
432 aliases, entry = cmdutil.findcmd(cmd, commands.table,
433 ui.configbool("ui", "strict"))
433 ui.configbool("ui", "strict"))
434 cmd = aliases[0]
434 cmd = aliases[0]
435 args = aliasargs(entry[0], args)
435 args = aliasargs(entry[0], args)
436 defaults = ui.config("defaults", cmd)
436 defaults = ui.config("defaults", cmd)
437 if defaults:
437 if defaults:
438 args = map(util.expandpath, shlex.split(defaults)) + args
438 args = map(util.expandpath, shlex.split(defaults)) + args
439 c = list(entry[1])
439 c = list(entry[1])
440 else:
440 else:
441 cmd = None
441 cmd = None
442 c = []
442 c = []
443
443
444 # combine global options into local
444 # combine global options into local
445 for o in commands.globalopts:
445 for o in commands.globalopts:
446 c.append((o[0], o[1], options[o[1]], o[3]))
446 c.append((o[0], o[1], options[o[1]], o[3]))
447
447
448 try:
448 try:
449 args = fancyopts.fancyopts(args, c, cmdoptions, True)
449 args = fancyopts.fancyopts(args, c, cmdoptions, True)
450 except fancyopts.getopt.GetoptError, inst:
450 except fancyopts.getopt.GetoptError, inst:
451 raise error.CommandError(cmd, inst)
451 raise error.CommandError(cmd, inst)
452
452
453 # separate global options back out
453 # separate global options back out
454 for o in commands.globalopts:
454 for o in commands.globalopts:
455 n = o[1]
455 n = o[1]
456 options[n] = cmdoptions[n]
456 options[n] = cmdoptions[n]
457 del cmdoptions[n]
457 del cmdoptions[n]
458
458
459 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
459 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
460
460
461 def _parseconfig(ui, config):
461 def _parseconfig(ui, config):
462 """parse the --config options from the command line"""
462 """parse the --config options from the command line"""
463 configs = []
463 configs = []
464
464
465 for cfg in config:
465 for cfg in config:
466 try:
466 try:
467 name, value = cfg.split('=', 1)
467 name, value = cfg.split('=', 1)
468 section, name = name.split('.', 1)
468 section, name = name.split('.', 1)
469 if not section or not name:
469 if not section or not name:
470 raise IndexError
470 raise IndexError
471 ui.setconfig(section, name, value)
471 ui.setconfig(section, name, value)
472 configs.append((section, name, value))
472 configs.append((section, name, value))
473 except (IndexError, ValueError):
473 except (IndexError, ValueError):
474 raise util.Abort(_('malformed --config option: %r '
474 raise util.Abort(_('malformed --config option: %r '
475 '(use --config section.name=value)') % cfg)
475 '(use --config section.name=value)') % cfg)
476
476
477 return configs
477 return configs
478
478
479 def _earlygetopt(aliases, args):
479 def _earlygetopt(aliases, args):
480 """Return list of values for an option (or aliases).
480 """Return list of values for an option (or aliases).
481
481
482 The values are listed in the order they appear in args.
482 The values are listed in the order they appear in args.
483 The options and values are removed from args.
483 The options and values are removed from args.
484 """
484 """
485 try:
485 try:
486 argcount = args.index("--")
486 argcount = args.index("--")
487 except ValueError:
487 except ValueError:
488 argcount = len(args)
488 argcount = len(args)
489 shortopts = [opt for opt in aliases if len(opt) == 2]
489 shortopts = [opt for opt in aliases if len(opt) == 2]
490 values = []
490 values = []
491 pos = 0
491 pos = 0
492 while pos < argcount:
492 while pos < argcount:
493 if args[pos] in aliases:
493 if args[pos] in aliases:
494 if pos + 1 >= argcount:
494 if pos + 1 >= argcount:
495 # ignore and let getopt report an error if there is no value
495 # ignore and let getopt report an error if there is no value
496 break
496 break
497 del args[pos]
497 del args[pos]
498 values.append(args.pop(pos))
498 values.append(args.pop(pos))
499 argcount -= 2
499 argcount -= 2
500 elif args[pos][:2] in shortopts:
500 elif args[pos][:2] in shortopts:
501 # short option can have no following space, e.g. hg log -Rfoo
501 # short option can have no following space, e.g. hg log -Rfoo
502 values.append(args.pop(pos)[2:])
502 values.append(args.pop(pos)[2:])
503 argcount -= 1
503 argcount -= 1
504 else:
504 else:
505 pos += 1
505 pos += 1
506 return values
506 return values
507
507
508 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
508 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
509 # run pre-hook, and abort if it fails
509 # run pre-hook, and abort if it fails
510 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
510 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
511 pats=cmdpats, opts=cmdoptions)
511 pats=cmdpats, opts=cmdoptions)
512 if ret:
512 if ret:
513 return ret
513 return ret
514 ret = _runcommand(ui, options, cmd, d)
514 ret = _runcommand(ui, options, cmd, d)
515 # run post-hook, passing command result
515 # run post-hook, passing command result
516 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
516 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
517 result=ret, pats=cmdpats, opts=cmdoptions)
517 result=ret, pats=cmdpats, opts=cmdoptions)
518 return ret
518 return ret
519
519
520 def _getlocal(ui, rpath):
520 def _getlocal(ui, rpath):
521 """Return (path, local ui object) for the given target path.
521 """Return (path, local ui object) for the given target path.
522
522
523 Takes paths in [cwd]/.hg/hgrc into account."
523 Takes paths in [cwd]/.hg/hgrc into account."
524 """
524 """
525 try:
525 try:
526 wd = os.getcwd()
526 wd = os.getcwd()
527 except OSError, e:
527 except OSError, e:
528 raise util.Abort(_("error getting current working directory: %s") %
528 raise util.Abort(_("error getting current working directory: %s") %
529 e.strerror)
529 e.strerror)
530 path = cmdutil.findrepo(wd) or ""
530 path = cmdutil.findrepo(wd) or ""
531 if not path:
531 if not path:
532 lui = ui
532 lui = ui
533 else:
533 else:
534 lui = ui.copy()
534 lui = ui.copy()
535 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
535 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
536
536
537 if rpath and rpath[-1]:
537 if rpath and rpath[-1]:
538 path = lui.expandpath(rpath[-1])
538 path = lui.expandpath(rpath[-1])
539 lui = ui.copy()
539 lui = ui.copy()
540 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
540 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
541
541
542 return path, lui
542 return path, lui
543
543
544 def _checkshellalias(lui, ui, args):
544 def _checkshellalias(lui, ui, args):
545 options = {}
545 options = {}
546
546
547 try:
547 try:
548 args = fancyopts.fancyopts(args, commands.globalopts, options)
548 args = fancyopts.fancyopts(args, commands.globalopts, options)
549 except fancyopts.getopt.GetoptError:
549 except fancyopts.getopt.GetoptError:
550 return
550 return
551
551
552 if not args:
552 if not args:
553 return
553 return
554
554
555 norepo = commands.norepo
555 norepo = commands.norepo
556 optionalrepo = commands.optionalrepo
556 optionalrepo = commands.optionalrepo
557 def restorecommands():
557 def restorecommands():
558 commands.norepo = norepo
558 commands.norepo = norepo
559 commands.optionalrepo = optionalrepo
559 commands.optionalrepo = optionalrepo
560
560
561 cmdtable = commands.table.copy()
561 cmdtable = commands.table.copy()
562 addaliases(lui, cmdtable)
562 addaliases(lui, cmdtable)
563
563
564 cmd = args[0]
564 cmd = args[0]
565 try:
565 try:
566 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
566 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
567 lui.configbool("ui", "strict"))
567 lui.configbool("ui", "strict"))
568 except (error.AmbiguousCommand, error.UnknownCommand):
568 except (error.AmbiguousCommand, error.UnknownCommand):
569 restorecommands()
569 restorecommands()
570 return
570 return
571
571
572 cmd = aliases[0]
572 cmd = aliases[0]
573 fn = entry[0]
573 fn = entry[0]
574
574
575 if cmd and util.safehasattr(fn, 'shell'):
575 if cmd and util.safehasattr(fn, 'shell'):
576 d = lambda: fn(ui, *args[1:])
576 d = lambda: fn(ui, *args[1:])
577 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
577 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
578 [], {})
578 [], {})
579
579
580 restorecommands()
580 restorecommands()
581
581
582 _loaded = set()
582 _loaded = set()
583 def _dispatch(req):
583 def _dispatch(req):
584 args = req.args
584 args = req.args
585 ui = req.ui
585 ui = req.ui
586
586
587 # read --config before doing anything else
587 # read --config before doing anything else
588 # (e.g. to change trust settings for reading .hg/hgrc)
588 # (e.g. to change trust settings for reading .hg/hgrc)
589 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
589 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
590
590
591 # check for cwd
591 # check for cwd
592 cwd = _earlygetopt(['--cwd'], args)
592 cwd = _earlygetopt(['--cwd'], args)
593 if cwd:
593 if cwd:
594 os.chdir(cwd[-1])
594 os.chdir(cwd[-1])
595
595
596 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
596 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
597 path, lui = _getlocal(ui, rpath)
597 path, lui = _getlocal(ui, rpath)
598
598
599 # Now that we're operating in the right directory/repository with
599 # Now that we're operating in the right directory/repository with
600 # the right config settings, check for shell aliases
600 # the right config settings, check for shell aliases
601 shellaliasfn = _checkshellalias(lui, ui, args)
601 shellaliasfn = _checkshellalias(lui, ui, args)
602 if shellaliasfn:
602 if shellaliasfn:
603 return shellaliasfn()
603 return shellaliasfn()
604
604
605 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
605 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
606 # reposetup. Programs like TortoiseHg will call _dispatch several
606 # reposetup. Programs like TortoiseHg will call _dispatch several
607 # times so we keep track of configured extensions in _loaded.
607 # times so we keep track of configured extensions in _loaded.
608 extensions.loadall(lui)
608 extensions.loadall(lui)
609 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
609 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
610 # Propagate any changes to lui.__class__ by extensions
610 # Propagate any changes to lui.__class__ by extensions
611 ui.__class__ = lui.__class__
611 ui.__class__ = lui.__class__
612
612
613 # (uisetup and extsetup are handled in extensions.loadall)
613 # (uisetup and extsetup are handled in extensions.loadall)
614
614
615 for name, module in exts:
615 for name, module in exts:
616 cmdtable = getattr(module, 'cmdtable', {})
616 cmdtable = getattr(module, 'cmdtable', {})
617 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
617 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
618 if overrides:
618 if overrides:
619 ui.warn(_("extension '%s' overrides commands: %s\n")
619 ui.warn(_("extension '%s' overrides commands: %s\n")
620 % (name, " ".join(overrides)))
620 % (name, " ".join(overrides)))
621 commands.table.update(cmdtable)
621 commands.table.update(cmdtable)
622 _loaded.add(name)
622 _loaded.add(name)
623
623
624 # (reposetup is handled in hg.repository)
624 # (reposetup is handled in hg.repository)
625
625
626 addaliases(lui, commands.table)
626 addaliases(lui, commands.table)
627
627
628 # check for fallback encoding
628 # check for fallback encoding
629 fallback = lui.config('ui', 'fallbackencoding')
629 fallback = lui.config('ui', 'fallbackencoding')
630 if fallback:
630 if fallback:
631 encoding.fallbackencoding = fallback
631 encoding.fallbackencoding = fallback
632
632
633 fullargs = args
633 fullargs = args
634 cmd, func, args, options, cmdoptions = _parse(lui, args)
634 cmd, func, args, options, cmdoptions = _parse(lui, args)
635
635
636 if options["config"]:
636 if options["config"]:
637 raise util.Abort(_("option --config may not be abbreviated!"))
637 raise util.Abort(_("option --config may not be abbreviated!"))
638 if options["cwd"]:
638 if options["cwd"]:
639 raise util.Abort(_("option --cwd may not be abbreviated!"))
639 raise util.Abort(_("option --cwd may not be abbreviated!"))
640 if options["repository"]:
640 if options["repository"]:
641 raise util.Abort(_(
641 raise util.Abort(_(
642 "option -R has to be separated from other options (e.g. not -qR) "
642 "option -R has to be separated from other options (e.g. not -qR) "
643 "and --repository may only be abbreviated as --repo!"))
643 "and --repository may only be abbreviated as --repo!"))
644
644
645 if options["encoding"]:
645 if options["encoding"]:
646 encoding.encoding = options["encoding"]
646 encoding.encoding = options["encoding"]
647 if options["encodingmode"]:
647 if options["encodingmode"]:
648 encoding.encodingmode = options["encodingmode"]
648 encoding.encodingmode = options["encodingmode"]
649 if options["time"]:
649 if options["time"]:
650 def get_times():
650 def get_times():
651 t = os.times()
651 t = os.times()
652 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
652 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
653 t = (t[0], t[1], t[2], t[3], time.clock())
653 t = (t[0], t[1], t[2], t[3], time.clock())
654 return t
654 return t
655 s = get_times()
655 s = get_times()
656 def print_time():
656 def print_time():
657 t = get_times()
657 t = get_times()
658 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
658 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
659 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
659 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
660 atexit.register(print_time)
660 atexit.register(print_time)
661
661
662 uis = set([ui, lui])
662 uis = set([ui, lui])
663
663
664 if req.repo:
664 if req.repo:
665 uis.add(req.repo.ui)
665 uis.add(req.repo.ui)
666
666
667 # copy configs that were passed on the cmdline (--config) to the repo ui
667 # copy configs that were passed on the cmdline (--config) to the repo ui
668 for cfg in cfgs:
668 for cfg in cfgs:
669 req.repo.ui.setconfig(*cfg)
669 req.repo.ui.setconfig(*cfg)
670
670
671 if options['verbose'] or options['debug'] or options['quiet']:
671 if options['verbose'] or options['debug'] or options['quiet']:
672 for opt in ('verbose', 'debug', 'quiet'):
672 for opt in ('verbose', 'debug', 'quiet'):
673 val = str(bool(options[opt]))
673 val = str(bool(options[opt]))
674 for ui_ in uis:
674 for ui_ in uis:
675 ui_.setconfig('ui', opt, val)
675 ui_.setconfig('ui', opt, val)
676
676
677 if options['traceback']:
677 if options['traceback']:
678 for ui_ in uis:
678 for ui_ in uis:
679 ui_.setconfig('ui', 'traceback', 'on')
679 ui_.setconfig('ui', 'traceback', 'on')
680
680
681 if options['noninteractive']:
681 if options['noninteractive']:
682 for ui_ in uis:
682 for ui_ in uis:
683 ui_.setconfig('ui', 'interactive', 'off')
683 ui_.setconfig('ui', 'interactive', 'off')
684
684
685 if cmdoptions.get('insecure', False):
685 if cmdoptions.get('insecure', False):
686 for ui_ in uis:
686 for ui_ in uis:
687 ui_.setconfig('web', 'cacerts', '')
687 ui_.setconfig('web', 'cacerts', '')
688
688
689 if options['version']:
689 if options['version']:
690 return commands.version_(ui)
690 return commands.version_(ui)
691 if options['help']:
691 if options['help']:
692 return commands.help_(ui, cmd)
692 return commands.help_(ui, cmd)
693 elif not cmd:
693 elif not cmd:
694 return commands.help_(ui, 'shortlist')
694 return commands.help_(ui, 'shortlist')
695
695
696 repo = None
696 repo = None
697 cmdpats = args[:]
697 cmdpats = args[:]
698 if cmd not in commands.norepo.split():
698 if cmd not in commands.norepo.split():
699 # use the repo from the request only if we don't have -R
699 # use the repo from the request only if we don't have -R
700 if not rpath and not cwd:
700 if not rpath and not cwd:
701 repo = req.repo
701 repo = req.repo
702
702
703 if repo:
703 if repo:
704 # set the descriptors of the repo ui to those of ui
704 # set the descriptors of the repo ui to those of ui
705 repo.ui.fin = ui.fin
705 repo.ui.fin = ui.fin
706 repo.ui.fout = ui.fout
706 repo.ui.fout = ui.fout
707 repo.ui.ferr = ui.ferr
707 repo.ui.ferr = ui.ferr
708 else:
708 else:
709 try:
709 try:
710 repo = hg.repository(ui, path=path)
710 repo = hg.repository(ui, path=path)
711 if not repo.local():
711 if not repo.local():
712 raise util.Abort(_("repository '%s' is not local") % path)
712 raise util.Abort(_("repository '%s' is not local") % path)
713 if not options['hidden']:
714 repo = repo.filtered('hidden')
715 else:
716 repo = repo.unfiltered()
713 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
717 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
714 except error.RequirementError:
718 except error.RequirementError:
715 raise
719 raise
716 except error.RepoError:
720 except error.RepoError:
717 if cmd not in commands.optionalrepo.split():
721 if cmd not in commands.optionalrepo.split():
718 if (cmd in commands.inferrepo.split() and
722 if (cmd in commands.inferrepo.split() and
719 args and not path): # try to infer -R from command args
723 args and not path): # try to infer -R from command args
720 repos = map(cmdutil.findrepo, args)
724 repos = map(cmdutil.findrepo, args)
721 guess = repos[0]
725 guess = repos[0]
722 if guess and repos.count(guess) == len(repos):
726 if guess and repos.count(guess) == len(repos):
723 req.args = ['--repository', guess] + fullargs
727 req.args = ['--repository', guess] + fullargs
724 return _dispatch(req)
728 return _dispatch(req)
725 if not path:
729 if not path:
726 raise error.RepoError(_("no repository found in '%s'"
730 raise error.RepoError(_("no repository found in '%s'"
727 " (.hg not found)")
731 " (.hg not found)")
728 % os.getcwd())
732 % os.getcwd())
729 raise
733 raise
730 if repo:
734 if repo:
731 ui = repo.ui
735 ui = repo.ui
732 args.insert(0, repo)
736 args.insert(0, repo)
733 elif rpath:
737 elif rpath:
734 ui.warn(_("warning: --repository ignored\n"))
738 ui.warn(_("warning: --repository ignored\n"))
735
739
736 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
740 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
737 ui.log("command", msg + "\n")
741 ui.log("command", msg + "\n")
738 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
742 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
739 try:
743 try:
740 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
744 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
741 cmdpats, cmdoptions)
745 cmdpats, cmdoptions)
742 finally:
746 finally:
743 if repo and repo != req.repo:
747 if repo and repo != req.repo:
744 repo.close()
748 repo.close()
745
749
746 def lsprofile(ui, func, fp):
750 def lsprofile(ui, func, fp):
747 format = ui.config('profiling', 'format', default='text')
751 format = ui.config('profiling', 'format', default='text')
748 field = ui.config('profiling', 'sort', default='inlinetime')
752 field = ui.config('profiling', 'sort', default='inlinetime')
749 climit = ui.configint('profiling', 'nested', default=5)
753 climit = ui.configint('profiling', 'nested', default=5)
750
754
751 if format not in ['text', 'kcachegrind']:
755 if format not in ['text', 'kcachegrind']:
752 ui.warn(_("unrecognized profiling format '%s'"
756 ui.warn(_("unrecognized profiling format '%s'"
753 " - Ignored\n") % format)
757 " - Ignored\n") % format)
754 format = 'text'
758 format = 'text'
755
759
756 try:
760 try:
757 from mercurial import lsprof
761 from mercurial import lsprof
758 except ImportError:
762 except ImportError:
759 raise util.Abort(_(
763 raise util.Abort(_(
760 'lsprof not available - install from '
764 'lsprof not available - install from '
761 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
765 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
762 p = lsprof.Profiler()
766 p = lsprof.Profiler()
763 p.enable(subcalls=True)
767 p.enable(subcalls=True)
764 try:
768 try:
765 return func()
769 return func()
766 finally:
770 finally:
767 p.disable()
771 p.disable()
768
772
769 if format == 'kcachegrind':
773 if format == 'kcachegrind':
770 import lsprofcalltree
774 import lsprofcalltree
771 calltree = lsprofcalltree.KCacheGrind(p)
775 calltree = lsprofcalltree.KCacheGrind(p)
772 calltree.output(fp)
776 calltree.output(fp)
773 else:
777 else:
774 # format == 'text'
778 # format == 'text'
775 stats = lsprof.Stats(p.getstats())
779 stats = lsprof.Stats(p.getstats())
776 stats.sort(field)
780 stats.sort(field)
777 stats.pprint(limit=30, file=fp, climit=climit)
781 stats.pprint(limit=30, file=fp, climit=climit)
778
782
779 def statprofile(ui, func, fp):
783 def statprofile(ui, func, fp):
780 try:
784 try:
781 import statprof
785 import statprof
782 except ImportError:
786 except ImportError:
783 raise util.Abort(_(
787 raise util.Abort(_(
784 'statprof not available - install using "easy_install statprof"'))
788 'statprof not available - install using "easy_install statprof"'))
785
789
786 freq = ui.configint('profiling', 'freq', default=1000)
790 freq = ui.configint('profiling', 'freq', default=1000)
787 if freq > 0:
791 if freq > 0:
788 statprof.reset(freq)
792 statprof.reset(freq)
789 else:
793 else:
790 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
794 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
791
795
792 statprof.start()
796 statprof.start()
793 try:
797 try:
794 return func()
798 return func()
795 finally:
799 finally:
796 statprof.stop()
800 statprof.stop()
797 statprof.display(fp)
801 statprof.display(fp)
798
802
799 def _runcommand(ui, options, cmd, cmdfunc):
803 def _runcommand(ui, options, cmd, cmdfunc):
800 def checkargs():
804 def checkargs():
801 try:
805 try:
802 return cmdfunc()
806 return cmdfunc()
803 except error.SignatureError:
807 except error.SignatureError:
804 raise error.CommandError(cmd, _("invalid arguments"))
808 raise error.CommandError(cmd, _("invalid arguments"))
805
809
806 if options['profile']:
810 if options['profile']:
807 profiler = os.getenv('HGPROF')
811 profiler = os.getenv('HGPROF')
808 if profiler is None:
812 if profiler is None:
809 profiler = ui.config('profiling', 'type', default='ls')
813 profiler = ui.config('profiling', 'type', default='ls')
810 if profiler not in ('ls', 'stat'):
814 if profiler not in ('ls', 'stat'):
811 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
815 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
812 profiler = 'ls'
816 profiler = 'ls'
813
817
814 output = ui.config('profiling', 'output')
818 output = ui.config('profiling', 'output')
815
819
816 if output:
820 if output:
817 path = ui.expandpath(output)
821 path = ui.expandpath(output)
818 fp = open(path, 'wb')
822 fp = open(path, 'wb')
819 else:
823 else:
820 fp = sys.stderr
824 fp = sys.stderr
821
825
822 try:
826 try:
823 if profiler == 'ls':
827 if profiler == 'ls':
824 return lsprofile(ui, checkargs, fp)
828 return lsprofile(ui, checkargs, fp)
825 else:
829 else:
826 return statprofile(ui, checkargs, fp)
830 return statprofile(ui, checkargs, fp)
827 finally:
831 finally:
828 if output:
832 if output:
829 fp.close()
833 fp.close()
830 else:
834 else:
831 return checkargs()
835 return checkargs()
@@ -1,521 +1,521 b''
1 $ hg init
1 $ hg init
2
2
3 Setup:
3 Setup:
4
4
5 $ echo a >> a
5 $ echo a >> a
6 $ hg ci -Am 'base'
6 $ hg ci -Am 'base'
7 adding a
7 adding a
8
8
9 Refuse to amend public csets:
9 Refuse to amend public csets:
10
10
11 $ hg phase -r . -p
11 $ hg phase -r . -p
12 $ hg ci --amend
12 $ hg ci --amend
13 abort: cannot amend public changesets
13 abort: cannot amend public changesets
14 [255]
14 [255]
15 $ hg phase -r . -f -d
15 $ hg phase -r . -f -d
16
16
17 $ echo a >> a
17 $ echo a >> a
18 $ hg ci -Am 'base1'
18 $ hg ci -Am 'base1'
19
19
20 Nothing to amend:
20 Nothing to amend:
21
21
22 $ hg ci --amend
22 $ hg ci --amend
23 nothing changed
23 nothing changed
24 [1]
24 [1]
25
25
26 $ cat >> $HGRCPATH <<EOF
26 $ cat >> $HGRCPATH <<EOF
27 > [hooks]
27 > [hooks]
28 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
28 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
29 > EOF
29 > EOF
30
30
31 Amending changeset with changes in working dir:
31 Amending changeset with changes in working dir:
32 (and check that --message does not trigger an editor)
32 (and check that --message does not trigger an editor)
33
33
34 $ echo a >> a
34 $ echo a >> a
35 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
35 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
36 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
36 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
37 43f1ba15f28a tip
37 43f1ba15f28a tip
38 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-amend-backup.hg (glob)
38 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-amend-backup.hg (glob)
39 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
39 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
40 $ hg diff -c .
40 $ hg diff -c .
41 diff -r ad120869acf0 -r 43f1ba15f28a a
41 diff -r ad120869acf0 -r 43f1ba15f28a a
42 --- a/a Thu Jan 01 00:00:00 1970 +0000
42 --- a/a Thu Jan 01 00:00:00 1970 +0000
43 +++ b/a Thu Jan 01 00:00:00 1970 +0000
43 +++ b/a Thu Jan 01 00:00:00 1970 +0000
44 @@ -1,1 +1,3 @@
44 @@ -1,1 +1,3 @@
45 a
45 a
46 +a
46 +a
47 +a
47 +a
48 $ hg log
48 $ hg log
49 changeset: 1:43f1ba15f28a
49 changeset: 1:43f1ba15f28a
50 tag: tip
50 tag: tip
51 user: test
51 user: test
52 date: Thu Jan 01 00:00:00 1970 +0000
52 date: Thu Jan 01 00:00:00 1970 +0000
53 summary: amend base1
53 summary: amend base1
54
54
55 changeset: 0:ad120869acf0
55 changeset: 0:ad120869acf0
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
57 date: Thu Jan 01 00:00:00 1970 +0000
58 summary: base
58 summary: base
59
59
60
60
61 Check proper abort for empty message
61 Check proper abort for empty message
62
62
63 $ cat > editor.sh << '__EOF__'
63 $ cat > editor.sh << '__EOF__'
64 > #!/bin/sh
64 > #!/bin/sh
65 > echo "" > "$1"
65 > echo "" > "$1"
66 > __EOF__
66 > __EOF__
67 $ echo b > b
67 $ echo b > b
68 $ hg add b
68 $ hg add b
69 $ hg summary
69 $ hg summary
70 parent: 1:43f1ba15f28a tip
70 parent: 1:43f1ba15f28a tip
71 amend base1
71 amend base1
72 branch: default
72 branch: default
73 commit: 1 added, 1 unknown
73 commit: 1 added, 1 unknown
74 update: (current)
74 update: (current)
75 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
75 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
76 transaction abort!
76 transaction abort!
77 rollback completed
77 rollback completed
78 abort: empty commit message
78 abort: empty commit message
79 [255]
79 [255]
80 $ hg summary
80 $ hg summary
81 parent: 1:43f1ba15f28a tip
81 parent: 1:43f1ba15f28a tip
82 amend base1
82 amend base1
83 branch: default
83 branch: default
84 commit: 1 added, 1 unknown
84 commit: 1 added, 1 unknown
85 update: (current)
85 update: (current)
86
86
87 Add new file:
87 Add new file:
88 $ hg ci --amend -m 'amend base1 new file'
88 $ hg ci --amend -m 'amend base1 new file'
89 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-amend-backup.hg (glob)
89 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-amend-backup.hg (glob)
90
90
91 Remove file that was added in amended commit:
91 Remove file that was added in amended commit:
92 (and test logfile option)
92 (and test logfile option)
93 (and test that logfile option do not trigger an editor)
93 (and test that logfile option do not trigger an editor)
94
94
95 $ hg rm b
95 $ hg rm b
96 $ echo 'amend base1 remove new file' > ../logfile
96 $ echo 'amend base1 remove new file' > ../logfile
97 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
97 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
98 saved backup bundle to $TESTTMP/.hg/strip-backup/b8e3cb2b3882-amend-backup.hg (glob)
98 saved backup bundle to $TESTTMP/.hg/strip-backup/b8e3cb2b3882-amend-backup.hg (glob)
99
99
100 $ hg cat b
100 $ hg cat b
101 b: no such file in rev 74609c7f506e
101 b: no such file in rev 74609c7f506e
102 [1]
102 [1]
103
103
104 No changes, just a different message:
104 No changes, just a different message:
105
105
106 $ hg ci -v --amend -m 'no changes, new message'
106 $ hg ci -v --amend -m 'no changes, new message'
107 amending changeset 74609c7f506e
107 amending changeset 74609c7f506e
108 copying changeset 74609c7f506e to ad120869acf0
108 copying changeset 74609c7f506e to ad120869acf0
109 a
109 a
110 stripping amended changeset 74609c7f506e
110 stripping amended changeset 74609c7f506e
111 1 changesets found
111 1 changesets found
112 saved backup bundle to $TESTTMP/.hg/strip-backup/74609c7f506e-amend-backup.hg (glob)
112 saved backup bundle to $TESTTMP/.hg/strip-backup/74609c7f506e-amend-backup.hg (glob)
113 1 changesets found
113 1 changesets found
114 adding branch
114 adding branch
115 adding changesets
115 adding changesets
116 adding manifests
116 adding manifests
117 adding file changes
117 adding file changes
118 added 1 changesets with 1 changes to 1 files
118 added 1 changesets with 1 changes to 1 files
119 committed changeset 1:1cd866679df8
119 committed changeset 1:1cd866679df8
120 $ hg diff -c .
120 $ hg diff -c .
121 diff -r ad120869acf0 -r 1cd866679df8 a
121 diff -r ad120869acf0 -r 1cd866679df8 a
122 --- a/a Thu Jan 01 00:00:00 1970 +0000
122 --- a/a Thu Jan 01 00:00:00 1970 +0000
123 +++ b/a Thu Jan 01 00:00:00 1970 +0000
123 +++ b/a Thu Jan 01 00:00:00 1970 +0000
124 @@ -1,1 +1,3 @@
124 @@ -1,1 +1,3 @@
125 a
125 a
126 +a
126 +a
127 +a
127 +a
128 $ hg log
128 $ hg log
129 changeset: 1:1cd866679df8
129 changeset: 1:1cd866679df8
130 tag: tip
130 tag: tip
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 summary: no changes, new message
133 summary: no changes, new message
134
134
135 changeset: 0:ad120869acf0
135 changeset: 0:ad120869acf0
136 user: test
136 user: test
137 date: Thu Jan 01 00:00:00 1970 +0000
137 date: Thu Jan 01 00:00:00 1970 +0000
138 summary: base
138 summary: base
139
139
140
140
141 Disable default date on commit so when -d isn't given, the old date is preserved:
141 Disable default date on commit so when -d isn't given, the old date is preserved:
142
142
143 $ echo '[defaults]' >> $HGRCPATH
143 $ echo '[defaults]' >> $HGRCPATH
144 $ echo 'commit=' >> $HGRCPATH
144 $ echo 'commit=' >> $HGRCPATH
145
145
146 Test -u/-d:
146 Test -u/-d:
147
147
148 $ hg ci --amend -u foo -d '1 0'
148 $ hg ci --amend -u foo -d '1 0'
149 saved backup bundle to $TESTTMP/.hg/strip-backup/1cd866679df8-amend-backup.hg (glob)
149 saved backup bundle to $TESTTMP/.hg/strip-backup/1cd866679df8-amend-backup.hg (glob)
150 $ echo a >> a
150 $ echo a >> a
151 $ hg ci --amend -u foo -d '1 0'
151 $ hg ci --amend -u foo -d '1 0'
152 saved backup bundle to $TESTTMP/.hg/strip-backup/780e6f23e03d-amend-backup.hg (glob)
152 saved backup bundle to $TESTTMP/.hg/strip-backup/780e6f23e03d-amend-backup.hg (glob)
153 $ hg log -r .
153 $ hg log -r .
154 changeset: 1:5f357c7560ab
154 changeset: 1:5f357c7560ab
155 tag: tip
155 tag: tip
156 user: foo
156 user: foo
157 date: Thu Jan 01 00:00:01 1970 +0000
157 date: Thu Jan 01 00:00:01 1970 +0000
158 summary: no changes, new message
158 summary: no changes, new message
159
159
160
160
161 Open editor with old commit message if a message isn't given otherwise:
161 Open editor with old commit message if a message isn't given otherwise:
162
162
163 $ cat > editor.sh << '__EOF__'
163 $ cat > editor.sh << '__EOF__'
164 > #!/bin/sh
164 > #!/bin/sh
165 > cat $1
165 > cat $1
166 > echo "another precious commit message" > "$1"
166 > echo "another precious commit message" > "$1"
167 > __EOF__
167 > __EOF__
168 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
168 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
169 amending changeset 5f357c7560ab
169 amending changeset 5f357c7560ab
170 copying changeset 5f357c7560ab to ad120869acf0
170 copying changeset 5f357c7560ab to ad120869acf0
171 no changes, new message
171 no changes, new message
172
172
173
173
174 HG: Enter commit message. Lines beginning with 'HG:' are removed.
174 HG: Enter commit message. Lines beginning with 'HG:' are removed.
175 HG: Leave message empty to abort commit.
175 HG: Leave message empty to abort commit.
176 HG: --
176 HG: --
177 HG: user: foo
177 HG: user: foo
178 HG: branch 'default'
178 HG: branch 'default'
179 HG: changed a
179 HG: changed a
180 a
180 a
181 stripping amended changeset 5f357c7560ab
181 stripping amended changeset 5f357c7560ab
182 1 changesets found
182 1 changesets found
183 saved backup bundle to $TESTTMP/.hg/strip-backup/5f357c7560ab-amend-backup.hg (glob)
183 saved backup bundle to $TESTTMP/.hg/strip-backup/5f357c7560ab-amend-backup.hg (glob)
184 1 changesets found
184 1 changesets found
185 adding branch
185 adding branch
186 adding changesets
186 adding changesets
187 adding manifests
187 adding manifests
188 adding file changes
188 adding file changes
189 added 1 changesets with 1 changes to 1 files
189 added 1 changesets with 1 changes to 1 files
190 committed changeset 1:7ab3bf440b54
190 committed changeset 1:7ab3bf440b54
191
191
192 Same, but with changes in working dir (different code path):
192 Same, but with changes in working dir (different code path):
193
193
194 $ echo a >> a
194 $ echo a >> a
195 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
195 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
196 amending changeset 7ab3bf440b54
196 amending changeset 7ab3bf440b54
197 a
197 a
198 copying changeset a0ea9b1a4c8c to ad120869acf0
198 copying changeset a0ea9b1a4c8c to ad120869acf0
199 another precious commit message
199 another precious commit message
200
200
201
201
202 HG: Enter commit message. Lines beginning with 'HG:' are removed.
202 HG: Enter commit message. Lines beginning with 'HG:' are removed.
203 HG: Leave message empty to abort commit.
203 HG: Leave message empty to abort commit.
204 HG: --
204 HG: --
205 HG: user: foo
205 HG: user: foo
206 HG: branch 'default'
206 HG: branch 'default'
207 HG: changed a
207 HG: changed a
208 a
208 a
209 stripping intermediate changeset a0ea9b1a4c8c
209 stripping intermediate changeset a0ea9b1a4c8c
210 stripping amended changeset 7ab3bf440b54
210 stripping amended changeset 7ab3bf440b54
211 2 changesets found
211 2 changesets found
212 saved backup bundle to $TESTTMP/.hg/strip-backup/7ab3bf440b54-amend-backup.hg (glob)
212 saved backup bundle to $TESTTMP/.hg/strip-backup/7ab3bf440b54-amend-backup.hg (glob)
213 1 changesets found
213 1 changesets found
214 adding branch
214 adding branch
215 adding changesets
215 adding changesets
216 adding manifests
216 adding manifests
217 adding file changes
217 adding file changes
218 added 1 changesets with 1 changes to 1 files
218 added 1 changesets with 1 changes to 1 files
219 committed changeset 1:ea22a388757c
219 committed changeset 1:ea22a388757c
220
220
221 $ rm editor.sh
221 $ rm editor.sh
222 $ hg log -r .
222 $ hg log -r .
223 changeset: 1:ea22a388757c
223 changeset: 1:ea22a388757c
224 tag: tip
224 tag: tip
225 user: foo
225 user: foo
226 date: Thu Jan 01 00:00:01 1970 +0000
226 date: Thu Jan 01 00:00:01 1970 +0000
227 summary: another precious commit message
227 summary: another precious commit message
228
228
229
229
230 Moving bookmarks, preserve active bookmark:
230 Moving bookmarks, preserve active bookmark:
231
231
232 $ hg book book1
232 $ hg book book1
233 $ hg book book2
233 $ hg book book2
234 $ hg ci --amend -m 'move bookmarks'
234 $ hg ci --amend -m 'move bookmarks'
235 saved backup bundle to $TESTTMP/.hg/strip-backup/ea22a388757c-amend-backup.hg (glob)
235 saved backup bundle to $TESTTMP/.hg/strip-backup/ea22a388757c-amend-backup.hg (glob)
236 $ hg book
236 $ hg book
237 book1 1:6cec5aa930e2
237 book1 1:6cec5aa930e2
238 * book2 1:6cec5aa930e2
238 * book2 1:6cec5aa930e2
239 $ echo a >> a
239 $ echo a >> a
240 $ hg ci --amend -m 'move bookmarks'
240 $ hg ci --amend -m 'move bookmarks'
241 saved backup bundle to $TESTTMP/.hg/strip-backup/6cec5aa930e2-amend-backup.hg (glob)
241 saved backup bundle to $TESTTMP/.hg/strip-backup/6cec5aa930e2-amend-backup.hg (glob)
242 $ hg book
242 $ hg book
243 book1 1:48bb6e53a15f
243 book1 1:48bb6e53a15f
244 * book2 1:48bb6e53a15f
244 * book2 1:48bb6e53a15f
245
245
246 abort does not loose bookmarks
246 abort does not loose bookmarks
247
247
248 $ cat > editor.sh << '__EOF__'
248 $ cat > editor.sh << '__EOF__'
249 > #!/bin/sh
249 > #!/bin/sh
250 > echo "" > "$1"
250 > echo "" > "$1"
251 > __EOF__
251 > __EOF__
252 $ echo a >> a
252 $ echo a >> a
253 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
253 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
254 transaction abort!
254 transaction abort!
255 rollback completed
255 rollback completed
256 abort: empty commit message
256 abort: empty commit message
257 [255]
257 [255]
258 $ hg book
258 $ hg book
259 book1 1:48bb6e53a15f
259 book1 1:48bb6e53a15f
260 * book2 1:48bb6e53a15f
260 * book2 1:48bb6e53a15f
261 $ hg revert -Caq
261 $ hg revert -Caq
262 $ rm editor.sh
262 $ rm editor.sh
263
263
264 $ echo '[defaults]' >> $HGRCPATH
264 $ echo '[defaults]' >> $HGRCPATH
265 $ echo "commit=-d '0 0'" >> $HGRCPATH
265 $ echo "commit=-d '0 0'" >> $HGRCPATH
266
266
267 Moving branches:
267 Moving branches:
268
268
269 $ hg branch foo
269 $ hg branch foo
270 marked working directory as branch foo
270 marked working directory as branch foo
271 (branches are permanent and global, did you want a bookmark?)
271 (branches are permanent and global, did you want a bookmark?)
272 $ echo a >> a
272 $ echo a >> a
273 $ hg ci -m 'branch foo'
273 $ hg ci -m 'branch foo'
274 $ hg branch default -f
274 $ hg branch default -f
275 marked working directory as branch default
275 marked working directory as branch default
276 (branches are permanent and global, did you want a bookmark?)
276 (branches are permanent and global, did you want a bookmark?)
277 $ hg ci --amend -m 'back to default'
277 $ hg ci --amend -m 'back to default'
278 saved backup bundle to $TESTTMP/.hg/strip-backup/8ac881fbf49d-amend-backup.hg (glob)
278 saved backup bundle to $TESTTMP/.hg/strip-backup/8ac881fbf49d-amend-backup.hg (glob)
279 $ hg branches
279 $ hg branches
280 default 2:ce12b0b57d46
280 default 2:ce12b0b57d46
281
281
282 Close branch:
282 Close branch:
283
283
284 $ hg up -q 0
284 $ hg up -q 0
285 $ echo b >> b
285 $ echo b >> b
286 $ hg branch foo
286 $ hg branch foo
287 marked working directory as branch foo
287 marked working directory as branch foo
288 (branches are permanent and global, did you want a bookmark?)
288 (branches are permanent and global, did you want a bookmark?)
289 $ hg ci -Am 'fork'
289 $ hg ci -Am 'fork'
290 adding b
290 adding b
291 $ echo b >> b
291 $ echo b >> b
292 $ hg ci -mb
292 $ hg ci -mb
293 $ hg ci --amend --close-branch -m 'closing branch foo'
293 $ hg ci --amend --close-branch -m 'closing branch foo'
294 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-amend-backup.hg (glob)
294 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-amend-backup.hg (glob)
295
295
296 Same thing, different code path:
296 Same thing, different code path:
297
297
298 $ echo b >> b
298 $ echo b >> b
299 $ hg ci -m 'reopen branch'
299 $ hg ci -m 'reopen branch'
300 reopening closed branch head 4
300 reopening closed branch head 4
301 $ echo b >> b
301 $ echo b >> b
302 $ hg ci --amend --close-branch
302 $ hg ci --amend --close-branch
303 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-amend-backup.hg (glob)
303 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-amend-backup.hg (glob)
304 $ hg branches
304 $ hg branches
305 default 2:ce12b0b57d46
305 default 2:ce12b0b57d46
306
306
307 Refuse to amend merges:
307 Refuse to amend merges:
308
308
309 $ hg up -q default
309 $ hg up -q default
310 $ hg merge foo
310 $ hg merge foo
311 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 (branch merge, don't forget to commit)
312 (branch merge, don't forget to commit)
313 $ hg ci --amend
313 $ hg ci --amend
314 abort: cannot amend while merging
314 abort: cannot amend while merging
315 [255]
315 [255]
316 $ hg ci -m 'merge'
316 $ hg ci -m 'merge'
317 $ hg ci --amend
317 $ hg ci --amend
318 abort: cannot amend merge changesets
318 abort: cannot amend merge changesets
319 [255]
319 [255]
320
320
321 Follow copies/renames:
321 Follow copies/renames:
322
322
323 $ hg mv b c
323 $ hg mv b c
324 $ hg ci -m 'b -> c'
324 $ hg ci -m 'b -> c'
325 $ hg mv c d
325 $ hg mv c d
326 $ hg ci --amend -m 'b -> d'
326 $ hg ci --amend -m 'b -> d'
327 saved backup bundle to $TESTTMP/.hg/strip-backup/b8c6eac7f12e-amend-backup.hg (glob)
327 saved backup bundle to $TESTTMP/.hg/strip-backup/b8c6eac7f12e-amend-backup.hg (glob)
328 $ hg st --rev '.^' --copies d
328 $ hg st --rev '.^' --copies d
329 A d
329 A d
330 b
330 b
331 $ hg cp d e
331 $ hg cp d e
332 $ hg ci -m 'e = d'
332 $ hg ci -m 'e = d'
333 $ hg cp e f
333 $ hg cp e f
334 $ hg ci --amend -m 'f = d'
334 $ hg ci --amend -m 'f = d'
335 saved backup bundle to $TESTTMP/.hg/strip-backup/7f9761d65613-amend-backup.hg (glob)
335 saved backup bundle to $TESTTMP/.hg/strip-backup/7f9761d65613-amend-backup.hg (glob)
336 $ hg st --rev '.^' --copies f
336 $ hg st --rev '.^' --copies f
337 A f
337 A f
338 d
338 d
339
339
340 $ mv f f.orig
340 $ mv f f.orig
341 $ hg rm -A f
341 $ hg rm -A f
342 $ hg ci -m removef
342 $ hg ci -m removef
343 $ hg cp a f
343 $ hg cp a f
344 $ mv f.orig f
344 $ mv f.orig f
345 $ hg ci --amend -m replacef
345 $ hg ci --amend -m replacef
346 saved backup bundle to $TESTTMP/.hg/strip-backup/9e8c5f7e3d95-amend-backup.hg (glob)
346 saved backup bundle to $TESTTMP/.hg/strip-backup/9e8c5f7e3d95-amend-backup.hg (glob)
347 $ hg st --change . --copies
347 $ hg st --change . --copies
348 $ hg log -r . --template "{file_copies}\n"
348 $ hg log -r . --template "{file_copies}\n"
349
349
350
350
351 Move added file (issue3410):
351 Move added file (issue3410):
352
352
353 $ echo g >> g
353 $ echo g >> g
354 $ hg ci -Am g
354 $ hg ci -Am g
355 adding g
355 adding g
356 $ hg mv g h
356 $ hg mv g h
357 $ hg ci --amend
357 $ hg ci --amend
358 saved backup bundle to $TESTTMP/.hg/strip-backup/24aa8eacce2b-amend-backup.hg (glob)
358 saved backup bundle to $TESTTMP/.hg/strip-backup/24aa8eacce2b-amend-backup.hg (glob)
359 $ hg st --change . --copies h
359 $ hg st --change . --copies h
360 A h
360 A h
361 $ hg log -r . --template "{file_copies}\n"
361 $ hg log -r . --template "{file_copies}\n"
362
362
363
363
364 Can't rollback an amend:
364 Can't rollback an amend:
365
365
366 $ hg rollback
366 $ hg rollback
367 no rollback information available
367 no rollback information available
368 [1]
368 [1]
369
369
370 Preserve extra dict (issue3430):
370 Preserve extra dict (issue3430):
371
371
372 $ hg branch a
372 $ hg branch a
373 marked working directory as branch a
373 marked working directory as branch a
374 (branches are permanent and global, did you want a bookmark?)
374 (branches are permanent and global, did you want a bookmark?)
375 $ echo a >> a
375 $ echo a >> a
376 $ hg ci -ma
376 $ hg ci -ma
377 $ hg ci --amend -m "a'"
377 $ hg ci --amend -m "a'"
378 saved backup bundle to $TESTTMP/.hg/strip-backup/3837aa2a2fdb-amend-backup.hg (glob)
378 saved backup bundle to $TESTTMP/.hg/strip-backup/3837aa2a2fdb-amend-backup.hg (glob)
379 $ hg log -r . --template "{branch}\n"
379 $ hg log -r . --template "{branch}\n"
380 a
380 a
381 $ hg ci --amend -m "a''"
381 $ hg ci --amend -m "a''"
382 saved backup bundle to $TESTTMP/.hg/strip-backup/c05c06be7514-amend-backup.hg (glob)
382 saved backup bundle to $TESTTMP/.hg/strip-backup/c05c06be7514-amend-backup.hg (glob)
383 $ hg log -r . --template "{branch}\n"
383 $ hg log -r . --template "{branch}\n"
384 a
384 a
385
385
386 Also preserve other entries in the dict that are in the old commit,
386 Also preserve other entries in the dict that are in the old commit,
387 first graft something so there's an additional entry:
387 first graft something so there's an additional entry:
388
388
389 $ hg up 0 -q
389 $ hg up 0 -q
390 $ echo z > z
390 $ echo z > z
391 $ hg ci -Am 'fork'
391 $ hg ci -Am 'fork'
392 adding z
392 adding z
393 created new head
393 created new head
394 $ hg up 11
394 $ hg up 11
395 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
395 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
396 $ hg graft 12
396 $ hg graft 12
397 grafting revision 12
397 grafting revision 12
398 $ hg ci --amend -m 'graft amend'
398 $ hg ci --amend -m 'graft amend'
399 saved backup bundle to $TESTTMP/.hg/strip-backup/bd010aea3f39-amend-backup.hg (glob)
399 saved backup bundle to $TESTTMP/.hg/strip-backup/bd010aea3f39-amend-backup.hg (glob)
400 $ hg log -r . --debug | grep extra
400 $ hg log -r . --debug | grep extra
401 extra: amend_source=bd010aea3f39f3fb2a2f884b9ccb0471cd77398e
401 extra: amend_source=bd010aea3f39f3fb2a2f884b9ccb0471cd77398e
402 extra: branch=a
402 extra: branch=a
403 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
403 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
404
404
405 Preserve phase
405 Preserve phase
406
406
407 $ hg phase '.^::.'
407 $ hg phase '.^::.'
408 11: draft
408 11: draft
409 13: draft
409 13: draft
410 $ hg phase --secret --force .
410 $ hg phase --secret --force .
411 $ hg phase '.^::.'
411 $ hg phase '.^::.'
412 11: draft
412 11: draft
413 13: secret
413 13: secret
414 $ hg commit --amend -m 'amend for phase' -q
414 $ hg commit --amend -m 'amend for phase' -q
415 $ hg phase '.^::.'
415 $ hg phase '.^::.'
416 11: draft
416 11: draft
417 13: secret
417 13: secret
418
418
419 Test amend with obsolete
419 Test amend with obsolete
420 ---------------------------
420 ---------------------------
421
421
422 Enable obsolete
422 Enable obsolete
423
423
424 $ cat > ${TESTTMP}/obs.py << EOF
424 $ cat > ${TESTTMP}/obs.py << EOF
425 > import mercurial.obsolete
425 > import mercurial.obsolete
426 > mercurial.obsolete._enabled = True
426 > mercurial.obsolete._enabled = True
427 > EOF
427 > EOF
428 $ echo '[extensions]' >> $HGRCPATH
428 $ echo '[extensions]' >> $HGRCPATH
429 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
429 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
430
430
431
431
432 Amend with no files changes
432 Amend with no files changes
433
433
434 $ hg id -n
434 $ hg id -n
435 13
435 13
436 $ hg ci --amend -m 'babar'
436 $ hg ci --amend -m 'babar'
437 $ hg id -n
437 $ hg id -n
438 14
438 14
439 $ hg log -Gl 3 --style=compact
439 $ hg log -Gl 3 --style=compact
440 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
440 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
441 | babar
441 | babar
442 |
442 |
443 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
443 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
444 | | fork
444 | | fork
445 | |
445 | |
446 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
446 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
447 | | a''
447 | | a''
448 | |
448 | |
449 $ hg log -Gl 4 --hidden --style=compact
449 $ hg log -Gl 4 --hidden --style=compact
450 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
450 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
451 | babar
451 | babar
452 |
452 |
453 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
453 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
454 |/ amend for phase
454 |/ amend for phase
455 |
455 |
456 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
456 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
457 | | fork
457 | | fork
458 | |
458 | |
459 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
459 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
460 | | a''
460 | | a''
461 | |
461 | |
462
462
463 Amend with files changes
463 Amend with files changes
464
464
465 (note: the extra commit over 15 is a temporary junk I would be happy to get
465 (note: the extra commit over 15 is a temporary junk I would be happy to get
466 ride of)
466 ride of)
467
467
468 $ echo 'babar' >> a
468 $ echo 'babar' >> a
469 $ hg commit --amend
469 $ hg commit --amend
470 $ hg log -Gl 6 --hidden --style=compact
470 $ hg log -Gl 6 --hidden --style=compact
471 @ 16[tip]:11 9f9e9bccf56c 1970-01-01 00:00 +0000 test
471 @ 16[tip]:11 9f9e9bccf56c 1970-01-01 00:00 +0000 test
472 | babar
472 | babar
473 |
473 |
474 | x 15 90fef497c56f 1970-01-01 00:00 +0000 test
474 | x 15 90fef497c56f 1970-01-01 00:00 +0000 test
475 | | temporary amend commit for b650e6ee8614
475 | | temporary amend commit for b650e6ee8614
476 | |
476 | |
477 | x 14:11 b650e6ee8614 1970-01-01 00:00 +0000 test
477 | x 14:11 b650e6ee8614 1970-01-01 00:00 +0000 test
478 |/ babar
478 |/ babar
479 |
479 |
480 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
480 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
481 |/ amend for phase
481 |/ amend for phase
482 |
482 |
483 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
483 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
484 | | fork
484 | | fork
485 | |
485 | |
486 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
486 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
487 | | a''
487 | | a''
488 | |
488 | |
489
489
490
490
491 Test that amend does not make it easy to create obsoletescence cycle
491 Test that amend does not make it easy to create obsoletescence cycle
492 ---------------------------------------------------------------------
492 ---------------------------------------------------------------------
493
493
494
494
495 $ hg id -r 14
495 $ hg id -r 14 --hidden
496 b650e6ee8614 (a)
496 b650e6ee8614 (a)
497 $ hg revert -ar 14
497 $ hg revert -ar 14 --hidden
498 reverting a
498 reverting a
499 $ hg commit --amend
499 $ hg commit --amend
500 $ hg id
500 $ hg id
501 b99e5df575f7 (a) tip
501 b99e5df575f7 (a) tip
502
502
503 Test ui.prevent-unstable
503 Test ui.prevent-unstable
504 ---------------------------------------------------------------------
504 ---------------------------------------------------------------------
505
505
506 $ hg up '.^'
506 $ hg up '.^'
507 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
507 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
508 $ echo 'b' >> a
508 $ echo 'b' >> a
509 $ hg log --style compact -r 'children(.)'
509 $ hg log --style compact -r 'children(.)'
510 18[tip]:11 b99e5df575f7 1970-01-01 00:00 +0000 test
510 18[tip]:11 b99e5df575f7 1970-01-01 00:00 +0000 test
511 babar
511 babar
512
512
513 $ hg commit --amend
513 $ hg commit --amend
514 $ hg log -r 'unstable()'
514 $ hg log -r 'unstable()'
515 changeset: 18:b99e5df575f7
515 changeset: 18:b99e5df575f7
516 branch: a
516 branch: a
517 parent: 11:3334b7925910
517 parent: 11:3334b7925910
518 user: test
518 user: test
519 date: Thu Jan 01 00:00:00 1970 +0000
519 date: Thu Jan 01 00:00:00 1970 +0000
520 summary: babar
520 summary: babar
521
521
@@ -1,278 +1,280 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 debugsuccessorssets
99 debugsuccessorssets
100 debugwalk
100 debugwalk
101 debugwireargs
101 debugwireargs
102
102
103 Do not show the alias of a debug command if there are other candidates
103 Do not show the alias of a debug command if there are other candidates
104 (this should hide rawcommit)
104 (this should hide rawcommit)
105 $ hg debugcomplete r
105 $ hg debugcomplete r
106 recover
106 recover
107 remove
107 remove
108 rename
108 rename
109 resolve
109 resolve
110 revert
110 revert
111 rollback
111 rollback
112 root
112 root
113 Show the alias of a debug command if there are no other candidates
113 Show the alias of a debug command if there are no other candidates
114 $ hg debugcomplete rawc
114 $ hg debugcomplete rawc
115
115
116
116
117 Show the global options
117 Show the global options
118 $ hg debugcomplete --options | sort
118 $ hg debugcomplete --options | sort
119 --config
119 --config
120 --cwd
120 --cwd
121 --debug
121 --debug
122 --debugger
122 --debugger
123 --encoding
123 --encoding
124 --encodingmode
124 --encodingmode
125 --help
125 --help
126 --hidden
126 --noninteractive
127 --noninteractive
127 --profile
128 --profile
128 --quiet
129 --quiet
129 --repository
130 --repository
130 --time
131 --time
131 --traceback
132 --traceback
132 --verbose
133 --verbose
133 --version
134 --version
134 -R
135 -R
135 -h
136 -h
136 -q
137 -q
137 -v
138 -v
138 -y
139 -y
139
140
140 Show the options for the "serve" command
141 Show the options for the "serve" command
141 $ hg debugcomplete --options serve | sort
142 $ hg debugcomplete --options serve | sort
142 --accesslog
143 --accesslog
143 --address
144 --address
144 --certificate
145 --certificate
145 --cmdserver
146 --cmdserver
146 --config
147 --config
147 --cwd
148 --cwd
148 --daemon
149 --daemon
149 --daemon-pipefds
150 --daemon-pipefds
150 --debug
151 --debug
151 --debugger
152 --debugger
152 --encoding
153 --encoding
153 --encodingmode
154 --encodingmode
154 --errorlog
155 --errorlog
155 --help
156 --help
157 --hidden
156 --ipv6
158 --ipv6
157 --name
159 --name
158 --noninteractive
160 --noninteractive
159 --pid-file
161 --pid-file
160 --port
162 --port
161 --prefix
163 --prefix
162 --profile
164 --profile
163 --quiet
165 --quiet
164 --repository
166 --repository
165 --stdio
167 --stdio
166 --style
168 --style
167 --templates
169 --templates
168 --time
170 --time
169 --traceback
171 --traceback
170 --verbose
172 --verbose
171 --version
173 --version
172 --web-conf
174 --web-conf
173 -6
175 -6
174 -A
176 -A
175 -E
177 -E
176 -R
178 -R
177 -a
179 -a
178 -d
180 -d
179 -h
181 -h
180 -n
182 -n
181 -p
183 -p
182 -q
184 -q
183 -t
185 -t
184 -v
186 -v
185 -y
187 -y
186
188
187 Show an error if we use --options with an ambiguous abbreviation
189 Show an error if we use --options with an ambiguous abbreviation
188 $ hg debugcomplete --options s
190 $ hg debugcomplete --options s
189 hg: command 's' is ambiguous:
191 hg: command 's' is ambiguous:
190 serve showconfig status summary
192 serve showconfig status summary
191 [255]
193 [255]
192
194
193 Show all commands + options
195 Show all commands + options
194 $ hg debugcommands
196 $ hg debugcommands
195 add: include, exclude, subrepos, dry-run
197 add: include, exclude, subrepos, dry-run
196 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
198 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
197 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
199 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
198 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
200 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
199 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
201 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
200 export: output, switch-parent, rev, text, git, nodates
202 export: output, switch-parent, rev, text, git, nodates
201 forget: include, exclude
203 forget: include, exclude
202 init: ssh, remotecmd, insecure
204 init: ssh, remotecmd, insecure
203 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
205 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
204 merge: force, rev, preview, tool
206 merge: force, rev, preview, tool
205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
207 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
208 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
207 remove: after, force, include, exclude
209 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
210 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
211 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
210 summary: remote
212 summary: remote
211 update: clean, check, date, rev
213 update: clean, check, date, rev
212 addremove: similarity, include, exclude, dry-run
214 addremove: similarity, include, exclude, dry-run
213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
215 archive: no-decode, prefix, rev, type, subrepos, include, exclude
214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
216 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
215 bisect: reset, good, bad, skip, extend, command, noupdate
217 bisect: reset, good, bad, skip, extend, command, noupdate
216 bookmarks: force, rev, delete, rename, inactive
218 bookmarks: force, rev, delete, rename, inactive
217 branch: force, clean
219 branch: force, clean
218 branches: active, closed
220 branches: active, closed
219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
221 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
220 cat: output, rev, decode, include, exclude
222 cat: output, rev, decode, include, exclude
221 copy: after, force, include, exclude, dry-run
223 copy: after, force, include, exclude, dry-run
222 debugancestor:
224 debugancestor:
223 debugbuilddag: mergeable-file, overwritten-file, new-file
225 debugbuilddag: mergeable-file, overwritten-file, new-file
224 debugbundle: all
226 debugbundle: all
225 debugcheckstate:
227 debugcheckstate:
226 debugcommands:
228 debugcommands:
227 debugcomplete: options
229 debugcomplete: options
228 debugdag: tags, branches, dots, spaces
230 debugdag: tags, branches, dots, spaces
229 debugdata: changelog, manifest
231 debugdata: changelog, manifest
230 debugdate: extended
232 debugdate: extended
231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
233 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
232 debugfileset: rev
234 debugfileset: rev
233 debugfsinfo:
235 debugfsinfo:
234 debuggetbundle: head, common, type
236 debuggetbundle: head, common, type
235 debugignore:
237 debugignore:
236 debugindex: changelog, manifest, format
238 debugindex: changelog, manifest, format
237 debugindexdot:
239 debugindexdot:
238 debuginstall:
240 debuginstall:
239 debugknown:
241 debugknown:
240 debugobsolete: flags, date, user
242 debugobsolete: flags, date, user
241 debugpushkey:
243 debugpushkey:
242 debugpvec:
244 debugpvec:
243 debugrebuildstate: rev
245 debugrebuildstate: rev
244 debugrename: rev
246 debugrename: rev
245 debugrevlog: changelog, manifest, dump
247 debugrevlog: changelog, manifest, dump
246 debugrevspec:
248 debugrevspec:
247 debugsetparents:
249 debugsetparents:
248 debugstate: nodates, datesort
250 debugstate: nodates, datesort
249 debugsub: rev
251 debugsub: rev
250 debugsuccessorssets:
252 debugsuccessorssets:
251 debugwalk: include, exclude
253 debugwalk: include, exclude
252 debugwireargs: three, four, five, ssh, remotecmd, insecure
254 debugwireargs: three, four, five, ssh, remotecmd, insecure
253 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
255 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
254 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
256 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
255 heads: rev, topo, active, closed, style, template
257 heads: rev, topo, active, closed, style, template
256 help: extension, command, keyword
258 help: extension, command, keyword
257 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
259 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
258 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
260 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
259 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
261 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
260 locate: rev, print0, fullpath, include, exclude
262 locate: rev, print0, fullpath, include, exclude
261 manifest: rev, all
263 manifest: rev, all
262 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
264 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
263 parents: rev, style, template
265 parents: rev, style, template
264 paths:
266 paths:
265 phase: public, draft, secret, force, rev
267 phase: public, draft, secret, force, rev
266 recover:
268 recover:
267 rename: after, force, include, exclude, dry-run
269 rename: after, force, include, exclude, dry-run
268 resolve: all, list, mark, unmark, no-status, tool, include, exclude
270 resolve: all, list, mark, unmark, no-status, tool, include, exclude
269 revert: all, date, rev, no-backup, include, exclude, dry-run
271 revert: all, date, rev, no-backup, include, exclude, dry-run
270 rollback: dry-run, force
272 rollback: dry-run, force
271 root:
273 root:
272 showconfig: untrusted
274 showconfig: untrusted
273 tag: force, local, rev, remove, edit, message, date, user
275 tag: force, local, rev, remove, edit, message, date, user
274 tags:
276 tags:
275 tip: patch, git, style, template
277 tip: patch, git, style, template
276 unbundle: update
278 unbundle: update
277 verify:
279 verify:
278 version:
280 version:
@@ -1,571 +1,573 b''
1 Test basic extension support
1 Test basic extension support
2
2
3 $ cat > foobar.py <<EOF
3 $ cat > foobar.py <<EOF
4 > import os
4 > import os
5 > from mercurial import commands
5 > from mercurial import commands
6 >
6 >
7 > def uisetup(ui):
7 > def uisetup(ui):
8 > ui.write("uisetup called\\n")
8 > ui.write("uisetup called\\n")
9 >
9 >
10 > def reposetup(ui, repo):
10 > def reposetup(ui, repo):
11 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
11 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
12 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
12 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
13 >
13 >
14 > def foo(ui, *args, **kwargs):
14 > def foo(ui, *args, **kwargs):
15 > ui.write("Foo\\n")
15 > ui.write("Foo\\n")
16 >
16 >
17 > def bar(ui, *args, **kwargs):
17 > def bar(ui, *args, **kwargs):
18 > ui.write("Bar\\n")
18 > ui.write("Bar\\n")
19 >
19 >
20 > cmdtable = {
20 > cmdtable = {
21 > "foo": (foo, [], "hg foo"),
21 > "foo": (foo, [], "hg foo"),
22 > "bar": (bar, [], "hg bar"),
22 > "bar": (bar, [], "hg bar"),
23 > }
23 > }
24 >
24 >
25 > commands.norepo += ' bar'
25 > commands.norepo += ' bar'
26 > EOF
26 > EOF
27 $ abspath=`pwd`/foobar.py
27 $ abspath=`pwd`/foobar.py
28
28
29 $ mkdir barfoo
29 $ mkdir barfoo
30 $ cp foobar.py barfoo/__init__.py
30 $ cp foobar.py barfoo/__init__.py
31 $ barfoopath=`pwd`/barfoo
31 $ barfoopath=`pwd`/barfoo
32
32
33 $ hg init a
33 $ hg init a
34 $ cd a
34 $ cd a
35 $ echo foo > file
35 $ echo foo > file
36 $ hg add file
36 $ hg add file
37 $ hg commit -m 'add file'
37 $ hg commit -m 'add file'
38
38
39 $ echo '[extensions]' >> $HGRCPATH
39 $ echo '[extensions]' >> $HGRCPATH
40 $ echo "foobar = $abspath" >> $HGRCPATH
40 $ echo "foobar = $abspath" >> $HGRCPATH
41 $ hg foo
41 $ hg foo
42 uisetup called
42 uisetup called
43 reposetup called for a
43 reposetup called for a
44 ui == repo.ui
44 ui == repo.ui
45 Foo
45 Foo
46
46
47 $ cd ..
47 $ cd ..
48 $ hg clone a b
48 $ hg clone a b
49 uisetup called
49 uisetup called
50 reposetup called for a
50 reposetup called for a
51 ui == repo.ui
51 ui == repo.ui
52 reposetup called for b
52 reposetup called for b
53 ui == repo.ui
53 ui == repo.ui
54 updating to branch default
54 updating to branch default
55 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
56
56
57 $ hg bar
57 $ hg bar
58 uisetup called
58 uisetup called
59 Bar
59 Bar
60 $ echo 'foobar = !' >> $HGRCPATH
60 $ echo 'foobar = !' >> $HGRCPATH
61
61
62 module/__init__.py-style
62 module/__init__.py-style
63
63
64 $ echo "barfoo = $barfoopath" >> $HGRCPATH
64 $ echo "barfoo = $barfoopath" >> $HGRCPATH
65 $ cd a
65 $ cd a
66 $ hg foo
66 $ hg foo
67 uisetup called
67 uisetup called
68 reposetup called for a
68 reposetup called for a
69 ui == repo.ui
69 ui == repo.ui
70 Foo
70 Foo
71 $ echo 'barfoo = !' >> $HGRCPATH
71 $ echo 'barfoo = !' >> $HGRCPATH
72
72
73 Check that extensions are loaded in phases:
73 Check that extensions are loaded in phases:
74
74
75 $ cat > foo.py <<EOF
75 $ cat > foo.py <<EOF
76 > import os
76 > import os
77 > name = os.path.basename(__file__).rsplit('.', 1)[0]
77 > name = os.path.basename(__file__).rsplit('.', 1)[0]
78 > print "1) %s imported" % name
78 > print "1) %s imported" % name
79 > def uisetup(ui):
79 > def uisetup(ui):
80 > print "2) %s uisetup" % name
80 > print "2) %s uisetup" % name
81 > def extsetup():
81 > def extsetup():
82 > print "3) %s extsetup" % name
82 > print "3) %s extsetup" % name
83 > def reposetup(ui, repo):
83 > def reposetup(ui, repo):
84 > print "4) %s reposetup" % name
84 > print "4) %s reposetup" % name
85 > EOF
85 > EOF
86
86
87 $ cp foo.py bar.py
87 $ cp foo.py bar.py
88 $ echo 'foo = foo.py' >> $HGRCPATH
88 $ echo 'foo = foo.py' >> $HGRCPATH
89 $ echo 'bar = bar.py' >> $HGRCPATH
89 $ echo 'bar = bar.py' >> $HGRCPATH
90
90
91 Command with no output, we just want to see the extensions loaded:
91 Command with no output, we just want to see the extensions loaded:
92
92
93 $ hg paths
93 $ hg paths
94 1) foo imported
94 1) foo imported
95 1) bar imported
95 1) bar imported
96 2) foo uisetup
96 2) foo uisetup
97 2) bar uisetup
97 2) bar uisetup
98 3) foo extsetup
98 3) foo extsetup
99 3) bar extsetup
99 3) bar extsetup
100 4) foo reposetup
100 4) foo reposetup
101 4) bar reposetup
101 4) bar reposetup
102
102
103 Check hgweb's load order:
103 Check hgweb's load order:
104
104
105 $ cat > hgweb.cgi <<EOF
105 $ cat > hgweb.cgi <<EOF
106 > #!/usr/bin/env python
106 > #!/usr/bin/env python
107 > from mercurial import demandimport; demandimport.enable()
107 > from mercurial import demandimport; demandimport.enable()
108 > from mercurial.hgweb import hgweb
108 > from mercurial.hgweb import hgweb
109 > from mercurial.hgweb import wsgicgi
109 > from mercurial.hgweb import wsgicgi
110 >
110 >
111 > application = hgweb('.', 'test repo')
111 > application = hgweb('.', 'test repo')
112 > wsgicgi.launch(application)
112 > wsgicgi.launch(application)
113 > EOF
113 > EOF
114
114
115 $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
115 $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
116 > | grep '^[0-9]) ' # ignores HTML output
116 > | grep '^[0-9]) ' # ignores HTML output
117 1) foo imported
117 1) foo imported
118 1) bar imported
118 1) bar imported
119 2) foo uisetup
119 2) foo uisetup
120 2) bar uisetup
120 2) bar uisetup
121 3) foo extsetup
121 3) foo extsetup
122 3) bar extsetup
122 3) bar extsetup
123 4) foo reposetup
123 4) foo reposetup
124 4) bar reposetup
124 4) bar reposetup
125 4) foo reposetup
125 4) foo reposetup
126 4) bar reposetup
126 4) bar reposetup
127
127
128 $ echo 'foo = !' >> $HGRCPATH
128 $ echo 'foo = !' >> $HGRCPATH
129 $ echo 'bar = !' >> $HGRCPATH
129 $ echo 'bar = !' >> $HGRCPATH
130
130
131 $ cd ..
131 $ cd ..
132
132
133 hide outer repo
133 hide outer repo
134 $ hg init
134 $ hg init
135
135
136 $ cat > empty.py <<EOF
136 $ cat > empty.py <<EOF
137 > '''empty cmdtable
137 > '''empty cmdtable
138 > '''
138 > '''
139 > cmdtable = {}
139 > cmdtable = {}
140 > EOF
140 > EOF
141 $ emptypath=`pwd`/empty.py
141 $ emptypath=`pwd`/empty.py
142 $ echo "empty = $emptypath" >> $HGRCPATH
142 $ echo "empty = $emptypath" >> $HGRCPATH
143 $ hg help empty
143 $ hg help empty
144 empty extension - empty cmdtable
144 empty extension - empty cmdtable
145
145
146 no commands defined
146 no commands defined
147
147
148 $ echo 'empty = !' >> $HGRCPATH
148 $ echo 'empty = !' >> $HGRCPATH
149
149
150 $ cat > debugextension.py <<EOF
150 $ cat > debugextension.py <<EOF
151 > '''only debugcommands
151 > '''only debugcommands
152 > '''
152 > '''
153 > def debugfoobar(ui, repo, *args, **opts):
153 > def debugfoobar(ui, repo, *args, **opts):
154 > "yet another debug command"
154 > "yet another debug command"
155 > pass
155 > pass
156 >
156 >
157 > def foo(ui, repo, *args, **opts):
157 > def foo(ui, repo, *args, **opts):
158 > """yet another foo command
158 > """yet another foo command
159 >
159 >
160 > This command has been DEPRECATED since forever.
160 > This command has been DEPRECATED since forever.
161 > """
161 > """
162 > pass
162 > pass
163 >
163 >
164 > cmdtable = {
164 > cmdtable = {
165 > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
165 > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
166 > "foo": (foo, (), "hg foo")
166 > "foo": (foo, (), "hg foo")
167 > }
167 > }
168 > EOF
168 > EOF
169 $ debugpath=`pwd`/debugextension.py
169 $ debugpath=`pwd`/debugextension.py
170 $ echo "debugextension = $debugpath" >> $HGRCPATH
170 $ echo "debugextension = $debugpath" >> $HGRCPATH
171
171
172 $ hg help debugextension
172 $ hg help debugextension
173 debugextension extension - only debugcommands
173 debugextension extension - only debugcommands
174
174
175 no commands defined
175 no commands defined
176
176
177 $ hg --verbose help debugextension
177 $ hg --verbose help debugextension
178 debugextension extension - only debugcommands
178 debugextension extension - only debugcommands
179
179
180 list of commands:
180 list of commands:
181
181
182 foo yet another foo command
182 foo yet another foo command
183
183
184 global options:
184 global options:
185
185
186 -R --repository REPO repository root directory or name of overlay bundle
186 -R --repository REPO repository root directory or name of overlay bundle
187 file
187 file
188 --cwd DIR change working directory
188 --cwd DIR change working directory
189 -y --noninteractive do not prompt, automatically pick the first choice for
189 -y --noninteractive do not prompt, automatically pick the first choice for
190 all prompts
190 all prompts
191 -q --quiet suppress output
191 -q --quiet suppress output
192 -v --verbose enable additional output
192 -v --verbose enable additional output
193 --config CONFIG [+] set/override config option (use 'section.name=value')
193 --config CONFIG [+] set/override config option (use 'section.name=value')
194 --debug enable debugging output
194 --debug enable debugging output
195 --debugger start debugger
195 --debugger start debugger
196 --encoding ENCODE set the charset encoding (default: ascii)
196 --encoding ENCODE set the charset encoding (default: ascii)
197 --encodingmode MODE set the charset encoding mode (default: strict)
197 --encodingmode MODE set the charset encoding mode (default: strict)
198 --traceback always print a traceback on exception
198 --traceback always print a traceback on exception
199 --time time how long the command takes
199 --time time how long the command takes
200 --profile print command execution profile
200 --profile print command execution profile
201 --version output version information and exit
201 --version output version information and exit
202 -h --help display help and exit
202 -h --help display help and exit
203 --hidden consider hidden changesets
203
204
204 [+] marked option can be specified multiple times
205 [+] marked option can be specified multiple times
205
206
206 $ hg --debug help debugextension
207 $ hg --debug help debugextension
207 debugextension extension - only debugcommands
208 debugextension extension - only debugcommands
208
209
209 list of commands:
210 list of commands:
210
211
211 debugfoobar yet another debug command
212 debugfoobar yet another debug command
212 foo yet another foo command
213 foo yet another foo command
213
214
214 global options:
215 global options:
215
216
216 -R --repository REPO repository root directory or name of overlay bundle
217 -R --repository REPO repository root directory or name of overlay bundle
217 file
218 file
218 --cwd DIR change working directory
219 --cwd DIR change working directory
219 -y --noninteractive do not prompt, automatically pick the first choice for
220 -y --noninteractive do not prompt, automatically pick the first choice for
220 all prompts
221 all prompts
221 -q --quiet suppress output
222 -q --quiet suppress output
222 -v --verbose enable additional output
223 -v --verbose enable additional output
223 --config CONFIG [+] set/override config option (use 'section.name=value')
224 --config CONFIG [+] set/override config option (use 'section.name=value')
224 --debug enable debugging output
225 --debug enable debugging output
225 --debugger start debugger
226 --debugger start debugger
226 --encoding ENCODE set the charset encoding (default: ascii)
227 --encoding ENCODE set the charset encoding (default: ascii)
227 --encodingmode MODE set the charset encoding mode (default: strict)
228 --encodingmode MODE set the charset encoding mode (default: strict)
228 --traceback always print a traceback on exception
229 --traceback always print a traceback on exception
229 --time time how long the command takes
230 --time time how long the command takes
230 --profile print command execution profile
231 --profile print command execution profile
231 --version output version information and exit
232 --version output version information and exit
232 -h --help display help and exit
233 -h --help display help and exit
234 --hidden consider hidden changesets
233
235
234 [+] marked option can be specified multiple times
236 [+] marked option can be specified multiple times
235 $ echo 'debugextension = !' >> $HGRCPATH
237 $ echo 'debugextension = !' >> $HGRCPATH
236
238
237 Extension module help vs command help:
239 Extension module help vs command help:
238
240
239 $ echo 'extdiff =' >> $HGRCPATH
241 $ echo 'extdiff =' >> $HGRCPATH
240 $ hg help extdiff
242 $ hg help extdiff
241 hg extdiff [OPT]... [FILE]...
243 hg extdiff [OPT]... [FILE]...
242
244
243 use external program to diff repository (or selected files)
245 use external program to diff repository (or selected files)
244
246
245 Show differences between revisions for the specified files, using an
247 Show differences between revisions for the specified files, using an
246 external program. The default program used is diff, with default options
248 external program. The default program used is diff, with default options
247 "-Npru".
249 "-Npru".
248
250
249 To select a different program, use the -p/--program option. The program
251 To select a different program, use the -p/--program option. The program
250 will be passed the names of two directories to compare. To pass additional
252 will be passed the names of two directories to compare. To pass additional
251 options to the program, use -o/--option. These will be passed before the
253 options to the program, use -o/--option. These will be passed before the
252 names of the directories to compare.
254 names of the directories to compare.
253
255
254 When two revision arguments are given, then changes are shown between
256 When two revision arguments are given, then changes are shown between
255 those revisions. If only one revision is specified then that revision is
257 those revisions. If only one revision is specified then that revision is
256 compared to the working directory, and, when no revisions are specified,
258 compared to the working directory, and, when no revisions are specified,
257 the working directory files are compared to its parent.
259 the working directory files are compared to its parent.
258
260
259 use "hg help -e extdiff" to show help for the extdiff extension
261 use "hg help -e extdiff" to show help for the extdiff extension
260
262
261 options:
263 options:
262
264
263 -p --program CMD comparison program to run
265 -p --program CMD comparison program to run
264 -o --option OPT [+] pass option to comparison program
266 -o --option OPT [+] pass option to comparison program
265 -r --rev REV [+] revision
267 -r --rev REV [+] revision
266 -c --change REV change made by revision
268 -c --change REV change made by revision
267 -I --include PATTERN [+] include names matching the given patterns
269 -I --include PATTERN [+] include names matching the given patterns
268 -X --exclude PATTERN [+] exclude names matching the given patterns
270 -X --exclude PATTERN [+] exclude names matching the given patterns
269
271
270 [+] marked option can be specified multiple times
272 [+] marked option can be specified multiple times
271
273
272 use "hg -v help extdiff" to show the global options
274 use "hg -v help extdiff" to show the global options
273
275
274 $ hg help --extension extdiff
276 $ hg help --extension extdiff
275 extdiff extension - command to allow external programs to compare revisions
277 extdiff extension - command to allow external programs to compare revisions
276
278
277 The extdiff Mercurial extension allows you to use external programs to compare
279 The extdiff Mercurial extension allows you to use external programs to compare
278 revisions, or revision with working directory. The external diff programs are
280 revisions, or revision with working directory. The external diff programs are
279 called with a configurable set of options and two non-option arguments: paths
281 called with a configurable set of options and two non-option arguments: paths
280 to directories containing snapshots of files to compare.
282 to directories containing snapshots of files to compare.
281
283
282 The extdiff extension also allows you to configure new diff commands, so you
284 The extdiff extension also allows you to configure new diff commands, so you
283 do not need to type "hg extdiff -p kdiff3" always.
285 do not need to type "hg extdiff -p kdiff3" always.
284
286
285 [extdiff]
287 [extdiff]
286 # add new command that runs GNU diff(1) in 'context diff' mode
288 # add new command that runs GNU diff(1) in 'context diff' mode
287 cdiff = gdiff -Nprc5
289 cdiff = gdiff -Nprc5
288 ## or the old way:
290 ## or the old way:
289 #cmd.cdiff = gdiff
291 #cmd.cdiff = gdiff
290 #opts.cdiff = -Nprc5
292 #opts.cdiff = -Nprc5
291
293
292 # add new command called vdiff, runs kdiff3
294 # add new command called vdiff, runs kdiff3
293 vdiff = kdiff3
295 vdiff = kdiff3
294
296
295 # add new command called meld, runs meld (no need to name twice)
297 # add new command called meld, runs meld (no need to name twice)
296 meld =
298 meld =
297
299
298 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
300 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
299 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
301 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
300 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
302 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
301 # your .vimrc
303 # your .vimrc
302 vimdiff = gvim -f "+next" \
304 vimdiff = gvim -f "+next" \
303 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
305 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
304
306
305 Tool arguments can include variables that are expanded at runtime:
307 Tool arguments can include variables that are expanded at runtime:
306
308
307 $parent1, $plabel1 - filename, descriptive label of first parent
309 $parent1, $plabel1 - filename, descriptive label of first parent
308 $child, $clabel - filename, descriptive label of child revision
310 $child, $clabel - filename, descriptive label of child revision
309 $parent2, $plabel2 - filename, descriptive label of second parent
311 $parent2, $plabel2 - filename, descriptive label of second parent
310 $root - repository root
312 $root - repository root
311 $parent is an alias for $parent1.
313 $parent is an alias for $parent1.
312
314
313 The extdiff extension will look in your [diff-tools] and [merge-tools]
315 The extdiff extension will look in your [diff-tools] and [merge-tools]
314 sections for diff tool arguments, when none are specified in [extdiff].
316 sections for diff tool arguments, when none are specified in [extdiff].
315
317
316 [extdiff]
318 [extdiff]
317 kdiff3 =
319 kdiff3 =
318
320
319 [diff-tools]
321 [diff-tools]
320 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
322 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
321
323
322 You can use -I/-X and list of file or directory names like normal "hg diff"
324 You can use -I/-X and list of file or directory names like normal "hg diff"
323 command. The extdiff extension makes snapshots of only needed files, so
325 command. The extdiff extension makes snapshots of only needed files, so
324 running the external diff program will actually be pretty fast (at least
326 running the external diff program will actually be pretty fast (at least
325 faster than having to compare the entire tree).
327 faster than having to compare the entire tree).
326
328
327 list of commands:
329 list of commands:
328
330
329 extdiff use external program to diff repository (or selected files)
331 extdiff use external program to diff repository (or selected files)
330
332
331 use "hg -v help extdiff" to show builtin aliases and global options
333 use "hg -v help extdiff" to show builtin aliases and global options
332
334
333 $ echo 'extdiff = !' >> $HGRCPATH
335 $ echo 'extdiff = !' >> $HGRCPATH
334
336
335 Test help topic with same name as extension
337 Test help topic with same name as extension
336
338
337 $ cat > multirevs.py <<EOF
339 $ cat > multirevs.py <<EOF
338 > from mercurial import commands
340 > from mercurial import commands
339 > """multirevs extension
341 > """multirevs extension
340 > Big multi-line module docstring."""
342 > Big multi-line module docstring."""
341 > def multirevs(ui, repo, arg, *args, **opts):
343 > def multirevs(ui, repo, arg, *args, **opts):
342 > """multirevs command"""
344 > """multirevs command"""
343 > pass
345 > pass
344 > cmdtable = {
346 > cmdtable = {
345 > "multirevs": (multirevs, [], 'ARG')
347 > "multirevs": (multirevs, [], 'ARG')
346 > }
348 > }
347 > commands.norepo += ' multirevs'
349 > commands.norepo += ' multirevs'
348 > EOF
350 > EOF
349 $ echo "multirevs = multirevs.py" >> $HGRCPATH
351 $ echo "multirevs = multirevs.py" >> $HGRCPATH
350
352
351 $ hg help multirevs
353 $ hg help multirevs
352 Specifying Multiple Revisions
354 Specifying Multiple Revisions
353
355
354 When Mercurial accepts more than one revision, they may be specified
356 When Mercurial accepts more than one revision, they may be specified
355 individually, or provided as a topologically continuous range, separated
357 individually, or provided as a topologically continuous range, separated
356 by the ":" character.
358 by the ":" character.
357
359
358 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
360 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
359 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
361 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
360 specified, it defaults to revision number 0. If END is not specified, it
362 specified, it defaults to revision number 0. If END is not specified, it
361 defaults to the tip. The range ":" thus means "all revisions".
363 defaults to the tip. The range ":" thus means "all revisions".
362
364
363 If BEGIN is greater than END, revisions are treated in reverse order.
365 If BEGIN is greater than END, revisions are treated in reverse order.
364
366
365 A range acts as a closed interval. This means that a range of 3:5 gives 3,
367 A range acts as a closed interval. This means that a range of 3:5 gives 3,
366 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
368 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
367
369
368 use "hg help -c multirevs" to see help for the multirevs command
370 use "hg help -c multirevs" to see help for the multirevs command
369
371
370 $ hg help -c multirevs
372 $ hg help -c multirevs
371 hg multirevs ARG
373 hg multirevs ARG
372
374
373 multirevs command
375 multirevs command
374
376
375 use "hg -v help multirevs" to show the global options
377 use "hg -v help multirevs" to show the global options
376
378
377 $ hg multirevs
379 $ hg multirevs
378 hg multirevs: invalid arguments
380 hg multirevs: invalid arguments
379 hg multirevs ARG
381 hg multirevs ARG
380
382
381 multirevs command
383 multirevs command
382
384
383 use "hg help multirevs" to show the full help text
385 use "hg help multirevs" to show the full help text
384 [255]
386 [255]
385
387
386 $ echo "multirevs = !" >> $HGRCPATH
388 $ echo "multirevs = !" >> $HGRCPATH
387
389
388 Issue811: Problem loading extensions twice (by site and by user)
390 Issue811: Problem loading extensions twice (by site and by user)
389
391
390 $ debugpath=`pwd`/debugissue811.py
392 $ debugpath=`pwd`/debugissue811.py
391 $ cat > debugissue811.py <<EOF
393 $ cat > debugissue811.py <<EOF
392 > '''show all loaded extensions
394 > '''show all loaded extensions
393 > '''
395 > '''
394 > from mercurial import extensions, commands
396 > from mercurial import extensions, commands
395 >
397 >
396 > def debugextensions(ui):
398 > def debugextensions(ui):
397 > "yet another debug command"
399 > "yet another debug command"
398 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
400 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
399 >
401 >
400 > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
402 > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
401 > commands.norepo += " debugextensions"
403 > commands.norepo += " debugextensions"
402 > EOF
404 > EOF
403 $ echo "debugissue811 = $debugpath" >> $HGRCPATH
405 $ echo "debugissue811 = $debugpath" >> $HGRCPATH
404 $ echo "mq=" >> $HGRCPATH
406 $ echo "mq=" >> $HGRCPATH
405 $ echo "hgext.mq=" >> $HGRCPATH
407 $ echo "hgext.mq=" >> $HGRCPATH
406 $ echo "hgext/mq=" >> $HGRCPATH
408 $ echo "hgext/mq=" >> $HGRCPATH
407
409
408 Show extensions:
410 Show extensions:
409
411
410 $ hg debugextensions
412 $ hg debugextensions
411 debugissue811
413 debugissue811
412 mq
414 mq
413
415
414 Disabled extension commands:
416 Disabled extension commands:
415
417
416 $ HGRCPATH=
418 $ HGRCPATH=
417 $ export HGRCPATH
419 $ export HGRCPATH
418 $ hg help email
420 $ hg help email
419 'email' is provided by the following extension:
421 'email' is provided by the following extension:
420
422
421 patchbomb command to send changesets as (a series of) patch emails
423 patchbomb command to send changesets as (a series of) patch emails
422
424
423 use "hg help extensions" for information on enabling extensions
425 use "hg help extensions" for information on enabling extensions
424 $ hg qdel
426 $ hg qdel
425 hg: unknown command 'qdel'
427 hg: unknown command 'qdel'
426 'qdelete' is provided by the following extension:
428 'qdelete' is provided by the following extension:
427
429
428 mq manage a stack of patches
430 mq manage a stack of patches
429
431
430 use "hg help extensions" for information on enabling extensions
432 use "hg help extensions" for information on enabling extensions
431 [255]
433 [255]
432 $ hg churn
434 $ hg churn
433 hg: unknown command 'churn'
435 hg: unknown command 'churn'
434 'churn' is provided by the following extension:
436 'churn' is provided by the following extension:
435
437
436 churn command to display statistics about repository history
438 churn command to display statistics about repository history
437
439
438 use "hg help extensions" for information on enabling extensions
440 use "hg help extensions" for information on enabling extensions
439 [255]
441 [255]
440
442
441 Disabled extensions:
443 Disabled extensions:
442
444
443 $ hg help churn
445 $ hg help churn
444 churn extension - command to display statistics about repository history
446 churn extension - command to display statistics about repository history
445
447
446 use "hg help extensions" for information on enabling extensions
448 use "hg help extensions" for information on enabling extensions
447 $ hg help patchbomb
449 $ hg help patchbomb
448 patchbomb extension - command to send changesets as (a series of) patch emails
450 patchbomb extension - command to send changesets as (a series of) patch emails
449
451
450 use "hg help extensions" for information on enabling extensions
452 use "hg help extensions" for information on enabling extensions
451
453
452 Broken disabled extension and command:
454 Broken disabled extension and command:
453
455
454 $ mkdir hgext
456 $ mkdir hgext
455 $ echo > hgext/__init__.py
457 $ echo > hgext/__init__.py
456 $ cat > hgext/broken.py <<EOF
458 $ cat > hgext/broken.py <<EOF
457 > "broken extension'
459 > "broken extension'
458 > EOF
460 > EOF
459 $ cat > path.py <<EOF
461 $ cat > path.py <<EOF
460 > import os, sys
462 > import os, sys
461 > sys.path.insert(0, os.environ['HGEXTPATH'])
463 > sys.path.insert(0, os.environ['HGEXTPATH'])
462 > EOF
464 > EOF
463 $ HGEXTPATH=`pwd`
465 $ HGEXTPATH=`pwd`
464 $ export HGEXTPATH
466 $ export HGEXTPATH
465
467
466 $ hg --config extensions.path=./path.py help broken
468 $ hg --config extensions.path=./path.py help broken
467 broken extension - (no help text available)
469 broken extension - (no help text available)
468
470
469 use "hg help extensions" for information on enabling extensions
471 use "hg help extensions" for information on enabling extensions
470
472
471 $ cat > hgext/forest.py <<EOF
473 $ cat > hgext/forest.py <<EOF
472 > cmdtable = None
474 > cmdtable = None
473 > EOF
475 > EOF
474 $ hg --config extensions.path=./path.py help foo > /dev/null
476 $ hg --config extensions.path=./path.py help foo > /dev/null
475 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
477 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
476 hg: unknown command 'foo'
478 hg: unknown command 'foo'
477 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
479 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
478 [255]
480 [255]
479
481
480 $ cat > throw.py <<EOF
482 $ cat > throw.py <<EOF
481 > from mercurial import cmdutil, commands
483 > from mercurial import cmdutil, commands
482 > cmdtable = {}
484 > cmdtable = {}
483 > command = cmdutil.command(cmdtable)
485 > command = cmdutil.command(cmdtable)
484 > class Bogon(Exception): pass
486 > class Bogon(Exception): pass
485 >
487 >
486 > @command('throw', [], 'hg throw')
488 > @command('throw', [], 'hg throw')
487 > def throw(ui, **opts):
489 > def throw(ui, **opts):
488 > """throws an exception"""
490 > """throws an exception"""
489 > raise Bogon()
491 > raise Bogon()
490 > commands.norepo += " throw"
492 > commands.norepo += " throw"
491 > EOF
493 > EOF
492 No declared supported version, extension complains:
494 No declared supported version, extension complains:
493 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
495 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
494 ** Unknown exception encountered with possibly-broken third-party extension throw
496 ** Unknown exception encountered with possibly-broken third-party extension throw
495 ** which supports versions unknown of Mercurial.
497 ** which supports versions unknown of Mercurial.
496 ** Please disable throw and try your action again.
498 ** Please disable throw and try your action again.
497 ** If that fixes the bug please report it to the extension author.
499 ** If that fixes the bug please report it to the extension author.
498 ** Python * (glob)
500 ** Python * (glob)
499 ** Mercurial Distributed SCM * (glob)
501 ** Mercurial Distributed SCM * (glob)
500 ** Extensions loaded: throw
502 ** Extensions loaded: throw
501 empty declaration of supported version, extension complains:
503 empty declaration of supported version, extension complains:
502 $ echo "testedwith = ''" >> throw.py
504 $ echo "testedwith = ''" >> throw.py
503 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
505 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
504 ** Unknown exception encountered with possibly-broken third-party extension throw
506 ** Unknown exception encountered with possibly-broken third-party extension throw
505 ** which supports versions unknown of Mercurial.
507 ** which supports versions unknown of Mercurial.
506 ** Please disable throw and try your action again.
508 ** Please disable throw and try your action again.
507 ** If that fixes the bug please report it to the extension author.
509 ** If that fixes the bug please report it to the extension author.
508 ** Python * (glob)
510 ** Python * (glob)
509 ** Mercurial Distributed SCM (*) (glob)
511 ** Mercurial Distributed SCM (*) (glob)
510 ** Extensions loaded: throw
512 ** Extensions loaded: throw
511 If the extension specifies a buglink, show that:
513 If the extension specifies a buglink, show that:
512 $ echo 'buglink = "http://example.com/bts"' >> throw.py
514 $ echo 'buglink = "http://example.com/bts"' >> throw.py
513 $ rm -f throw.pyc throw.pyo
515 $ rm -f throw.pyc throw.pyo
514 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
516 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
515 ** Unknown exception encountered with possibly-broken third-party extension throw
517 ** Unknown exception encountered with possibly-broken third-party extension throw
516 ** which supports versions unknown of Mercurial.
518 ** which supports versions unknown of Mercurial.
517 ** Please disable throw and try your action again.
519 ** Please disable throw and try your action again.
518 ** If that fixes the bug please report it to http://example.com/bts
520 ** If that fixes the bug please report it to http://example.com/bts
519 ** Python * (glob)
521 ** Python * (glob)
520 ** Mercurial Distributed SCM (*) (glob)
522 ** Mercurial Distributed SCM (*) (glob)
521 ** Extensions loaded: throw
523 ** Extensions loaded: throw
522 If the extensions declare outdated versions, accuse the older extension first:
524 If the extensions declare outdated versions, accuse the older extension first:
523 $ echo "from mercurial import util" >> older.py
525 $ echo "from mercurial import util" >> older.py
524 $ echo "util.version = lambda:'2.2'" >> older.py
526 $ echo "util.version = lambda:'2.2'" >> older.py
525 $ echo "testedwith = '1.9.3'" >> older.py
527 $ echo "testedwith = '1.9.3'" >> older.py
526 $ echo "testedwith = '2.1.1'" >> throw.py
528 $ echo "testedwith = '2.1.1'" >> throw.py
527 $ rm -f throw.pyc throw.pyo
529 $ rm -f throw.pyc throw.pyo
528 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
530 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
529 > throw 2>&1 | egrep '^\*\*'
531 > throw 2>&1 | egrep '^\*\*'
530 ** Unknown exception encountered with possibly-broken third-party extension older
532 ** Unknown exception encountered with possibly-broken third-party extension older
531 ** which supports versions 1.9.3 of Mercurial.
533 ** which supports versions 1.9.3 of Mercurial.
532 ** Please disable older and try your action again.
534 ** Please disable older and try your action again.
533 ** If that fixes the bug please report it to the extension author.
535 ** If that fixes the bug please report it to the extension author.
534 ** Python * (glob)
536 ** Python * (glob)
535 ** Mercurial Distributed SCM (version 2.2)
537 ** Mercurial Distributed SCM (version 2.2)
536 ** Extensions loaded: throw, older
538 ** Extensions loaded: throw, older
537 One extension only tested with older, one only with newer versions:
539 One extension only tested with older, one only with newer versions:
538 $ echo "util.version = lambda:'2.1.0'" >> older.py
540 $ echo "util.version = lambda:'2.1.0'" >> older.py
539 $ rm -f older.pyc older.pyo
541 $ rm -f older.pyc older.pyo
540 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
542 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
541 > throw 2>&1 | egrep '^\*\*'
543 > throw 2>&1 | egrep '^\*\*'
542 ** Unknown exception encountered with possibly-broken third-party extension older
544 ** Unknown exception encountered with possibly-broken third-party extension older
543 ** which supports versions 1.9.3 of Mercurial.
545 ** which supports versions 1.9.3 of Mercurial.
544 ** Please disable older and try your action again.
546 ** Please disable older and try your action again.
545 ** If that fixes the bug please report it to the extension author.
547 ** If that fixes the bug please report it to the extension author.
546 ** Python * (glob)
548 ** Python * (glob)
547 ** Mercurial Distributed SCM (version 2.1.0)
549 ** Mercurial Distributed SCM (version 2.1.0)
548 ** Extensions loaded: throw, older
550 ** Extensions loaded: throw, older
549 Older extension is tested with current version, the other only with newer:
551 Older extension is tested with current version, the other only with newer:
550 $ echo "util.version = lambda:'1.9.3'" >> older.py
552 $ echo "util.version = lambda:'1.9.3'" >> older.py
551 $ rm -f older.pyc older.pyo
553 $ rm -f older.pyc older.pyo
552 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
554 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
553 > throw 2>&1 | egrep '^\*\*'
555 > throw 2>&1 | egrep '^\*\*'
554 ** Unknown exception encountered with possibly-broken third-party extension throw
556 ** Unknown exception encountered with possibly-broken third-party extension throw
555 ** which supports versions 2.1.1 of Mercurial.
557 ** which supports versions 2.1.1 of Mercurial.
556 ** Please disable throw and try your action again.
558 ** Please disable throw and try your action again.
557 ** If that fixes the bug please report it to http://example.com/bts
559 ** If that fixes the bug please report it to http://example.com/bts
558 ** Python * (glob)
560 ** Python * (glob)
559 ** Mercurial Distributed SCM (version 1.9.3)
561 ** Mercurial Distributed SCM (version 1.9.3)
560 ** Extensions loaded: throw, older
562 ** Extensions loaded: throw, older
561
563
562 Declare the version as supporting this hg version, show regular bts link:
564 Declare the version as supporting this hg version, show regular bts link:
563 $ hgver=`python -c 'from mercurial import util; print util.version().split("+")[0]'`
565 $ hgver=`python -c 'from mercurial import util; print util.version().split("+")[0]'`
564 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
566 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
565 $ rm -f throw.pyc throw.pyo
567 $ rm -f throw.pyc throw.pyo
566 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
568 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
567 ** unknown exception encountered, please report by visiting
569 ** unknown exception encountered, please report by visiting
568 ** http://mercurial.selenic.com/wiki/BugTracker
570 ** http://mercurial.selenic.com/wiki/BugTracker
569 ** Python * (glob)
571 ** Python * (glob)
570 ** Mercurial Distributed SCM (*) (glob)
572 ** Mercurial Distributed SCM (*) (glob)
571 ** Extensions loaded: throw
573 ** Extensions loaded: throw
@@ -1,875 +1,877 b''
1 Short help:
1 Short help:
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge working directory with another revision
17 merge merge working directory with another revision
18 pull pull changes from the specified source
18 pull pull changes from the specified source
19 push push changes to the specified destination
19 push push changes to the specified destination
20 remove remove the specified files on the next commit
20 remove remove the specified files on the next commit
21 serve start stand-alone webserver
21 serve start stand-alone webserver
22 status show changed files in the working directory
22 status show changed files in the working directory
23 summary summarize working directory state
23 summary summarize working directory state
24 update update working directory (or switch revisions)
24 update update working directory (or switch revisions)
25
25
26 use "hg help" for the full list of commands or "hg -v" for details
26 use "hg help" for the full list of commands or "hg -v" for details
27
27
28 $ hg -q
28 $ hg -q
29 add add the specified files on the next commit
29 add add the specified files on the next commit
30 annotate show changeset information by line for each file
30 annotate show changeset information by line for each file
31 clone make a copy of an existing repository
31 clone make a copy of an existing repository
32 commit commit the specified files or all outstanding changes
32 commit commit the specified files or all outstanding changes
33 diff diff repository (or selected files)
33 diff diff repository (or selected files)
34 export dump the header and diffs for one or more changesets
34 export dump the header and diffs for one or more changesets
35 forget forget the specified files on the next commit
35 forget forget the specified files on the next commit
36 init create a new repository in the given directory
36 init create a new repository in the given directory
37 log show revision history of entire repository or files
37 log show revision history of entire repository or files
38 merge merge working directory with another revision
38 merge merge working directory with another revision
39 pull pull changes from the specified source
39 pull pull changes from the specified source
40 push push changes to the specified destination
40 push push changes to the specified destination
41 remove remove the specified files on the next commit
41 remove remove the specified files on the next commit
42 serve start stand-alone webserver
42 serve start stand-alone webserver
43 status show changed files in the working directory
43 status show changed files in the working directory
44 summary summarize working directory state
44 summary summarize working directory state
45 update update working directory (or switch revisions)
45 update update working directory (or switch revisions)
46
46
47 $ hg help
47 $ hg help
48 Mercurial Distributed SCM
48 Mercurial Distributed SCM
49
49
50 list of commands:
50 list of commands:
51
51
52 add add the specified files on the next commit
52 add add the specified files on the next commit
53 addremove add all new files, delete all missing files
53 addremove add all new files, delete all missing files
54 annotate show changeset information by line for each file
54 annotate show changeset information by line for each file
55 archive create an unversioned archive of a repository revision
55 archive create an unversioned archive of a repository revision
56 backout reverse effect of earlier changeset
56 backout reverse effect of earlier changeset
57 bisect subdivision search of changesets
57 bisect subdivision search of changesets
58 bookmarks track a line of development with movable markers
58 bookmarks track a line of development with movable markers
59 branch set or show the current branch name
59 branch set or show the current branch name
60 branches list repository named branches
60 branches list repository named branches
61 bundle create a changegroup file
61 bundle create a changegroup file
62 cat output the current or given revision of files
62 cat output the current or given revision of files
63 clone make a copy of an existing repository
63 clone make a copy of an existing repository
64 commit commit the specified files or all outstanding changes
64 commit commit the specified files or all outstanding changes
65 copy mark files as copied for the next commit
65 copy mark files as copied for the next commit
66 diff diff repository (or selected files)
66 diff diff repository (or selected files)
67 export dump the header and diffs for one or more changesets
67 export dump the header and diffs for one or more changesets
68 forget forget the specified files on the next commit
68 forget forget the specified files on the next commit
69 graft copy changes from other branches onto the current branch
69 graft copy changes from other branches onto the current branch
70 grep search for a pattern in specified files and revisions
70 grep search for a pattern in specified files and revisions
71 heads show current repository heads or show branch heads
71 heads show current repository heads or show branch heads
72 help show help for a given topic or a help overview
72 help show help for a given topic or a help overview
73 identify identify the working copy or specified revision
73 identify identify the working copy or specified revision
74 import import an ordered set of patches
74 import import an ordered set of patches
75 incoming show new changesets found in source
75 incoming show new changesets found in source
76 init create a new repository in the given directory
76 init create a new repository in the given directory
77 locate locate files matching specific patterns
77 locate locate files matching specific patterns
78 log show revision history of entire repository or files
78 log show revision history of entire repository or files
79 manifest output the current or given revision of the project manifest
79 manifest output the current or given revision of the project manifest
80 merge merge working directory with another revision
80 merge merge working directory with another revision
81 outgoing show changesets not found in the destination
81 outgoing show changesets not found in the destination
82 parents show the parents of the working directory or revision
82 parents show the parents of the working directory or revision
83 paths show aliases for remote repositories
83 paths show aliases for remote repositories
84 phase set or show the current phase name
84 phase set or show the current phase name
85 pull pull changes from the specified source
85 pull pull changes from the specified source
86 push push changes to the specified destination
86 push push changes to the specified destination
87 recover roll back an interrupted transaction
87 recover roll back an interrupted transaction
88 remove remove the specified files on the next commit
88 remove remove the specified files on the next commit
89 rename rename files; equivalent of copy + remove
89 rename rename files; equivalent of copy + remove
90 resolve redo merges or set/view the merge status of files
90 resolve redo merges or set/view the merge status of files
91 revert restore files to their checkout state
91 revert restore files to their checkout state
92 rollback roll back the last transaction (dangerous)
92 rollback roll back the last transaction (dangerous)
93 root print the root (top) of the current working directory
93 root print the root (top) of the current working directory
94 serve start stand-alone webserver
94 serve start stand-alone webserver
95 showconfig show combined config settings from all hgrc files
95 showconfig show combined config settings from all hgrc files
96 status show changed files in the working directory
96 status show changed files in the working directory
97 summary summarize working directory state
97 summary summarize working directory state
98 tag add one or more tags for the current or given revision
98 tag add one or more tags for the current or given revision
99 tags list repository tags
99 tags list repository tags
100 tip show the tip revision
100 tip show the tip revision
101 unbundle apply one or more changegroup files
101 unbundle apply one or more changegroup files
102 update update working directory (or switch revisions)
102 update update working directory (or switch revisions)
103 verify verify the integrity of the repository
103 verify verify the integrity of the repository
104 version output version and copyright information
104 version output version and copyright information
105
105
106 additional help topics:
106 additional help topics:
107
107
108 config Configuration Files
108 config Configuration Files
109 dates Date Formats
109 dates Date Formats
110 diffs Diff Formats
110 diffs Diff Formats
111 environment Environment Variables
111 environment Environment Variables
112 extensions Using Additional Features
112 extensions Using Additional Features
113 filesets Specifying File Sets
113 filesets Specifying File Sets
114 glossary Glossary
114 glossary Glossary
115 hgignore Syntax for Mercurial Ignore Files
115 hgignore Syntax for Mercurial Ignore Files
116 hgweb Configuring hgweb
116 hgweb Configuring hgweb
117 merge-tools Merge Tools
117 merge-tools Merge Tools
118 multirevs Specifying Multiple Revisions
118 multirevs Specifying Multiple Revisions
119 patterns File Name Patterns
119 patterns File Name Patterns
120 phases Working with Phases
120 phases Working with Phases
121 revisions Specifying Single Revisions
121 revisions Specifying Single Revisions
122 revsets Specifying Revision Sets
122 revsets Specifying Revision Sets
123 subrepos Subrepositories
123 subrepos Subrepositories
124 templating Template Usage
124 templating Template Usage
125 urls URL Paths
125 urls URL Paths
126
126
127 use "hg -v help" to show builtin aliases and global options
127 use "hg -v help" to show builtin aliases and global options
128
128
129 $ hg -q help
129 $ hg -q help
130 add add the specified files on the next commit
130 add add the specified files on the next commit
131 addremove add all new files, delete all missing files
131 addremove add all new files, delete all missing files
132 annotate show changeset information by line for each file
132 annotate show changeset information by line for each file
133 archive create an unversioned archive of a repository revision
133 archive create an unversioned archive of a repository revision
134 backout reverse effect of earlier changeset
134 backout reverse effect of earlier changeset
135 bisect subdivision search of changesets
135 bisect subdivision search of changesets
136 bookmarks track a line of development with movable markers
136 bookmarks track a line of development with movable markers
137 branch set or show the current branch name
137 branch set or show the current branch name
138 branches list repository named branches
138 branches list repository named branches
139 bundle create a changegroup file
139 bundle create a changegroup file
140 cat output the current or given revision of files
140 cat output the current or given revision of files
141 clone make a copy of an existing repository
141 clone make a copy of an existing repository
142 commit commit the specified files or all outstanding changes
142 commit commit the specified files or all outstanding changes
143 copy mark files as copied for the next commit
143 copy mark files as copied for the next commit
144 diff diff repository (or selected files)
144 diff diff repository (or selected files)
145 export dump the header and diffs for one or more changesets
145 export dump the header and diffs for one or more changesets
146 forget forget the specified files on the next commit
146 forget forget the specified files on the next commit
147 graft copy changes from other branches onto the current branch
147 graft copy changes from other branches onto the current branch
148 grep search for a pattern in specified files and revisions
148 grep search for a pattern in specified files and revisions
149 heads show current repository heads or show branch heads
149 heads show current repository heads or show branch heads
150 help show help for a given topic or a help overview
150 help show help for a given topic or a help overview
151 identify identify the working copy or specified revision
151 identify identify the working copy or specified revision
152 import import an ordered set of patches
152 import import an ordered set of patches
153 incoming show new changesets found in source
153 incoming show new changesets found in source
154 init create a new repository in the given directory
154 init create a new repository in the given directory
155 locate locate files matching specific patterns
155 locate locate files matching specific patterns
156 log show revision history of entire repository or files
156 log show revision history of entire repository or files
157 manifest output the current or given revision of the project manifest
157 manifest output the current or given revision of the project manifest
158 merge merge working directory with another revision
158 merge merge working directory with another revision
159 outgoing show changesets not found in the destination
159 outgoing show changesets not found in the destination
160 parents show the parents of the working directory or revision
160 parents show the parents of the working directory or revision
161 paths show aliases for remote repositories
161 paths show aliases for remote repositories
162 phase set or show the current phase name
162 phase set or show the current phase name
163 pull pull changes from the specified source
163 pull pull changes from the specified source
164 push push changes to the specified destination
164 push push changes to the specified destination
165 recover roll back an interrupted transaction
165 recover roll back an interrupted transaction
166 remove remove the specified files on the next commit
166 remove remove the specified files on the next commit
167 rename rename files; equivalent of copy + remove
167 rename rename files; equivalent of copy + remove
168 resolve redo merges or set/view the merge status of files
168 resolve redo merges or set/view the merge status of files
169 revert restore files to their checkout state
169 revert restore files to their checkout state
170 rollback roll back the last transaction (dangerous)
170 rollback roll back the last transaction (dangerous)
171 root print the root (top) of the current working directory
171 root print the root (top) of the current working directory
172 serve start stand-alone webserver
172 serve start stand-alone webserver
173 showconfig show combined config settings from all hgrc files
173 showconfig show combined config settings from all hgrc files
174 status show changed files in the working directory
174 status show changed files in the working directory
175 summary summarize working directory state
175 summary summarize working directory state
176 tag add one or more tags for the current or given revision
176 tag add one or more tags for the current or given revision
177 tags list repository tags
177 tags list repository tags
178 tip show the tip revision
178 tip show the tip revision
179 unbundle apply one or more changegroup files
179 unbundle apply one or more changegroup files
180 update update working directory (or switch revisions)
180 update update working directory (or switch revisions)
181 verify verify the integrity of the repository
181 verify verify the integrity of the repository
182 version output version and copyright information
182 version output version and copyright information
183
183
184 additional help topics:
184 additional help topics:
185
185
186 config Configuration Files
186 config Configuration Files
187 dates Date Formats
187 dates Date Formats
188 diffs Diff Formats
188 diffs Diff Formats
189 environment Environment Variables
189 environment Environment Variables
190 extensions Using Additional Features
190 extensions Using Additional Features
191 filesets Specifying File Sets
191 filesets Specifying File Sets
192 glossary Glossary
192 glossary Glossary
193 hgignore Syntax for Mercurial Ignore Files
193 hgignore Syntax for Mercurial Ignore Files
194 hgweb Configuring hgweb
194 hgweb Configuring hgweb
195 merge-tools Merge Tools
195 merge-tools Merge Tools
196 multirevs Specifying Multiple Revisions
196 multirevs Specifying Multiple Revisions
197 patterns File Name Patterns
197 patterns File Name Patterns
198 phases Working with Phases
198 phases Working with Phases
199 revisions Specifying Single Revisions
199 revisions Specifying Single Revisions
200 revsets Specifying Revision Sets
200 revsets Specifying Revision Sets
201 subrepos Subrepositories
201 subrepos Subrepositories
202 templating Template Usage
202 templating Template Usage
203 urls URL Paths
203 urls URL Paths
204
204
205 Test short command list with verbose option
205 Test short command list with verbose option
206
206
207 $ hg -v help shortlist
207 $ hg -v help shortlist
208 Mercurial Distributed SCM
208 Mercurial Distributed SCM
209
209
210 basic commands:
210 basic commands:
211
211
212 add add the specified files on the next commit
212 add add the specified files on the next commit
213 annotate, blame
213 annotate, blame
214 show changeset information by line for each file
214 show changeset information by line for each file
215 clone make a copy of an existing repository
215 clone make a copy of an existing repository
216 commit, ci commit the specified files or all outstanding changes
216 commit, ci commit the specified files or all outstanding changes
217 diff diff repository (or selected files)
217 diff diff repository (or selected files)
218 export dump the header and diffs for one or more changesets
218 export dump the header and diffs for one or more changesets
219 forget forget the specified files on the next commit
219 forget forget the specified files on the next commit
220 init create a new repository in the given directory
220 init create a new repository in the given directory
221 log, history show revision history of entire repository or files
221 log, history show revision history of entire repository or files
222 merge merge working directory with another revision
222 merge merge working directory with another revision
223 pull pull changes from the specified source
223 pull pull changes from the specified source
224 push push changes to the specified destination
224 push push changes to the specified destination
225 remove, rm remove the specified files on the next commit
225 remove, rm remove the specified files on the next commit
226 serve start stand-alone webserver
226 serve start stand-alone webserver
227 status, st show changed files in the working directory
227 status, st show changed files in the working directory
228 summary, sum summarize working directory state
228 summary, sum summarize working directory state
229 update, up, checkout, co
229 update, up, checkout, co
230 update working directory (or switch revisions)
230 update working directory (or switch revisions)
231
231
232 global options:
232 global options:
233
233
234 -R --repository REPO repository root directory or name of overlay bundle
234 -R --repository REPO repository root directory or name of overlay bundle
235 file
235 file
236 --cwd DIR change working directory
236 --cwd DIR change working directory
237 -y --noninteractive do not prompt, automatically pick the first choice for
237 -y --noninteractive do not prompt, automatically pick the first choice for
238 all prompts
238 all prompts
239 -q --quiet suppress output
239 -q --quiet suppress output
240 -v --verbose enable additional output
240 -v --verbose enable additional output
241 --config CONFIG [+] set/override config option (use 'section.name=value')
241 --config CONFIG [+] set/override config option (use 'section.name=value')
242 --debug enable debugging output
242 --debug enable debugging output
243 --debugger start debugger
243 --debugger start debugger
244 --encoding ENCODE set the charset encoding (default: ascii)
244 --encoding ENCODE set the charset encoding (default: ascii)
245 --encodingmode MODE set the charset encoding mode (default: strict)
245 --encodingmode MODE set the charset encoding mode (default: strict)
246 --traceback always print a traceback on exception
246 --traceback always print a traceback on exception
247 --time time how long the command takes
247 --time time how long the command takes
248 --profile print command execution profile
248 --profile print command execution profile
249 --version output version information and exit
249 --version output version information and exit
250 -h --help display help and exit
250 -h --help display help and exit
251 --hidden consider hidden changesets
251
252
252 [+] marked option can be specified multiple times
253 [+] marked option can be specified multiple times
253
254
254 use "hg help" for the full list of commands
255 use "hg help" for the full list of commands
255
256
256 $ hg add -h
257 $ hg add -h
257 hg add [OPTION]... [FILE]...
258 hg add [OPTION]... [FILE]...
258
259
259 add the specified files on the next commit
260 add the specified files on the next commit
260
261
261 Schedule files to be version controlled and added to the repository.
262 Schedule files to be version controlled and added to the repository.
262
263
263 The files will be added to the repository at the next commit. To undo an
264 The files will be added to the repository at the next commit. To undo an
264 add before that, see "hg forget".
265 add before that, see "hg forget".
265
266
266 If no names are given, add all files to the repository.
267 If no names are given, add all files to the repository.
267
268
268 Returns 0 if all files are successfully added.
269 Returns 0 if all files are successfully added.
269
270
270 options:
271 options:
271
272
272 -I --include PATTERN [+] include names matching the given patterns
273 -I --include PATTERN [+] include names matching the given patterns
273 -X --exclude PATTERN [+] exclude names matching the given patterns
274 -X --exclude PATTERN [+] exclude names matching the given patterns
274 -S --subrepos recurse into subrepositories
275 -S --subrepos recurse into subrepositories
275 -n --dry-run do not perform actions, just print output
276 -n --dry-run do not perform actions, just print output
276
277
277 [+] marked option can be specified multiple times
278 [+] marked option can be specified multiple times
278
279
279 use "hg -v help add" to show more complete help and the global options
280 use "hg -v help add" to show more complete help and the global options
280
281
281 Verbose help for add
282 Verbose help for add
282
283
283 $ hg add -hv
284 $ hg add -hv
284 hg add [OPTION]... [FILE]...
285 hg add [OPTION]... [FILE]...
285
286
286 add the specified files on the next commit
287 add the specified files on the next commit
287
288
288 Schedule files to be version controlled and added to the repository.
289 Schedule files to be version controlled and added to the repository.
289
290
290 The files will be added to the repository at the next commit. To undo an
291 The files will be added to the repository at the next commit. To undo an
291 add before that, see "hg forget".
292 add before that, see "hg forget".
292
293
293 If no names are given, add all files to the repository.
294 If no names are given, add all files to the repository.
294
295
295 An example showing how new (unknown) files are added automatically by "hg
296 An example showing how new (unknown) files are added automatically by "hg
296 add":
297 add":
297
298
298 $ ls
299 $ ls
299 foo.c
300 foo.c
300 $ hg status
301 $ hg status
301 ? foo.c
302 ? foo.c
302 $ hg add
303 $ hg add
303 adding foo.c
304 adding foo.c
304 $ hg status
305 $ hg status
305 A foo.c
306 A foo.c
306
307
307 Returns 0 if all files are successfully added.
308 Returns 0 if all files are successfully added.
308
309
309 options:
310 options:
310
311
311 -I --include PATTERN [+] include names matching the given patterns
312 -I --include PATTERN [+] include names matching the given patterns
312 -X --exclude PATTERN [+] exclude names matching the given patterns
313 -X --exclude PATTERN [+] exclude names matching the given patterns
313 -S --subrepos recurse into subrepositories
314 -S --subrepos recurse into subrepositories
314 -n --dry-run do not perform actions, just print output
315 -n --dry-run do not perform actions, just print output
315
316
316 [+] marked option can be specified multiple times
317 [+] marked option can be specified multiple times
317
318
318 global options:
319 global options:
319
320
320 -R --repository REPO repository root directory or name of overlay bundle
321 -R --repository REPO repository root directory or name of overlay bundle
321 file
322 file
322 --cwd DIR change working directory
323 --cwd DIR change working directory
323 -y --noninteractive do not prompt, automatically pick the first choice for
324 -y --noninteractive do not prompt, automatically pick the first choice for
324 all prompts
325 all prompts
325 -q --quiet suppress output
326 -q --quiet suppress output
326 -v --verbose enable additional output
327 -v --verbose enable additional output
327 --config CONFIG [+] set/override config option (use 'section.name=value')
328 --config CONFIG [+] set/override config option (use 'section.name=value')
328 --debug enable debugging output
329 --debug enable debugging output
329 --debugger start debugger
330 --debugger start debugger
330 --encoding ENCODE set the charset encoding (default: ascii)
331 --encoding ENCODE set the charset encoding (default: ascii)
331 --encodingmode MODE set the charset encoding mode (default: strict)
332 --encodingmode MODE set the charset encoding mode (default: strict)
332 --traceback always print a traceback on exception
333 --traceback always print a traceback on exception
333 --time time how long the command takes
334 --time time how long the command takes
334 --profile print command execution profile
335 --profile print command execution profile
335 --version output version information and exit
336 --version output version information and exit
336 -h --help display help and exit
337 -h --help display help and exit
338 --hidden consider hidden changesets
337
339
338 [+] marked option can be specified multiple times
340 [+] marked option can be specified multiple times
339
341
340 Test help option with version option
342 Test help option with version option
341
343
342 $ hg add -h --version
344 $ hg add -h --version
343 Mercurial Distributed SCM (version *) (glob)
345 Mercurial Distributed SCM (version *) (glob)
344 (see http://mercurial.selenic.com for more information)
346 (see http://mercurial.selenic.com for more information)
345
347
346 Copyright (C) 2005-2012 Matt Mackall and others
348 Copyright (C) 2005-2012 Matt Mackall and others
347 This is free software; see the source for copying conditions. There is NO
349 This is free software; see the source for copying conditions. There is NO
348 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
350 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
349
351
350 $ hg add --skjdfks
352 $ hg add --skjdfks
351 hg add: option --skjdfks not recognized
353 hg add: option --skjdfks not recognized
352 hg add [OPTION]... [FILE]...
354 hg add [OPTION]... [FILE]...
353
355
354 add the specified files on the next commit
356 add the specified files on the next commit
355
357
356 options:
358 options:
357
359
358 -I --include PATTERN [+] include names matching the given patterns
360 -I --include PATTERN [+] include names matching the given patterns
359 -X --exclude PATTERN [+] exclude names matching the given patterns
361 -X --exclude PATTERN [+] exclude names matching the given patterns
360 -S --subrepos recurse into subrepositories
362 -S --subrepos recurse into subrepositories
361 -n --dry-run do not perform actions, just print output
363 -n --dry-run do not perform actions, just print output
362
364
363 [+] marked option can be specified multiple times
365 [+] marked option can be specified multiple times
364
366
365 use "hg help add" to show the full help text
367 use "hg help add" to show the full help text
366 [255]
368 [255]
367
369
368 Test ambiguous command help
370 Test ambiguous command help
369
371
370 $ hg help ad
372 $ hg help ad
371 list of commands:
373 list of commands:
372
374
373 add add the specified files on the next commit
375 add add the specified files on the next commit
374 addremove add all new files, delete all missing files
376 addremove add all new files, delete all missing files
375
377
376 use "hg -v help ad" to show builtin aliases and global options
378 use "hg -v help ad" to show builtin aliases and global options
377
379
378 Test command without options
380 Test command without options
379
381
380 $ hg help verify
382 $ hg help verify
381 hg verify
383 hg verify
382
384
383 verify the integrity of the repository
385 verify the integrity of the repository
384
386
385 Verify the integrity of the current repository.
387 Verify the integrity of the current repository.
386
388
387 This will perform an extensive check of the repository's integrity,
389 This will perform an extensive check of the repository's integrity,
388 validating the hashes and checksums of each entry in the changelog,
390 validating the hashes and checksums of each entry in the changelog,
389 manifest, and tracked files, as well as the integrity of their crosslinks
391 manifest, and tracked files, as well as the integrity of their crosslinks
390 and indices.
392 and indices.
391
393
392 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
394 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
393 information about recovery from corruption of the repository.
395 information about recovery from corruption of the repository.
394
396
395 Returns 0 on success, 1 if errors are encountered.
397 Returns 0 on success, 1 if errors are encountered.
396
398
397 use "hg -v help verify" to show the global options
399 use "hg -v help verify" to show the global options
398
400
399 $ hg help diff
401 $ hg help diff
400 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
402 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
401
403
402 diff repository (or selected files)
404 diff repository (or selected files)
403
405
404 Show differences between revisions for the specified files.
406 Show differences between revisions for the specified files.
405
407
406 Differences between files are shown using the unified diff format.
408 Differences between files are shown using the unified diff format.
407
409
408 Note:
410 Note:
409 diff may generate unexpected results for merges, as it will default to
411 diff may generate unexpected results for merges, as it will default to
410 comparing against the working directory's first parent changeset if no
412 comparing against the working directory's first parent changeset if no
411 revisions are specified.
413 revisions are specified.
412
414
413 When two revision arguments are given, then changes are shown between
415 When two revision arguments are given, then changes are shown between
414 those revisions. If only one revision is specified then that revision is
416 those revisions. If only one revision is specified then that revision is
415 compared to the working directory, and, when no revisions are specified,
417 compared to the working directory, and, when no revisions are specified,
416 the working directory files are compared to its parent.
418 the working directory files are compared to its parent.
417
419
418 Alternatively you can specify -c/--change with a revision to see the
420 Alternatively you can specify -c/--change with a revision to see the
419 changes in that changeset relative to its first parent.
421 changes in that changeset relative to its first parent.
420
422
421 Without the -a/--text option, diff will avoid generating diffs of files it
423 Without the -a/--text option, diff will avoid generating diffs of files it
422 detects as binary. With -a, diff will generate a diff anyway, probably
424 detects as binary. With -a, diff will generate a diff anyway, probably
423 with undesirable results.
425 with undesirable results.
424
426
425 Use the -g/--git option to generate diffs in the git extended diff format.
427 Use the -g/--git option to generate diffs in the git extended diff format.
426 For more information, read "hg help diffs".
428 For more information, read "hg help diffs".
427
429
428 Returns 0 on success.
430 Returns 0 on success.
429
431
430 options:
432 options:
431
433
432 -r --rev REV [+] revision
434 -r --rev REV [+] revision
433 -c --change REV change made by revision
435 -c --change REV change made by revision
434 -a --text treat all files as text
436 -a --text treat all files as text
435 -g --git use git extended diff format
437 -g --git use git extended diff format
436 --nodates omit dates from diff headers
438 --nodates omit dates from diff headers
437 -p --show-function show which function each change is in
439 -p --show-function show which function each change is in
438 --reverse produce a diff that undoes the changes
440 --reverse produce a diff that undoes the changes
439 -w --ignore-all-space ignore white space when comparing lines
441 -w --ignore-all-space ignore white space when comparing lines
440 -b --ignore-space-change ignore changes in the amount of white space
442 -b --ignore-space-change ignore changes in the amount of white space
441 -B --ignore-blank-lines ignore changes whose lines are all blank
443 -B --ignore-blank-lines ignore changes whose lines are all blank
442 -U --unified NUM number of lines of context to show
444 -U --unified NUM number of lines of context to show
443 --stat output diffstat-style summary of changes
445 --stat output diffstat-style summary of changes
444 -I --include PATTERN [+] include names matching the given patterns
446 -I --include PATTERN [+] include names matching the given patterns
445 -X --exclude PATTERN [+] exclude names matching the given patterns
447 -X --exclude PATTERN [+] exclude names matching the given patterns
446 -S --subrepos recurse into subrepositories
448 -S --subrepos recurse into subrepositories
447
449
448 [+] marked option can be specified multiple times
450 [+] marked option can be specified multiple times
449
451
450 use "hg -v help diff" to show more complete help and the global options
452 use "hg -v help diff" to show more complete help and the global options
451
453
452 $ hg help status
454 $ hg help status
453 hg status [OPTION]... [FILE]...
455 hg status [OPTION]... [FILE]...
454
456
455 aliases: st
457 aliases: st
456
458
457 show changed files in the working directory
459 show changed files in the working directory
458
460
459 Show status of files in the repository. If names are given, only files
461 Show status of files in the repository. If names are given, only files
460 that match are shown. Files that are clean or ignored or the source of a
462 that match are shown. Files that are clean or ignored or the source of a
461 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
463 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
462 -C/--copies or -A/--all are given. Unless options described with "show
464 -C/--copies or -A/--all are given. Unless options described with "show
463 only ..." are given, the options -mardu are used.
465 only ..." are given, the options -mardu are used.
464
466
465 Option -q/--quiet hides untracked (unknown and ignored) files unless
467 Option -q/--quiet hides untracked (unknown and ignored) files unless
466 explicitly requested with -u/--unknown or -i/--ignored.
468 explicitly requested with -u/--unknown or -i/--ignored.
467
469
468 Note:
470 Note:
469 status may appear to disagree with diff if permissions have changed or
471 status may appear to disagree with diff if permissions have changed or
470 a merge has occurred. The standard diff format does not report
472 a merge has occurred. The standard diff format does not report
471 permission changes and diff only reports changes relative to one merge
473 permission changes and diff only reports changes relative to one merge
472 parent.
474 parent.
473
475
474 If one revision is given, it is used as the base revision. If two
476 If one revision is given, it is used as the base revision. If two
475 revisions are given, the differences between them are shown. The --change
477 revisions are given, the differences between them are shown. The --change
476 option can also be used as a shortcut to list the changed files of a
478 option can also be used as a shortcut to list the changed files of a
477 revision from its first parent.
479 revision from its first parent.
478
480
479 The codes used to show the status of files are:
481 The codes used to show the status of files are:
480
482
481 M = modified
483 M = modified
482 A = added
484 A = added
483 R = removed
485 R = removed
484 C = clean
486 C = clean
485 ! = missing (deleted by non-hg command, but still tracked)
487 ! = missing (deleted by non-hg command, but still tracked)
486 ? = not tracked
488 ? = not tracked
487 I = ignored
489 I = ignored
488 = origin of the previous file listed as A (added)
490 = origin of the previous file listed as A (added)
489
491
490 Returns 0 on success.
492 Returns 0 on success.
491
493
492 options:
494 options:
493
495
494 -A --all show status of all files
496 -A --all show status of all files
495 -m --modified show only modified files
497 -m --modified show only modified files
496 -a --added show only added files
498 -a --added show only added files
497 -r --removed show only removed files
499 -r --removed show only removed files
498 -d --deleted show only deleted (but tracked) files
500 -d --deleted show only deleted (but tracked) files
499 -c --clean show only files without changes
501 -c --clean show only files without changes
500 -u --unknown show only unknown (not tracked) files
502 -u --unknown show only unknown (not tracked) files
501 -i --ignored show only ignored files
503 -i --ignored show only ignored files
502 -n --no-status hide status prefix
504 -n --no-status hide status prefix
503 -C --copies show source of copied files
505 -C --copies show source of copied files
504 -0 --print0 end filenames with NUL, for use with xargs
506 -0 --print0 end filenames with NUL, for use with xargs
505 --rev REV [+] show difference from revision
507 --rev REV [+] show difference from revision
506 --change REV list the changed files of a revision
508 --change REV list the changed files of a revision
507 -I --include PATTERN [+] include names matching the given patterns
509 -I --include PATTERN [+] include names matching the given patterns
508 -X --exclude PATTERN [+] exclude names matching the given patterns
510 -X --exclude PATTERN [+] exclude names matching the given patterns
509 -S --subrepos recurse into subrepositories
511 -S --subrepos recurse into subrepositories
510
512
511 [+] marked option can be specified multiple times
513 [+] marked option can be specified multiple times
512
514
513 use "hg -v help status" to show more complete help and the global options
515 use "hg -v help status" to show more complete help and the global options
514
516
515 $ hg -q help status
517 $ hg -q help status
516 hg status [OPTION]... [FILE]...
518 hg status [OPTION]... [FILE]...
517
519
518 show changed files in the working directory
520 show changed files in the working directory
519
521
520 $ hg help foo
522 $ hg help foo
521 hg: unknown command 'foo'
523 hg: unknown command 'foo'
522 Mercurial Distributed SCM
524 Mercurial Distributed SCM
523
525
524 basic commands:
526 basic commands:
525
527
526 add add the specified files on the next commit
528 add add the specified files on the next commit
527 annotate show changeset information by line for each file
529 annotate show changeset information by line for each file
528 clone make a copy of an existing repository
530 clone make a copy of an existing repository
529 commit commit the specified files or all outstanding changes
531 commit commit the specified files or all outstanding changes
530 diff diff repository (or selected files)
532 diff diff repository (or selected files)
531 export dump the header and diffs for one or more changesets
533 export dump the header and diffs for one or more changesets
532 forget forget the specified files on the next commit
534 forget forget the specified files on the next commit
533 init create a new repository in the given directory
535 init create a new repository in the given directory
534 log show revision history of entire repository or files
536 log show revision history of entire repository or files
535 merge merge working directory with another revision
537 merge merge working directory with another revision
536 pull pull changes from the specified source
538 pull pull changes from the specified source
537 push push changes to the specified destination
539 push push changes to the specified destination
538 remove remove the specified files on the next commit
540 remove remove the specified files on the next commit
539 serve start stand-alone webserver
541 serve start stand-alone webserver
540 status show changed files in the working directory
542 status show changed files in the working directory
541 summary summarize working directory state
543 summary summarize working directory state
542 update update working directory (or switch revisions)
544 update update working directory (or switch revisions)
543
545
544 use "hg help" for the full list of commands or "hg -v" for details
546 use "hg help" for the full list of commands or "hg -v" for details
545 [255]
547 [255]
546
548
547 $ hg skjdfks
549 $ hg skjdfks
548 hg: unknown command 'skjdfks'
550 hg: unknown command 'skjdfks'
549 Mercurial Distributed SCM
551 Mercurial Distributed SCM
550
552
551 basic commands:
553 basic commands:
552
554
553 add add the specified files on the next commit
555 add add the specified files on the next commit
554 annotate show changeset information by line for each file
556 annotate show changeset information by line for each file
555 clone make a copy of an existing repository
557 clone make a copy of an existing repository
556 commit commit the specified files or all outstanding changes
558 commit commit the specified files or all outstanding changes
557 diff diff repository (or selected files)
559 diff diff repository (or selected files)
558 export dump the header and diffs for one or more changesets
560 export dump the header and diffs for one or more changesets
559 forget forget the specified files on the next commit
561 forget forget the specified files on the next commit
560 init create a new repository in the given directory
562 init create a new repository in the given directory
561 log show revision history of entire repository or files
563 log show revision history of entire repository or files
562 merge merge working directory with another revision
564 merge merge working directory with another revision
563 pull pull changes from the specified source
565 pull pull changes from the specified source
564 push push changes to the specified destination
566 push push changes to the specified destination
565 remove remove the specified files on the next commit
567 remove remove the specified files on the next commit
566 serve start stand-alone webserver
568 serve start stand-alone webserver
567 status show changed files in the working directory
569 status show changed files in the working directory
568 summary summarize working directory state
570 summary summarize working directory state
569 update update working directory (or switch revisions)
571 update update working directory (or switch revisions)
570
572
571 use "hg help" for the full list of commands or "hg -v" for details
573 use "hg help" for the full list of commands or "hg -v" for details
572 [255]
574 [255]
573
575
574 $ cat > helpext.py <<EOF
576 $ cat > helpext.py <<EOF
575 > import os
577 > import os
576 > from mercurial import commands
578 > from mercurial import commands
577 >
579 >
578 > def nohelp(ui, *args, **kwargs):
580 > def nohelp(ui, *args, **kwargs):
579 > pass
581 > pass
580 >
582 >
581 > cmdtable = {
583 > cmdtable = {
582 > "nohelp": (nohelp, [], "hg nohelp"),
584 > "nohelp": (nohelp, [], "hg nohelp"),
583 > }
585 > }
584 >
586 >
585 > commands.norepo += ' nohelp'
587 > commands.norepo += ' nohelp'
586 > EOF
588 > EOF
587 $ echo '[extensions]' >> $HGRCPATH
589 $ echo '[extensions]' >> $HGRCPATH
588 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
590 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
589
591
590 Test command with no help text
592 Test command with no help text
591
593
592 $ hg help nohelp
594 $ hg help nohelp
593 hg nohelp
595 hg nohelp
594
596
595 (no help text available)
597 (no help text available)
596
598
597 use "hg -v help nohelp" to show the global options
599 use "hg -v help nohelp" to show the global options
598
600
599 $ hg help -k nohelp
601 $ hg help -k nohelp
600 Commands:
602 Commands:
601
603
602 nohelp hg nohelp
604 nohelp hg nohelp
603
605
604 Extension Commands:
606 Extension Commands:
605
607
606 nohelp (no help text available)
608 nohelp (no help text available)
607
609
608 Test that default list of commands omits extension commands
610 Test that default list of commands omits extension commands
609
611
610 $ hg help
612 $ hg help
611 Mercurial Distributed SCM
613 Mercurial Distributed SCM
612
614
613 list of commands:
615 list of commands:
614
616
615 add add the specified files on the next commit
617 add add the specified files on the next commit
616 addremove add all new files, delete all missing files
618 addremove add all new files, delete all missing files
617 annotate show changeset information by line for each file
619 annotate show changeset information by line for each file
618 archive create an unversioned archive of a repository revision
620 archive create an unversioned archive of a repository revision
619 backout reverse effect of earlier changeset
621 backout reverse effect of earlier changeset
620 bisect subdivision search of changesets
622 bisect subdivision search of changesets
621 bookmarks track a line of development with movable markers
623 bookmarks track a line of development with movable markers
622 branch set or show the current branch name
624 branch set or show the current branch name
623 branches list repository named branches
625 branches list repository named branches
624 bundle create a changegroup file
626 bundle create a changegroup file
625 cat output the current or given revision of files
627 cat output the current or given revision of files
626 clone make a copy of an existing repository
628 clone make a copy of an existing repository
627 commit commit the specified files or all outstanding changes
629 commit commit the specified files or all outstanding changes
628 copy mark files as copied for the next commit
630 copy mark files as copied for the next commit
629 diff diff repository (or selected files)
631 diff diff repository (or selected files)
630 export dump the header and diffs for one or more changesets
632 export dump the header and diffs for one or more changesets
631 forget forget the specified files on the next commit
633 forget forget the specified files on the next commit
632 graft copy changes from other branches onto the current branch
634 graft copy changes from other branches onto the current branch
633 grep search for a pattern in specified files and revisions
635 grep search for a pattern in specified files and revisions
634 heads show current repository heads or show branch heads
636 heads show current repository heads or show branch heads
635 help show help for a given topic or a help overview
637 help show help for a given topic or a help overview
636 identify identify the working copy or specified revision
638 identify identify the working copy or specified revision
637 import import an ordered set of patches
639 import import an ordered set of patches
638 incoming show new changesets found in source
640 incoming show new changesets found in source
639 init create a new repository in the given directory
641 init create a new repository in the given directory
640 locate locate files matching specific patterns
642 locate locate files matching specific patterns
641 log show revision history of entire repository or files
643 log show revision history of entire repository or files
642 manifest output the current or given revision of the project manifest
644 manifest output the current or given revision of the project manifest
643 merge merge working directory with another revision
645 merge merge working directory with another revision
644 outgoing show changesets not found in the destination
646 outgoing show changesets not found in the destination
645 parents show the parents of the working directory or revision
647 parents show the parents of the working directory or revision
646 paths show aliases for remote repositories
648 paths show aliases for remote repositories
647 phase set or show the current phase name
649 phase set or show the current phase name
648 pull pull changes from the specified source
650 pull pull changes from the specified source
649 push push changes to the specified destination
651 push push changes to the specified destination
650 recover roll back an interrupted transaction
652 recover roll back an interrupted transaction
651 remove remove the specified files on the next commit
653 remove remove the specified files on the next commit
652 rename rename files; equivalent of copy + remove
654 rename rename files; equivalent of copy + remove
653 resolve redo merges or set/view the merge status of files
655 resolve redo merges or set/view the merge status of files
654 revert restore files to their checkout state
656 revert restore files to their checkout state
655 rollback roll back the last transaction (dangerous)
657 rollback roll back the last transaction (dangerous)
656 root print the root (top) of the current working directory
658 root print the root (top) of the current working directory
657 serve start stand-alone webserver
659 serve start stand-alone webserver
658 showconfig show combined config settings from all hgrc files
660 showconfig show combined config settings from all hgrc files
659 status show changed files in the working directory
661 status show changed files in the working directory
660 summary summarize working directory state
662 summary summarize working directory state
661 tag add one or more tags for the current or given revision
663 tag add one or more tags for the current or given revision
662 tags list repository tags
664 tags list repository tags
663 tip show the tip revision
665 tip show the tip revision
664 unbundle apply one or more changegroup files
666 unbundle apply one or more changegroup files
665 update update working directory (or switch revisions)
667 update update working directory (or switch revisions)
666 verify verify the integrity of the repository
668 verify verify the integrity of the repository
667 version output version and copyright information
669 version output version and copyright information
668
670
669 enabled extensions:
671 enabled extensions:
670
672
671 helpext (no help text available)
673 helpext (no help text available)
672
674
673 additional help topics:
675 additional help topics:
674
676
675 config Configuration Files
677 config Configuration Files
676 dates Date Formats
678 dates Date Formats
677 diffs Diff Formats
679 diffs Diff Formats
678 environment Environment Variables
680 environment Environment Variables
679 extensions Using Additional Features
681 extensions Using Additional Features
680 filesets Specifying File Sets
682 filesets Specifying File Sets
681 glossary Glossary
683 glossary Glossary
682 hgignore Syntax for Mercurial Ignore Files
684 hgignore Syntax for Mercurial Ignore Files
683 hgweb Configuring hgweb
685 hgweb Configuring hgweb
684 merge-tools Merge Tools
686 merge-tools Merge Tools
685 multirevs Specifying Multiple Revisions
687 multirevs Specifying Multiple Revisions
686 patterns File Name Patterns
688 patterns File Name Patterns
687 phases Working with Phases
689 phases Working with Phases
688 revisions Specifying Single Revisions
690 revisions Specifying Single Revisions
689 revsets Specifying Revision Sets
691 revsets Specifying Revision Sets
690 subrepos Subrepositories
692 subrepos Subrepositories
691 templating Template Usage
693 templating Template Usage
692 urls URL Paths
694 urls URL Paths
693
695
694 use "hg -v help" to show builtin aliases and global options
696 use "hg -v help" to show builtin aliases and global options
695
697
696
698
697
699
698 Test list of commands with command with no help text
700 Test list of commands with command with no help text
699
701
700 $ hg help helpext
702 $ hg help helpext
701 helpext extension - no help text available
703 helpext extension - no help text available
702
704
703 list of commands:
705 list of commands:
704
706
705 nohelp (no help text available)
707 nohelp (no help text available)
706
708
707 use "hg -v help helpext" to show builtin aliases and global options
709 use "hg -v help helpext" to show builtin aliases and global options
708
710
709 Test a help topic
711 Test a help topic
710
712
711 $ hg help revs
713 $ hg help revs
712 Specifying Single Revisions
714 Specifying Single Revisions
713
715
714 Mercurial supports several ways to specify individual revisions.
716 Mercurial supports several ways to specify individual revisions.
715
717
716 A plain integer is treated as a revision number. Negative integers are
718 A plain integer is treated as a revision number. Negative integers are
717 treated as sequential offsets from the tip, with -1 denoting the tip, -2
719 treated as sequential offsets from the tip, with -1 denoting the tip, -2
718 denoting the revision prior to the tip, and so forth.
720 denoting the revision prior to the tip, and so forth.
719
721
720 A 40-digit hexadecimal string is treated as a unique revision identifier.
722 A 40-digit hexadecimal string is treated as a unique revision identifier.
721
723
722 A hexadecimal string less than 40 characters long is treated as a unique
724 A hexadecimal string less than 40 characters long is treated as a unique
723 revision identifier and is referred to as a short-form identifier. A
725 revision identifier and is referred to as a short-form identifier. A
724 short-form identifier is only valid if it is the prefix of exactly one
726 short-form identifier is only valid if it is the prefix of exactly one
725 full-length identifier.
727 full-length identifier.
726
728
727 Any other string is treated as a bookmark, tag, or branch name. A bookmark
729 Any other string is treated as a bookmark, tag, or branch name. A bookmark
728 is a movable pointer to a revision. A tag is a permanent name associated
730 is a movable pointer to a revision. A tag is a permanent name associated
729 with a revision. A branch name denotes the tipmost revision of that
731 with a revision. A branch name denotes the tipmost revision of that
730 branch. Bookmark, tag, and branch names must not contain the ":"
732 branch. Bookmark, tag, and branch names must not contain the ":"
731 character.
733 character.
732
734
733 The reserved name "tip" always identifies the most recent revision.
735 The reserved name "tip" always identifies the most recent revision.
734
736
735 The reserved name "null" indicates the null revision. This is the revision
737 The reserved name "null" indicates the null revision. This is the revision
736 of an empty repository, and the parent of revision 0.
738 of an empty repository, and the parent of revision 0.
737
739
738 The reserved name "." indicates the working directory parent. If no
740 The reserved name "." indicates the working directory parent. If no
739 working directory is checked out, it is equivalent to null. If an
741 working directory is checked out, it is equivalent to null. If an
740 uncommitted merge is in progress, "." is the revision of the first parent.
742 uncommitted merge is in progress, "." is the revision of the first parent.
741
743
742 Test templating help
744 Test templating help
743
745
744 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
746 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
745 desc String. The text of the changeset description.
747 desc String. The text of the changeset description.
746 diffstat String. Statistics of changes with the following format:
748 diffstat String. Statistics of changes with the following format:
747 firstline Any text. Returns the first line of text.
749 firstline Any text. Returns the first line of text.
748 nonempty Any text. Returns '(none)' if the string is empty.
750 nonempty Any text. Returns '(none)' if the string is empty.
749
751
750 Test help hooks
752 Test help hooks
751
753
752 $ cat > helphook1.py <<EOF
754 $ cat > helphook1.py <<EOF
753 > from mercurial import help
755 > from mercurial import help
754 >
756 >
755 > def rewrite(topic, doc):
757 > def rewrite(topic, doc):
756 > return doc + '\nhelphook1\n'
758 > return doc + '\nhelphook1\n'
757 >
759 >
758 > def extsetup(ui):
760 > def extsetup(ui):
759 > help.addtopichook('revsets', rewrite)
761 > help.addtopichook('revsets', rewrite)
760 > EOF
762 > EOF
761 $ cat > helphook2.py <<EOF
763 $ cat > helphook2.py <<EOF
762 > from mercurial import help
764 > from mercurial import help
763 >
765 >
764 > def rewrite(topic, doc):
766 > def rewrite(topic, doc):
765 > return doc + '\nhelphook2\n'
767 > return doc + '\nhelphook2\n'
766 >
768 >
767 > def extsetup(ui):
769 > def extsetup(ui):
768 > help.addtopichook('revsets', rewrite)
770 > help.addtopichook('revsets', rewrite)
769 > EOF
771 > EOF
770 $ echo '[extensions]' >> $HGRCPATH
772 $ echo '[extensions]' >> $HGRCPATH
771 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
773 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
772 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
774 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
773 $ hg help revsets | grep helphook
775 $ hg help revsets | grep helphook
774 helphook1
776 helphook1
775 helphook2
777 helphook2
776
778
777 Test keyword search help
779 Test keyword search help
778
780
779 $ hg help -k clone
781 $ hg help -k clone
780 Topics:
782 Topics:
781
783
782 config Configuration Files
784 config Configuration Files
783 extensions Using Additional Features
785 extensions Using Additional Features
784 glossary Glossary
786 glossary Glossary
785 phases Working with Phases
787 phases Working with Phases
786 subrepos Subrepositories
788 subrepos Subrepositories
787 urls URL Paths
789 urls URL Paths
788
790
789 Commands:
791 Commands:
790
792
791 clone make a copy of an existing repository
793 clone make a copy of an existing repository
792 paths show aliases for remote repositories
794 paths show aliases for remote repositories
793 update update working directory (or switch revisions)
795 update update working directory (or switch revisions)
794
796
795 Extensions:
797 Extensions:
796
798
797 relink recreates hardlinks between repository clones
799 relink recreates hardlinks between repository clones
798
800
799 Extension Commands:
801 Extension Commands:
800
802
801 qclone clone main and patch repository at same time
803 qclone clone main and patch repository at same time
802
804
803 Test omit indicating for help
805 Test omit indicating for help
804
806
805 $ cat > addverboseitems.py <<EOF
807 $ cat > addverboseitems.py <<EOF
806 > '''extension to test omit indicating.
808 > '''extension to test omit indicating.
807 >
809 >
808 > This paragraph is never omitted (for extension)
810 > This paragraph is never omitted (for extension)
809 >
811 >
810 > .. container:: verbose
812 > .. container:: verbose
811 >
813 >
812 > This paragraph is omitted,
814 > This paragraph is omitted,
813 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
815 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
814 >
816 >
815 > This paragraph is never omitted, too (for extension)
817 > This paragraph is never omitted, too (for extension)
816 > '''
818 > '''
817 >
819 >
818 > from mercurial import help, commands
820 > from mercurial import help, commands
819 > testtopic = """This paragraph is never omitted (for topic).
821 > testtopic = """This paragraph is never omitted (for topic).
820 >
822 >
821 > .. container:: verbose
823 > .. container:: verbose
822 >
824 >
823 > This paragraph is omitted,
825 > This paragraph is omitted,
824 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
826 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
825 >
827 >
826 > This paragraph is never omitted, too (for topic)
828 > This paragraph is never omitted, too (for topic)
827 > """
829 > """
828 > def extsetup(ui):
830 > def extsetup(ui):
829 > help.helptable.append((["topic-containing-verbose"],
831 > help.helptable.append((["topic-containing-verbose"],
830 > "This is the topic to test omit indicating.",
832 > "This is the topic to test omit indicating.",
831 > lambda : testtopic))
833 > lambda : testtopic))
832 > EOF
834 > EOF
833 $ echo '[extensions]' >> $HGRCPATH
835 $ echo '[extensions]' >> $HGRCPATH
834 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
836 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
835 $ hg help addverboseitems
837 $ hg help addverboseitems
836 addverboseitems extension - extension to test omit indicating.
838 addverboseitems extension - extension to test omit indicating.
837
839
838 This paragraph is never omitted (for extension)
840 This paragraph is never omitted (for extension)
839
841
840 This paragraph is never omitted, too (for extension)
842 This paragraph is never omitted, too (for extension)
841
843
842 use "hg help -v addverboseitems" to show more complete help
844 use "hg help -v addverboseitems" to show more complete help
843
845
844 no commands defined
846 no commands defined
845 $ hg help -v addverboseitems
847 $ hg help -v addverboseitems
846 addverboseitems extension - extension to test omit indicating.
848 addverboseitems extension - extension to test omit indicating.
847
849
848 This paragraph is never omitted (for extension)
850 This paragraph is never omitted (for extension)
849
851
850 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
852 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
851
853
852 This paragraph is never omitted, too (for extension)
854 This paragraph is never omitted, too (for extension)
853
855
854 no commands defined
856 no commands defined
855 $ hg help topic-containing-verbose
857 $ hg help topic-containing-verbose
856 This is the topic to test omit indicating.
858 This is the topic to test omit indicating.
857
859
858 This paragraph is never omitted (for topic).
860 This paragraph is never omitted (for topic).
859
861
860 This paragraph is never omitted, too (for topic)
862 This paragraph is never omitted, too (for topic)
861
863
862 use "hg help -v topic-containing-verbose" to show more complete help
864 use "hg help -v topic-containing-verbose" to show more complete help
863 $ hg help -v topic-containing-verbose
865 $ hg help -v topic-containing-verbose
864 This is the topic to test omit indicating.
866 This is the topic to test omit indicating.
865
867
866 This paragraph is never omitted (for topic).
868 This paragraph is never omitted (for topic).
867
869
868 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
870 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
869
871
870 This paragraph is never omitted, too (for topic)
872 This paragraph is never omitted, too (for topic)
871
873
872 Test usage of section marks in help documents
874 Test usage of section marks in help documents
873
875
874 $ cd "$TESTDIR"/../doc
876 $ cd "$TESTDIR"/../doc
875 $ python check-seclevel.py
877 $ python check-seclevel.py
@@ -1,1157 +1,1155 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > keyword =
3 > keyword =
4 > mq =
4 > mq =
5 > notify =
5 > notify =
6 > record =
6 > record =
7 > transplant =
7 > transplant =
8 > [ui]
8 > [ui]
9 > interactive = true
9 > interactive = true
10 > EOF
10 > EOF
11
11
12 hide outer repo
12 hide outer repo
13 $ hg init
13 $ hg init
14
14
15 Run kwdemo before [keyword] files are set up
15 Run kwdemo before [keyword] files are set up
16 as it would succeed without uisetup otherwise
16 as it would succeed without uisetup otherwise
17
17
18 $ hg --quiet kwdemo
18 $ hg --quiet kwdemo
19 [extensions]
19 [extensions]
20 keyword =
20 keyword =
21 [keyword]
21 [keyword]
22 demo.txt =
22 demo.txt =
23 [keywordset]
23 [keywordset]
24 svn = False
24 svn = False
25 [keywordmaps]
25 [keywordmaps]
26 Author = {author|user}
26 Author = {author|user}
27 Date = {date|utcdate}
27 Date = {date|utcdate}
28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
28 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
29 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
30 RCSFile = {file|basename},v
30 RCSFile = {file|basename},v
31 RCSfile = {file|basename},v
31 RCSfile = {file|basename},v
32 Revision = {node|short}
32 Revision = {node|short}
33 Source = {root}/{file},v
33 Source = {root}/{file},v
34 $Author: test $
34 $Author: test $
35 $Date: ????/??/?? ??:??:?? $ (glob)
35 $Date: ????/??/?? ??:??:?? $ (glob)
36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
36 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
37 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
38 $RCSFile: demo.txt,v $
38 $RCSFile: demo.txt,v $
39 $RCSfile: demo.txt,v $
39 $RCSfile: demo.txt,v $
40 $Revision: ???????????? $ (glob)
40 $Revision: ???????????? $ (glob)
41 $Source: */demo.txt,v $ (glob)
41 $Source: */demo.txt,v $ (glob)
42
42
43 $ hg --quiet kwdemo "Branch = {branches}"
43 $ hg --quiet kwdemo "Branch = {branches}"
44 [extensions]
44 [extensions]
45 keyword =
45 keyword =
46 [keyword]
46 [keyword]
47 demo.txt =
47 demo.txt =
48 [keywordset]
48 [keywordset]
49 svn = False
49 svn = False
50 [keywordmaps]
50 [keywordmaps]
51 Branch = {branches}
51 Branch = {branches}
52 $Branch: demobranch $
52 $Branch: demobranch $
53
53
54 $ cat <<EOF >> $HGRCPATH
54 $ cat <<EOF >> $HGRCPATH
55 > [keyword]
55 > [keyword]
56 > ** =
56 > ** =
57 > b = ignore
57 > b = ignore
58 > i = ignore
58 > i = ignore
59 > [hooks]
59 > [hooks]
60 > EOF
60 > EOF
61 $ cp $HGRCPATH $HGRCPATH.nohooks
61 $ cp $HGRCPATH $HGRCPATH.nohooks
62 > cat <<EOF >> $HGRCPATH
62 > cat <<EOF >> $HGRCPATH
63 > commit=
63 > commit=
64 > commit.test=cp a hooktest
64 > commit.test=cp a hooktest
65 > EOF
65 > EOF
66
66
67 $ hg init Test-bndl
67 $ hg init Test-bndl
68 $ cd Test-bndl
68 $ cd Test-bndl
69
69
70 kwshrink should exit silently in empty/invalid repo
70 kwshrink should exit silently in empty/invalid repo
71
71
72 $ hg kwshrink
72 $ hg kwshrink
73
73
74 Symlinks cannot be created on Windows.
74 Symlinks cannot be created on Windows.
75 A bundle to test this was made with:
75 A bundle to test this was made with:
76 hg init t
76 hg init t
77 cd t
77 cd t
78 echo a > a
78 echo a > a
79 ln -s a sym
79 ln -s a sym
80 hg add sym
80 hg add sym
81 hg ci -m addsym -u mercurial
81 hg ci -m addsym -u mercurial
82 hg bundle --base null ../test-keyword.hg
82 hg bundle --base null ../test-keyword.hg
83
83
84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
84 $ hg pull -u "$TESTDIR"/bundles/test-keyword.hg
85 pulling from *test-keyword.hg (glob)
85 pulling from *test-keyword.hg (glob)
86 requesting all changes
86 requesting all changes
87 adding changesets
87 adding changesets
88 adding manifests
88 adding manifests
89 adding file changes
89 adding file changes
90 added 1 changesets with 1 changes to 1 files
90 added 1 changesets with 1 changes to 1 files
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92
92
93 $ echo 'expand $Id$' > a
93 $ echo 'expand $Id$' > a
94 $ echo 'do not process $Id:' >> a
94 $ echo 'do not process $Id:' >> a
95 $ echo 'xxx $' >> a
95 $ echo 'xxx $' >> a
96 $ echo 'ignore $Id$' > b
96 $ echo 'ignore $Id$' > b
97
97
98 Output files as they were created
98 Output files as they were created
99
99
100 $ cat a b
100 $ cat a b
101 expand $Id$
101 expand $Id$
102 do not process $Id:
102 do not process $Id:
103 xxx $
103 xxx $
104 ignore $Id$
104 ignore $Id$
105
105
106 no kwfiles
106 no kwfiles
107
107
108 $ hg kwfiles
108 $ hg kwfiles
109
109
110 untracked candidates
110 untracked candidates
111
111
112 $ hg -v kwfiles --unknown
112 $ hg -v kwfiles --unknown
113 k a
113 k a
114
114
115 Add files and check status
115 Add files and check status
116
116
117 $ hg addremove
117 $ hg addremove
118 adding a
118 adding a
119 adding b
119 adding b
120 $ hg status
120 $ hg status
121 A a
121 A a
122 A b
122 A b
123
123
124
124
125 Default keyword expansion including commit hook
125 Default keyword expansion including commit hook
126 Interrupted commit should not change state or run commit hook
126 Interrupted commit should not change state or run commit hook
127
127
128 $ hg --debug commit
128 $ hg --debug commit
129 abort: empty commit message
129 abort: empty commit message
130 [255]
130 [255]
131 $ hg status
131 $ hg status
132 A a
132 A a
133 A b
133 A b
134
134
135 Commit with several checks
135 Commit with several checks
136
136
137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
137 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
138 a
138 a
139 b
139 b
140 overwriting a expanding keywords
140 overwriting a expanding keywords
141 running hook commit.test: cp a hooktest
141 running hook commit.test: cp a hooktest
142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
142 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
143 $ hg status
143 $ hg status
144 ? hooktest
144 ? hooktest
145 $ hg debugrebuildstate
145 $ hg debugrebuildstate
146 $ hg --quiet identify
146 $ hg --quiet identify
147 ef63ca68695b
147 ef63ca68695b
148
148
149 cat files in working directory with keywords expanded
149 cat files in working directory with keywords expanded
150
150
151 $ cat a b
151 $ cat a b
152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
152 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
153 do not process $Id:
153 do not process $Id:
154 xxx $
154 xxx $
155 ignore $Id$
155 ignore $Id$
156
156
157 hg cat files and symlink, no expansion
157 hg cat files and symlink, no expansion
158
158
159 $ hg cat sym a b && echo
159 $ hg cat sym a b && echo
160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
160 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
161 do not process $Id:
161 do not process $Id:
162 xxx $
162 xxx $
163 ignore $Id$
163 ignore $Id$
164 a
164 a
165
165
166 $ diff a hooktest
166 $ diff a hooktest
167
167
168 $ cp $HGRCPATH.nohooks $HGRCPATH
168 $ cp $HGRCPATH.nohooks $HGRCPATH
169 $ rm hooktest
169 $ rm hooktest
170
170
171 hg status of kw-ignored binary file starting with '\1\n'
171 hg status of kw-ignored binary file starting with '\1\n'
172
172
173 >>> open("i", "wb").write("\1\nfoo")
173 >>> open("i", "wb").write("\1\nfoo")
174 $ hg -q commit -Am metasep i
174 $ hg -q commit -Am metasep i
175 $ hg status
175 $ hg status
176 >>> open("i", "wb").write("\1\nbar")
176 >>> open("i", "wb").write("\1\nbar")
177 $ hg status
177 $ hg status
178 M i
178 M i
179 $ hg -q commit -m "modify metasep" i
179 $ hg -q commit -m "modify metasep" i
180 $ hg status --rev 2:3
180 $ hg status --rev 2:3
181 M i
181 M i
182 $ touch empty
182 $ touch empty
183 $ hg -q commit -A -m "another file"
183 $ hg -q commit -A -m "another file"
184 $ hg status -A --rev 3:4 i
184 $ hg status -A --rev 3:4 i
185 C i
185 C i
186
186
187 $ hg -q strip -n 2
187 $ hg -q strip -n 2
188
188
189 Test hook execution
189 Test hook execution
190
190
191 bundle
191 bundle
192
192
193 $ hg bundle --base null ../kw.hg
193 $ hg bundle --base null ../kw.hg
194 2 changesets found
194 2 changesets found
195 $ cd ..
195 $ cd ..
196 $ hg init Test
196 $ hg init Test
197 $ cd Test
197 $ cd Test
198
198
199 Notify on pull to check whether keywords stay as is in email
199 Notify on pull to check whether keywords stay as is in email
200 ie. if patch.diff wrapper acts as it should
200 ie. if patch.diff wrapper acts as it should
201
201
202 $ cat <<EOF >> $HGRCPATH
202 $ cat <<EOF >> $HGRCPATH
203 > [hooks]
203 > [hooks]
204 > incoming.notify = python:hgext.notify.hook
204 > incoming.notify = python:hgext.notify.hook
205 > [notify]
205 > [notify]
206 > sources = pull
206 > sources = pull
207 > diffstat = False
207 > diffstat = False
208 > maxsubject = 15
208 > maxsubject = 15
209 > [reposubs]
209 > [reposubs]
210 > * = Test
210 > * = Test
211 > EOF
211 > EOF
212
212
213 Pull from bundle and trigger notify
213 Pull from bundle and trigger notify
214
214
215 $ hg pull -u ../kw.hg
215 $ hg pull -u ../kw.hg
216 pulling from ../kw.hg
216 pulling from ../kw.hg
217 requesting all changes
217 requesting all changes
218 adding changesets
218 adding changesets
219 adding manifests
219 adding manifests
220 adding file changes
220 adding file changes
221 added 2 changesets with 3 changes to 3 files
221 added 2 changesets with 3 changes to 3 files
222 Content-Type: text/plain; charset="us-ascii"
222 Content-Type: text/plain; charset="us-ascii"
223 MIME-Version: 1.0
223 MIME-Version: 1.0
224 Content-Transfer-Encoding: 7bit
224 Content-Transfer-Encoding: 7bit
225 Date: * (glob)
225 Date: * (glob)
226 Subject: changeset in...
226 Subject: changeset in...
227 From: mercurial
227 From: mercurial
228 X-Hg-Notification: changeset a2392c293916
228 X-Hg-Notification: changeset a2392c293916
229 Message-Id: <hg.a2392c293916*> (glob)
229 Message-Id: <hg.a2392c293916*> (glob)
230 To: Test
230 To: Test
231
231
232 changeset a2392c293916 in $TESTTMP/Test (glob)
232 changeset a2392c293916 in $TESTTMP/Test (glob)
233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
233 details: $TESTTMP/Test?cmd=changeset;node=a2392c293916
234 description:
234 description:
235 addsym
235 addsym
236
236
237 diffs (6 lines):
237 diffs (6 lines):
238
238
239 diff -r 000000000000 -r a2392c293916 sym
239 diff -r 000000000000 -r a2392c293916 sym
240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
240 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
241 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
242 @@ -0,0 +1,1 @@
242 @@ -0,0 +1,1 @@
243 +a
243 +a
244 \ No newline at end of file
244 \ No newline at end of file
245 Content-Type: text/plain; charset="us-ascii"
245 Content-Type: text/plain; charset="us-ascii"
246 MIME-Version: 1.0
246 MIME-Version: 1.0
247 Content-Transfer-Encoding: 7bit
247 Content-Transfer-Encoding: 7bit
248 Date:* (glob)
248 Date:* (glob)
249 Subject: changeset in...
249 Subject: changeset in...
250 From: User Name <user@example.com>
250 From: User Name <user@example.com>
251 X-Hg-Notification: changeset ef63ca68695b
251 X-Hg-Notification: changeset ef63ca68695b
252 Message-Id: <hg.ef63ca68695b*> (glob)
252 Message-Id: <hg.ef63ca68695b*> (glob)
253 To: Test
253 To: Test
254
254
255 changeset ef63ca68695b in $TESTTMP/Test (glob)
255 changeset ef63ca68695b in $TESTTMP/Test (glob)
256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
256 details: $TESTTMP/Test?cmd=changeset;node=ef63ca68695b
257 description:
257 description:
258 absym
258 absym
259
259
260 diffs (12 lines):
260 diffs (12 lines):
261
261
262 diff -r a2392c293916 -r ef63ca68695b a
262 diff -r a2392c293916 -r ef63ca68695b a
263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
263 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
264 +++ b/a Thu Jan 01 00:00:00 1970 +0000
265 @@ -0,0 +1,3 @@
265 @@ -0,0 +1,3 @@
266 +expand $Id$
266 +expand $Id$
267 +do not process $Id:
267 +do not process $Id:
268 +xxx $
268 +xxx $
269 diff -r a2392c293916 -r ef63ca68695b b
269 diff -r a2392c293916 -r ef63ca68695b b
270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
271 +++ b/b Thu Jan 01 00:00:00 1970 +0000
272 @@ -0,0 +1,1 @@
272 @@ -0,0 +1,1 @@
273 +ignore $Id$
273 +ignore $Id$
274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
275
275
276 $ cp $HGRCPATH.nohooks $HGRCPATH
276 $ cp $HGRCPATH.nohooks $HGRCPATH
277
277
278 Touch files and check with status
278 Touch files and check with status
279
279
280 $ touch a b
280 $ touch a b
281 $ hg status
281 $ hg status
282
282
283 Update and expand
283 Update and expand
284
284
285 $ rm sym a b
285 $ rm sym a b
286 $ hg update -C
286 $ hg update -C
287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 $ cat a b
288 $ cat a b
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
290 do not process $Id:
290 do not process $Id:
291 xxx $
291 xxx $
292 ignore $Id$
292 ignore $Id$
293
293
294 Check whether expansion is filewise and file mode is preserved
294 Check whether expansion is filewise and file mode is preserved
295
295
296 $ echo '$Id$' > c
296 $ echo '$Id$' > c
297 $ echo 'tests for different changenodes' >> c
297 $ echo 'tests for different changenodes' >> c
298 #if unix-permissions
298 #if unix-permissions
299 $ chmod 600 c
299 $ chmod 600 c
300 $ ls -l c | cut -b 1-10
300 $ ls -l c | cut -b 1-10
301 -rw-------
301 -rw-------
302 #endif
302 #endif
303
303
304 commit file c
304 commit file c
305
305
306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
306 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
307 adding c
307 adding c
308 #if unix-permissions
308 #if unix-permissions
309 $ ls -l c | cut -b 1-10
309 $ ls -l c | cut -b 1-10
310 -rw-------
310 -rw-------
311 #endif
311 #endif
312
312
313 force expansion
313 force expansion
314
314
315 $ hg -v kwexpand
315 $ hg -v kwexpand
316 overwriting a expanding keywords
316 overwriting a expanding keywords
317 overwriting c expanding keywords
317 overwriting c expanding keywords
318
318
319 compare changenodes in a and c
319 compare changenodes in a and c
320
320
321 $ cat a c
321 $ cat a c
322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
322 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
323 do not process $Id:
323 do not process $Id:
324 xxx $
324 xxx $
325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
325 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
326 tests for different changenodes
326 tests for different changenodes
327
327
328 record
328 record
329
329
330 $ echo '$Id$' > r
330 $ echo '$Id$' > r
331 $ hg add r
331 $ hg add r
332
332
333 record chunk
333 record chunk
334
334
335 >>> lines = open('a', 'rb').readlines()
335 >>> lines = open('a', 'rb').readlines()
336 >>> lines.insert(1, 'foo\n')
336 >>> lines.insert(1, 'foo\n')
337 >>> lines.append('bar\n')
337 >>> lines.append('bar\n')
338 >>> open('a', 'wb').writelines(lines)
338 >>> open('a', 'wb').writelines(lines)
339 $ hg record -d '10 1' -m rectest a<<EOF
339 $ hg record -d '10 1' -m rectest a<<EOF
340 > y
340 > y
341 > y
341 > y
342 > n
342 > n
343 > EOF
343 > EOF
344 diff --git a/a b/a
344 diff --git a/a b/a
345 2 hunks, 2 lines changed
345 2 hunks, 2 lines changed
346 examine changes to 'a'? [Ynesfdaq?]
346 examine changes to 'a'? [Ynesfdaq?]
347 @@ -1,3 +1,4 @@
347 @@ -1,3 +1,4 @@
348 expand $Id$
348 expand $Id$
349 +foo
349 +foo
350 do not process $Id:
350 do not process $Id:
351 xxx $
351 xxx $
352 record change 1/2 to 'a'? [Ynesfdaq?]
352 record change 1/2 to 'a'? [Ynesfdaq?]
353 @@ -2,2 +3,3 @@
353 @@ -2,2 +3,3 @@
354 do not process $Id:
354 do not process $Id:
355 xxx $
355 xxx $
356 +bar
356 +bar
357 record change 2/2 to 'a'? [Ynesfdaq?]
357 record change 2/2 to 'a'? [Ynesfdaq?]
358
358
359 $ hg identify
359 $ hg identify
360 5f5eb23505c3+ tip
360 5f5eb23505c3+ tip
361 $ hg status
361 $ hg status
362 M a
362 M a
363 A r
363 A r
364
364
365 Cat modified file a
365 Cat modified file a
366
366
367 $ cat a
367 $ cat a
368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
368 expand $Id: a,v 5f5eb23505c3 1970/01/01 00:00:10 test $
369 foo
369 foo
370 do not process $Id:
370 do not process $Id:
371 xxx $
371 xxx $
372 bar
372 bar
373
373
374 Diff remaining chunk
374 Diff remaining chunk
375
375
376 $ hg diff a
376 $ hg diff a
377 diff -r 5f5eb23505c3 a
377 diff -r 5f5eb23505c3 a
378 --- a/a Thu Jan 01 00:00:09 1970 -0000
378 --- a/a Thu Jan 01 00:00:09 1970 -0000
379 +++ b/a * (glob)
379 +++ b/a * (glob)
380 @@ -2,3 +2,4 @@
380 @@ -2,3 +2,4 @@
381 foo
381 foo
382 do not process $Id:
382 do not process $Id:
383 xxx $
383 xxx $
384 +bar
384 +bar
385
385
386 $ hg rollback
386 $ hg rollback
387 repository tip rolled back to revision 2 (undo commit)
387 repository tip rolled back to revision 2 (undo commit)
388 working directory now based on revision 2
388 working directory now based on revision 2
389
389
390 Record all chunks in file a
390 Record all chunks in file a
391
391
392 $ echo foo > msg
392 $ echo foo > msg
393
393
394 - do not use "hg record -m" here!
394 - do not use "hg record -m" here!
395
395
396 $ hg record -l msg -d '11 1' a<<EOF
396 $ hg record -l msg -d '11 1' a<<EOF
397 > y
397 > y
398 > y
398 > y
399 > y
399 > y
400 > EOF
400 > EOF
401 diff --git a/a b/a
401 diff --git a/a b/a
402 2 hunks, 2 lines changed
402 2 hunks, 2 lines changed
403 examine changes to 'a'? [Ynesfdaq?]
403 examine changes to 'a'? [Ynesfdaq?]
404 @@ -1,3 +1,4 @@
404 @@ -1,3 +1,4 @@
405 expand $Id$
405 expand $Id$
406 +foo
406 +foo
407 do not process $Id:
407 do not process $Id:
408 xxx $
408 xxx $
409 record change 1/2 to 'a'? [Ynesfdaq?]
409 record change 1/2 to 'a'? [Ynesfdaq?]
410 @@ -2,2 +3,3 @@
410 @@ -2,2 +3,3 @@
411 do not process $Id:
411 do not process $Id:
412 xxx $
412 xxx $
413 +bar
413 +bar
414 record change 2/2 to 'a'? [Ynesfdaq?]
414 record change 2/2 to 'a'? [Ynesfdaq?]
415
415
416 File a should be clean
416 File a should be clean
417
417
418 $ hg status -A a
418 $ hg status -A a
419 C a
419 C a
420
420
421 rollback and revert expansion
421 rollback and revert expansion
422
422
423 $ cat a
423 $ cat a
424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
424 expand $Id: a,v 78e0a02d76aa 1970/01/01 00:00:11 test $
425 foo
425 foo
426 do not process $Id:
426 do not process $Id:
427 xxx $
427 xxx $
428 bar
428 bar
429 $ hg --verbose rollback
429 $ hg --verbose rollback
430 repository tip rolled back to revision 2 (undo commit)
430 repository tip rolled back to revision 2 (undo commit)
431 working directory now based on revision 2
431 working directory now based on revision 2
432 overwriting a expanding keywords
432 overwriting a expanding keywords
433 $ hg status a
433 $ hg status a
434 M a
434 M a
435 $ cat a
435 $ cat a
436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
436 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
437 foo
437 foo
438 do not process $Id:
438 do not process $Id:
439 xxx $
439 xxx $
440 bar
440 bar
441 $ echo '$Id$' > y
441 $ echo '$Id$' > y
442 $ echo '$Id$' > z
442 $ echo '$Id$' > z
443 $ hg add y
443 $ hg add y
444 $ hg commit -Am "rollback only" z
444 $ hg commit -Am "rollback only" z
445 $ cat z
445 $ cat z
446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
446 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
447 $ hg --verbose rollback
447 $ hg --verbose rollback
448 repository tip rolled back to revision 2 (undo commit)
448 repository tip rolled back to revision 2 (undo commit)
449 working directory now based on revision 2
449 working directory now based on revision 2
450 overwriting z shrinking keywords
450 overwriting z shrinking keywords
451
451
452 Only z should be overwritten
452 Only z should be overwritten
453
453
454 $ hg status a y z
454 $ hg status a y z
455 M a
455 M a
456 A y
456 A y
457 A z
457 A z
458 $ cat z
458 $ cat z
459 $Id$
459 $Id$
460 $ hg forget y z
460 $ hg forget y z
461 $ rm y z
461 $ rm y z
462
462
463 record added file alone
463 record added file alone
464
464
465 $ hg -v record -l msg -d '12 2' r<<EOF
465 $ hg -v record -l msg -d '12 2' r<<EOF
466 > y
466 > y
467 > EOF
467 > EOF
468 diff --git a/r b/r
468 diff --git a/r b/r
469 new file mode 100644
469 new file mode 100644
470 examine changes to 'r'? [Ynesfdaq?]
470 examine changes to 'r'? [Ynesfdaq?]
471 r
471 r
472 committed changeset 3:82a2f715724d
472 committed changeset 3:82a2f715724d
473 overwriting r expanding keywords
473 overwriting r expanding keywords
474 - status call required for dirstate.normallookup() check
474 - status call required for dirstate.normallookup() check
475 $ hg status r
475 $ hg status r
476 $ hg --verbose rollback
476 $ hg --verbose rollback
477 repository tip rolled back to revision 2 (undo commit)
477 repository tip rolled back to revision 2 (undo commit)
478 working directory now based on revision 2
478 working directory now based on revision 2
479 overwriting r shrinking keywords
479 overwriting r shrinking keywords
480 $ hg forget r
480 $ hg forget r
481 $ rm msg r
481 $ rm msg r
482 $ hg update -C
482 $ hg update -C
483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
484
484
485 record added keyword ignored file
485 record added keyword ignored file
486
486
487 $ echo '$Id$' > i
487 $ echo '$Id$' > i
488 $ hg add i
488 $ hg add i
489 $ hg --verbose record -d '13 1' -m recignored<<EOF
489 $ hg --verbose record -d '13 1' -m recignored<<EOF
490 > y
490 > y
491 > EOF
491 > EOF
492 diff --git a/i b/i
492 diff --git a/i b/i
493 new file mode 100644
493 new file mode 100644
494 examine changes to 'i'? [Ynesfdaq?]
494 examine changes to 'i'? [Ynesfdaq?]
495 i
495 i
496 committed changeset 3:9f40ceb5a072
496 committed changeset 3:9f40ceb5a072
497 $ cat i
497 $ cat i
498 $Id$
498 $Id$
499 $ hg -q rollback
499 $ hg -q rollback
500 $ hg forget i
500 $ hg forget i
501 $ rm i
501 $ rm i
502
502
503 amend
503 amend
504
504
505 $ echo amend >> a
505 $ echo amend >> a
506 $ echo amend >> b
506 $ echo amend >> b
507 $ hg -q commit -d '14 1' -m 'prepare amend'
507 $ hg -q commit -d '14 1' -m 'prepare amend'
508
508
509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
509 $ hg --debug commit --amend -d '15 1' -m 'amend without changes' | grep keywords
510 overwriting a expanding keywords
510 overwriting a expanding keywords
511 $ hg -q id
511 $ hg -q id
512 67d8c481a6be
512 67d8c481a6be
513 $ head -1 a
513 $ head -1 a
514 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
514 expand $Id: a,v 67d8c481a6be 1970/01/01 00:00:15 test $
515
515
516 $ hg -q strip -n tip
516 $ hg -q strip -n tip
517
517
518 Test patch queue repo
518 Test patch queue repo
519
519
520 $ hg init --mq
520 $ hg init --mq
521 $ hg qimport -r tip -n mqtest.diff
521 $ hg qimport -r tip -n mqtest.diff
522 $ hg commit --mq -m mqtest
522 $ hg commit --mq -m mqtest
523
523
524 Keywords should not be expanded in patch
524 Keywords should not be expanded in patch
525
525
526 $ cat .hg/patches/mqtest.diff
526 $ cat .hg/patches/mqtest.diff
527 # HG changeset patch
527 # HG changeset patch
528 # User User Name <user@example.com>
528 # User User Name <user@example.com>
529 # Date 1 0
529 # Date 1 0
530 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
530 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
531 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
531 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
532 cndiff
532 cndiff
533
533
534 diff -r ef63ca68695b -r 40a904bbbe4c c
534 diff -r ef63ca68695b -r 40a904bbbe4c c
535 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
535 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
536 +++ b/c Thu Jan 01 00:00:01 1970 +0000
536 +++ b/c Thu Jan 01 00:00:01 1970 +0000
537 @@ -0,0 +1,2 @@
537 @@ -0,0 +1,2 @@
538 +$Id$
538 +$Id$
539 +tests for different changenodes
539 +tests for different changenodes
540
540
541 $ hg qpop
541 $ hg qpop
542 popping mqtest.diff
542 popping mqtest.diff
543 patch queue now empty
543 patch queue now empty
544
544
545 qgoto, implying qpush, should expand
545 qgoto, implying qpush, should expand
546
546
547 $ hg qgoto mqtest.diff
547 $ hg qgoto mqtest.diff
548 applying mqtest.diff
548 applying mqtest.diff
549 now at: mqtest.diff
549 now at: mqtest.diff
550 $ cat c
550 $ cat c
551 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
551 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
552 tests for different changenodes
552 tests for different changenodes
553 $ hg cat c
553 $ hg cat c
554 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
554 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
555 tests for different changenodes
555 tests for different changenodes
556
556
557 Keywords should not be expanded in filelog
557 Keywords should not be expanded in filelog
558
558
559 $ hg --config 'extensions.keyword=!' cat c
559 $ hg --config 'extensions.keyword=!' cat c
560 $Id$
560 $Id$
561 tests for different changenodes
561 tests for different changenodes
562
562
563 qpop and move on
563 qpop and move on
564
564
565 $ hg qpop
565 $ hg qpop
566 popping mqtest.diff
566 popping mqtest.diff
567 patch queue now empty
567 patch queue now empty
568
568
569 Copy and show added kwfiles
569 Copy and show added kwfiles
570
570
571 $ hg cp a c
571 $ hg cp a c
572 $ hg kwfiles
572 $ hg kwfiles
573 a
573 a
574 c
574 c
575
575
576 Commit and show expansion in original and copy
576 Commit and show expansion in original and copy
577
577
578 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
578 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
579 invalid branchheads cache (unserved): tip differs
579 c
580 c
580 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
581 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
581 overwriting c expanding keywords
582 overwriting c expanding keywords
582 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
583 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
583 $ cat a c
584 $ cat a c
584 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
585 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
585 do not process $Id:
586 do not process $Id:
586 xxx $
587 xxx $
587 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
588 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
588 do not process $Id:
589 do not process $Id:
589 xxx $
590 xxx $
590
591
591 Touch copied c and check its status
592 Touch copied c and check its status
592
593
593 $ touch c
594 $ touch c
594 $ hg status
595 $ hg status
595
596
596 Copy kwfile to keyword ignored file unexpanding keywords
597 Copy kwfile to keyword ignored file unexpanding keywords
597
598
598 $ hg --verbose copy a i
599 $ hg --verbose copy a i
599 copying a to i
600 copying a to i
600 overwriting i shrinking keywords
601 overwriting i shrinking keywords
601 $ head -n 1 i
602 $ head -n 1 i
602 expand $Id$
603 expand $Id$
603 $ hg forget i
604 $ hg forget i
604 $ rm i
605 $ rm i
605
606
606 Copy ignored file to ignored file: no overwriting
607 Copy ignored file to ignored file: no overwriting
607
608
608 $ hg --verbose copy b i
609 $ hg --verbose copy b i
609 copying b to i
610 copying b to i
610 $ hg forget i
611 $ hg forget i
611 $ rm i
612 $ rm i
612
613
613 cp symlink file; hg cp -A symlink file (part1)
614 cp symlink file; hg cp -A symlink file (part1)
614 - copied symlink points to kwfile: overwrite
615 - copied symlink points to kwfile: overwrite
615
616
616 #if symlink
617 #if symlink
617 $ cp sym i
618 $ cp sym i
618 $ ls -l i
619 $ ls -l i
619 -rw-r--r--* (glob)
620 -rw-r--r--* (glob)
620 $ head -1 i
621 $ head -1 i
621 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
622 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
622 $ hg copy --after --verbose sym i
623 $ hg copy --after --verbose sym i
623 copying sym to i
624 copying sym to i
624 overwriting i shrinking keywords
625 overwriting i shrinking keywords
625 $ head -1 i
626 $ head -1 i
626 expand $Id$
627 expand $Id$
627 $ hg forget i
628 $ hg forget i
628 $ rm i
629 $ rm i
629 #endif
630 #endif
630
631
631 Test different options of hg kwfiles
632 Test different options of hg kwfiles
632
633
633 $ hg kwfiles
634 $ hg kwfiles
634 a
635 a
635 c
636 c
636 $ hg -v kwfiles --ignore
637 $ hg -v kwfiles --ignore
637 I b
638 I b
638 I sym
639 I sym
639 $ hg kwfiles --all
640 $ hg kwfiles --all
640 K a
641 K a
641 K c
642 K c
642 I b
643 I b
643 I sym
644 I sym
644
645
645 Diff specific revision
646 Diff specific revision
646
647
647 $ hg diff --rev 1
648 $ hg diff --rev 1
648 diff -r ef63ca68695b c
649 diff -r ef63ca68695b c
649 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
650 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
650 +++ b/c * (glob)
651 +++ b/c * (glob)
651 @@ -0,0 +1,3 @@
652 @@ -0,0 +1,3 @@
652 +expand $Id$
653 +expand $Id$
653 +do not process $Id:
654 +do not process $Id:
654 +xxx $
655 +xxx $
655
656
656 Status after rollback:
657 Status after rollback:
657
658
658 $ hg rollback
659 $ hg rollback
659 repository tip rolled back to revision 1 (undo commit)
660 repository tip rolled back to revision 1 (undo commit)
660 working directory now based on revision 1
661 working directory now based on revision 1
661 $ hg status
662 $ hg status
662 A c
663 A c
663 $ hg update --clean
664 $ hg update --clean
664 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
665 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
665
666
666 #if symlink
667 #if symlink
667
668
668 cp symlink file; hg cp -A symlink file (part2)
669 cp symlink file; hg cp -A symlink file (part2)
669 - copied symlink points to kw ignored file: do not overwrite
670 - copied symlink points to kw ignored file: do not overwrite
670
671
671 $ cat a > i
672 $ cat a > i
672 $ ln -s i symignored
673 $ ln -s i symignored
673 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
674 $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
674 $ cp symignored x
675 $ cp symignored x
675 $ hg copy --after --verbose symignored x
676 $ hg copy --after --verbose symignored x
676 copying symignored to x
677 copying symignored to x
677 $ head -n 1 x
678 $ head -n 1 x
678 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
679 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
679 $ hg forget x
680 $ hg forget x
680 $ rm x
681 $ rm x
681
682
682 $ hg rollback
683 $ hg rollback
683 repository tip rolled back to revision 1 (undo commit)
684 repository tip rolled back to revision 1 (undo commit)
684 working directory now based on revision 1
685 working directory now based on revision 1
685 $ hg update --clean
686 $ hg update --clean
686 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
687 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
687 $ rm i symignored
688 $ rm i symignored
688
689
689 #endif
690 #endif
690
691
691 Custom keywordmaps as argument to kwdemo
692 Custom keywordmaps as argument to kwdemo
692
693
693 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
694 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
694 [extensions]
695 [extensions]
695 keyword =
696 keyword =
696 [keyword]
697 [keyword]
697 ** =
698 ** =
698 b = ignore
699 b = ignore
699 demo.txt =
700 demo.txt =
700 i = ignore
701 i = ignore
701 [keywordset]
702 [keywordset]
702 svn = False
703 svn = False
703 [keywordmaps]
704 [keywordmaps]
704 Xinfo = {author}: {desc}
705 Xinfo = {author}: {desc}
705 $Xinfo: test: hg keyword configuration and expansion example $
706 $Xinfo: test: hg keyword configuration and expansion example $
706
707
707 Configure custom keywordmaps
708 Configure custom keywordmaps
708
709
709 $ cat <<EOF >>$HGRCPATH
710 $ cat <<EOF >>$HGRCPATH
710 > [keywordmaps]
711 > [keywordmaps]
711 > Id = {file} {node|short} {date|rfc822date} {author|user}
712 > Id = {file} {node|short} {date|rfc822date} {author|user}
712 > Xinfo = {author}: {desc}
713 > Xinfo = {author}: {desc}
713 > EOF
714 > EOF
714
715
715 Cat and hg cat files before custom expansion
716 Cat and hg cat files before custom expansion
716
717
717 $ cat a b
718 $ cat a b
718 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
719 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
719 do not process $Id:
720 do not process $Id:
720 xxx $
721 xxx $
721 ignore $Id$
722 ignore $Id$
722 $ hg cat sym a b && echo
723 $ hg cat sym a b && echo
723 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
724 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
724 do not process $Id:
725 do not process $Id:
725 xxx $
726 xxx $
726 ignore $Id$
727 ignore $Id$
727 a
728 a
728
729
729 Write custom keyword and prepare multi-line commit message
730 Write custom keyword and prepare multi-line commit message
730
731
731 $ echo '$Xinfo$' >> a
732 $ echo '$Xinfo$' >> a
732 $ cat <<EOF >> log
733 $ cat <<EOF >> log
733 > firstline
734 > firstline
734 > secondline
735 > secondline
735 > EOF
736 > EOF
736
737
737 Interrupted commit should not change state
738 Interrupted commit should not change state
738
739
739 $ hg commit
740 $ hg commit
740 abort: empty commit message
741 abort: empty commit message
741 [255]
742 [255]
742 $ hg status
743 $ hg status
743 M a
744 M a
744 ? c
745 ? c
745 ? log
746 ? log
746
747
747 Commit with multi-line message and custom expansion
748 Commit with multi-line message and custom expansion
748
749
749 |Note:
750 |Note:
750 |
751 |
751 | After the last rollback, the "unserved" branchheads cache became invalid, but
752 | After the last rollback, the "unserved" branchheads cache became invalid, but
752 | all changeset in the repo were public. So filtering wise:
753 | all changeset in the repo were public. So filtering wise:
753 | "mutable" == "unserved" == ø.
754 | "mutable" == "unserved" == ø.
754 |
755 |
755 | As the "unserved" cache is invalid, we fall back to "mutable" cache. But not
756 | As the "unserved" cache is invalid, we fall back to "mutable" cache. But not
756 | update is needed between "mutable" and "unserved" cache and the "unserved"
757 | update is needed between "mutable" and "unserved" cache and the "unserved"
757 | cache is not updated on disk. The on disk version therefor stay invalid for
758 | cache is not updated on disk. The on disk version therefor stay invalid for
758 | some time. This explains why the "unserved" branchheads cache is detect
759 | some time. This explains why the "unserved" branchheads cache is detect
759 | invalid here.
760 | invalid here.
760
761
761 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
762 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
762 invalid branchheads cache: tip differs
763 invalid branchheads cache (unserved): tip differs
763 invalid branchheads cache (unserved): tip differs
764 a
764 a
765 invalid branchheads cache: tip differs
765 invalid branchheads cache: tip differs
766 invalid branchheads cache (unserved): tip differs
766 invalid branchheads cache (unserved): tip differs
767 overwriting a expanding keywords
767 overwriting a expanding keywords
768 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
768 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
769 $ rm log
769 $ rm log
770
770
771 Stat, verify and show custom expansion (firstline)
771 Stat, verify and show custom expansion (firstline)
772
772
773 $ hg status
773 $ hg status
774 ? c
774 ? c
775 $ hg verify
775 $ hg verify
776 checking changesets
776 checking changesets
777 checking manifests
777 checking manifests
778 crosschecking files in changesets and manifests
778 crosschecking files in changesets and manifests
779 checking files
779 checking files
780 3 files, 3 changesets, 4 total revisions
780 3 files, 3 changesets, 4 total revisions
781 $ cat a b
781 $ cat a b
782 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
782 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
783 do not process $Id:
783 do not process $Id:
784 xxx $
784 xxx $
785 $Xinfo: User Name <user@example.com>: firstline $
785 $Xinfo: User Name <user@example.com>: firstline $
786 ignore $Id$
786 ignore $Id$
787 $ hg cat sym a b && echo
787 $ hg cat sym a b && echo
788 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
788 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
789 do not process $Id:
789 do not process $Id:
790 xxx $
790 xxx $
791 $Xinfo: User Name <user@example.com>: firstline $
791 $Xinfo: User Name <user@example.com>: firstline $
792 ignore $Id$
792 ignore $Id$
793 a
793 a
794
794
795 annotate
795 annotate
796
796
797 $ hg annotate a
797 $ hg annotate a
798 1: expand $Id$
798 1: expand $Id$
799 1: do not process $Id:
799 1: do not process $Id:
800 1: xxx $
800 1: xxx $
801 2: $Xinfo$
801 2: $Xinfo$
802
802
803 remove with status checks
803 remove with status checks
804
804
805 $ hg debugrebuildstate
805 $ hg debugrebuildstate
806 $ hg remove a
806 $ hg remove a
807 $ hg --debug commit -m rma
807 $ hg --debug commit -m rma
808 invalid branchheads cache: tip differs
808 invalid branchheads cache: tip differs
809 invalid branchheads cache: tip differs
810 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
809 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
811 $ hg status
810 $ hg status
812 ? c
811 ? c
813
812
814 Rollback, revert, and check expansion
813 Rollback, revert, and check expansion
815
814
816 $ hg rollback
815 $ hg rollback
817 repository tip rolled back to revision 2 (undo commit)
816 repository tip rolled back to revision 2 (undo commit)
818 working directory now based on revision 2
817 working directory now based on revision 2
819 $ hg status
818 $ hg status
820 R a
819 R a
821 ? c
820 ? c
822 $ hg revert --no-backup --rev tip a
821 $ hg revert --no-backup --rev tip a
823 $ cat a
822 $ cat a
824 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
823 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
825 do not process $Id:
824 do not process $Id:
826 xxx $
825 xxx $
827 $Xinfo: User Name <user@example.com>: firstline $
826 $Xinfo: User Name <user@example.com>: firstline $
828
827
829 Clone to test global and local configurations
828 Clone to test global and local configurations
830
829
831 $ cd ..
830 $ cd ..
832
831
833 Expansion in destination with global configuration
832 Expansion in destination with global configuration
834
833
835 $ hg --quiet clone Test globalconf
834 $ hg --quiet clone Test globalconf
836 $ cat globalconf/a
835 $ cat globalconf/a
837 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
836 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
838 do not process $Id:
837 do not process $Id:
839 xxx $
838 xxx $
840 $Xinfo: User Name <user@example.com>: firstline $
839 $Xinfo: User Name <user@example.com>: firstline $
841
840
842 No expansion in destination with local configuration in origin only
841 No expansion in destination with local configuration in origin only
843
842
844 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
843 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
845 $ cat localconf/a
844 $ cat localconf/a
846 expand $Id$
845 expand $Id$
847 do not process $Id:
846 do not process $Id:
848 xxx $
847 xxx $
849 $Xinfo$
848 $Xinfo$
850
849
851 Clone to test incoming
850 Clone to test incoming
852
851
853 $ hg clone -r1 Test Test-a
852 $ hg clone -r1 Test Test-a
854 adding changesets
853 adding changesets
855 adding manifests
854 adding manifests
856 adding file changes
855 adding file changes
857 added 2 changesets with 3 changes to 3 files
856 added 2 changesets with 3 changes to 3 files
858 updating to branch default
857 updating to branch default
859 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
858 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
860 $ cd Test-a
859 $ cd Test-a
861 $ cat <<EOF >> .hg/hgrc
860 $ cat <<EOF >> .hg/hgrc
862 > [paths]
861 > [paths]
863 > default = ../Test
862 > default = ../Test
864 > EOF
863 > EOF
865 $ hg incoming
864 $ hg incoming
866 comparing with $TESTTMP/Test (glob)
865 comparing with $TESTTMP/Test (glob)
867 searching for changes
866 searching for changes
868 changeset: 2:bb948857c743
867 changeset: 2:bb948857c743
869 tag: tip
868 tag: tip
870 user: User Name <user@example.com>
869 user: User Name <user@example.com>
871 date: Thu Jan 01 00:00:02 1970 +0000
870 date: Thu Jan 01 00:00:02 1970 +0000
872 summary: firstline
871 summary: firstline
873
872
874 Imported patch should not be rejected
873 Imported patch should not be rejected
875
874
876 >>> import re
875 >>> import re
877 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
876 >>> text = re.sub(r'(Id.*)', r'\1 rejecttest', open('a').read())
878 >>> open('a', 'wb').write(text)
877 >>> open('a', 'wb').write(text)
879 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
878 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
880 a
879 a
881 overwriting a expanding keywords
880 overwriting a expanding keywords
882 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
881 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
883 $ hg export -o ../rejecttest.diff tip
882 $ hg export -o ../rejecttest.diff tip
884 $ cd ../Test
883 $ cd ../Test
885 $ hg import ../rejecttest.diff
884 $ hg import ../rejecttest.diff
886 applying ../rejecttest.diff
885 applying ../rejecttest.diff
887 $ cat a b
886 $ cat a b
888 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
887 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
889 do not process $Id: rejecttest
888 do not process $Id: rejecttest
890 xxx $
889 xxx $
891 $Xinfo: User Name <user@example.com>: rejects? $
890 $Xinfo: User Name <user@example.com>: rejects? $
892 ignore $Id$
891 ignore $Id$
893
892
894 $ hg rollback
893 $ hg rollback
895 repository tip rolled back to revision 2 (undo import)
894 repository tip rolled back to revision 2 (undo import)
896 working directory now based on revision 2
895 working directory now based on revision 2
897 $ hg update --clean
896 $ hg update --clean
898 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
897 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899
898
900 kwexpand/kwshrink on selected files
899 kwexpand/kwshrink on selected files
901
900
902 $ mkdir x
901 $ mkdir x
903 $ hg copy a x/a
902 $ hg copy a x/a
904 $ hg --verbose kwshrink a
903 $ hg --verbose kwshrink a
905 overwriting a shrinking keywords
904 overwriting a shrinking keywords
906 - sleep required for dirstate.normal() check
905 - sleep required for dirstate.normal() check
907 $ sleep 1
906 $ sleep 1
908 $ hg status a
907 $ hg status a
909 $ hg --verbose kwexpand a
908 $ hg --verbose kwexpand a
910 overwriting a expanding keywords
909 overwriting a expanding keywords
911 $ hg status a
910 $ hg status a
912
911
913 kwexpand x/a should abort
912 kwexpand x/a should abort
914
913
915 $ hg --verbose kwexpand x/a
914 $ hg --verbose kwexpand x/a
916 abort: outstanding uncommitted changes
915 abort: outstanding uncommitted changes
917 [255]
916 [255]
918 $ cd x
917 $ cd x
919 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
918 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
920 invalid branchheads cache: tip differs
921 x/a
919 x/a
922 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
920 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
923 invalid branchheads cache: tip differs
921 invalid branchheads cache: tip differs
924 overwriting x/a expanding keywords
922 overwriting x/a expanding keywords
925 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
923 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
926 $ cat a
924 $ cat a
927 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
925 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
928 do not process $Id:
926 do not process $Id:
929 xxx $
927 xxx $
930 $Xinfo: User Name <user@example.com>: xa $
928 $Xinfo: User Name <user@example.com>: xa $
931
929
932 kwshrink a inside directory x
930 kwshrink a inside directory x
933
931
934 $ hg --verbose kwshrink a
932 $ hg --verbose kwshrink a
935 overwriting x/a shrinking keywords
933 overwriting x/a shrinking keywords
936 $ cat a
934 $ cat a
937 expand $Id$
935 expand $Id$
938 do not process $Id:
936 do not process $Id:
939 xxx $
937 xxx $
940 $Xinfo$
938 $Xinfo$
941 $ cd ..
939 $ cd ..
942
940
943 kwexpand nonexistent
941 kwexpand nonexistent
944
942
945 $ hg kwexpand nonexistent
943 $ hg kwexpand nonexistent
946 nonexistent:* (glob)
944 nonexistent:* (glob)
947
945
948
946
949 #if serve
947 #if serve
950 hg serve
948 hg serve
951 - expand with hgweb file
949 - expand with hgweb file
952 - no expansion with hgweb annotate/changeset/filediff
950 - no expansion with hgweb annotate/changeset/filediff
953 - check errors
951 - check errors
954
952
955 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
953 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
956 $ cat hg.pid >> $DAEMON_PIDS
954 $ cat hg.pid >> $DAEMON_PIDS
957 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
955 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
958 200 Script output follows
956 200 Script output follows
959
957
960 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
958 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
961 do not process $Id:
959 do not process $Id:
962 xxx $
960 xxx $
963 $Xinfo: User Name <user@example.com>: firstline $
961 $Xinfo: User Name <user@example.com>: firstline $
964 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
962 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
965 200 Script output follows
963 200 Script output follows
966
964
967
965
968 user@1: expand $Id$
966 user@1: expand $Id$
969 user@1: do not process $Id:
967 user@1: do not process $Id:
970 user@1: xxx $
968 user@1: xxx $
971 user@2: $Xinfo$
969 user@2: $Xinfo$
972
970
973
971
974
972
975
973
976 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
974 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
977 200 Script output follows
975 200 Script output follows
978
976
979
977
980 # HG changeset patch
978 # HG changeset patch
981 # User User Name <user@example.com>
979 # User User Name <user@example.com>
982 # Date 3 0
980 # Date 3 0
983 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
981 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
984 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
982 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
985 xa
983 xa
986
984
987 diff -r bb948857c743 -r b4560182a3f9 x/a
985 diff -r bb948857c743 -r b4560182a3f9 x/a
988 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
986 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
989 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
987 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
990 @@ -0,0 +1,4 @@
988 @@ -0,0 +1,4 @@
991 +expand $Id$
989 +expand $Id$
992 +do not process $Id:
990 +do not process $Id:
993 +xxx $
991 +xxx $
994 +$Xinfo$
992 +$Xinfo$
995
993
996 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
994 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
997 200 Script output follows
995 200 Script output follows
998
996
999
997
1000 diff -r ef63ca68695b -r bb948857c743 a
998 diff -r ef63ca68695b -r bb948857c743 a
1001 --- a/a Thu Jan 01 00:00:00 1970 +0000
999 --- a/a Thu Jan 01 00:00:00 1970 +0000
1002 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1000 +++ b/a Thu Jan 01 00:00:02 1970 +0000
1003 @@ -1,3 +1,4 @@
1001 @@ -1,3 +1,4 @@
1004 expand $Id$
1002 expand $Id$
1005 do not process $Id:
1003 do not process $Id:
1006 xxx $
1004 xxx $
1007 +$Xinfo$
1005 +$Xinfo$
1008
1006
1009
1007
1010
1008
1011
1009
1012 $ cat errors.log
1010 $ cat errors.log
1013 #endif
1011 #endif
1014
1012
1015 Prepare merge and resolve tests
1013 Prepare merge and resolve tests
1016
1014
1017 $ echo '$Id$' > m
1015 $ echo '$Id$' > m
1018 $ hg add m
1016 $ hg add m
1019 $ hg commit -m 4kw
1017 $ hg commit -m 4kw
1020 $ echo foo >> m
1018 $ echo foo >> m
1021 $ hg commit -m 5foo
1019 $ hg commit -m 5foo
1022
1020
1023 simplemerge
1021 simplemerge
1024
1022
1025 $ hg update 4
1023 $ hg update 4
1026 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1024 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1027 $ echo foo >> m
1025 $ echo foo >> m
1028 $ hg commit -m 6foo
1026 $ hg commit -m 6foo
1029 created new head
1027 created new head
1030 $ hg merge
1028 $ hg merge
1031 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1029 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1032 (branch merge, don't forget to commit)
1030 (branch merge, don't forget to commit)
1033 $ hg commit -m simplemerge
1031 $ hg commit -m simplemerge
1034 $ cat m
1032 $ cat m
1035 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1033 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
1036 foo
1034 foo
1037
1035
1038 conflict: keyword should stay outside conflict zone
1036 conflict: keyword should stay outside conflict zone
1039
1037
1040 $ hg update 4
1038 $ hg update 4
1041 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1039 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1042 $ echo bar >> m
1040 $ echo bar >> m
1043 $ hg commit -m 8bar
1041 $ hg commit -m 8bar
1044 created new head
1042 created new head
1045 $ hg merge
1043 $ hg merge
1046 merging m
1044 merging m
1047 warning: conflicts during merge.
1045 warning: conflicts during merge.
1048 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1046 merging m incomplete! (edit conflicts, then use 'hg resolve --mark')
1049 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1047 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1050 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1048 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1051 [1]
1049 [1]
1052 $ cat m
1050 $ cat m
1053 $Id$
1051 $Id$
1054 <<<<<<< local
1052 <<<<<<< local
1055 bar
1053 bar
1056 =======
1054 =======
1057 foo
1055 foo
1058 >>>>>>> other
1056 >>>>>>> other
1059
1057
1060 resolve to local
1058 resolve to local
1061
1059
1062 $ HGMERGE=internal:local hg resolve -a
1060 $ HGMERGE=internal:local hg resolve -a
1063 $ hg commit -m localresolve
1061 $ hg commit -m localresolve
1064 $ cat m
1062 $ cat m
1065 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1063 $Id: m 800511b3a22d Thu, 01 Jan 1970 00:00:00 +0000 test $
1066 bar
1064 bar
1067
1065
1068 Test restricted mode with transplant -b
1066 Test restricted mode with transplant -b
1069
1067
1070 $ hg update 6
1068 $ hg update 6
1071 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1072 $ hg branch foo
1070 $ hg branch foo
1073 marked working directory as branch foo
1071 marked working directory as branch foo
1074 (branches are permanent and global, did you want a bookmark?)
1072 (branches are permanent and global, did you want a bookmark?)
1075 $ mv a a.bak
1073 $ mv a a.bak
1076 $ echo foobranch > a
1074 $ echo foobranch > a
1077 $ cat a.bak >> a
1075 $ cat a.bak >> a
1078 $ rm a.bak
1076 $ rm a.bak
1079 $ hg commit -m 9foobranch
1077 $ hg commit -m 9foobranch
1080 $ hg update default
1078 $ hg update default
1081 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1079 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1082 $ hg -y transplant -b foo tip
1080 $ hg -y transplant -b foo tip
1083 applying 4aa30d025d50
1081 applying 4aa30d025d50
1084 4aa30d025d50 transplanted to e00abbf63521
1082 4aa30d025d50 transplanted to e00abbf63521
1085
1083
1086 Expansion in changeset but not in file
1084 Expansion in changeset but not in file
1087
1085
1088 $ hg tip -p
1086 $ hg tip -p
1089 changeset: 11:e00abbf63521
1087 changeset: 11:e00abbf63521
1090 tag: tip
1088 tag: tip
1091 parent: 9:800511b3a22d
1089 parent: 9:800511b3a22d
1092 user: test
1090 user: test
1093 date: Thu Jan 01 00:00:00 1970 +0000
1091 date: Thu Jan 01 00:00:00 1970 +0000
1094 summary: 9foobranch
1092 summary: 9foobranch
1095
1093
1096 diff -r 800511b3a22d -r e00abbf63521 a
1094 diff -r 800511b3a22d -r e00abbf63521 a
1097 --- a/a Thu Jan 01 00:00:00 1970 +0000
1095 --- a/a Thu Jan 01 00:00:00 1970 +0000
1098 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1096 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1099 @@ -1,3 +1,4 @@
1097 @@ -1,3 +1,4 @@
1100 +foobranch
1098 +foobranch
1101 expand $Id$
1099 expand $Id$
1102 do not process $Id:
1100 do not process $Id:
1103 xxx $
1101 xxx $
1104
1102
1105 $ head -n 2 a
1103 $ head -n 2 a
1106 foobranch
1104 foobranch
1107 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1105 expand $Id: a e00abbf63521 Thu, 01 Jan 1970 00:00:00 +0000 test $
1108
1106
1109 Turn off expansion
1107 Turn off expansion
1110
1108
1111 $ hg -q rollback
1109 $ hg -q rollback
1112 $ hg -q update -C
1110 $ hg -q update -C
1113
1111
1114 kwshrink with unknown file u
1112 kwshrink with unknown file u
1115
1113
1116 $ cp a u
1114 $ cp a u
1117 $ hg --verbose kwshrink
1115 $ hg --verbose kwshrink
1118 overwriting a shrinking keywords
1116 overwriting a shrinking keywords
1119 overwriting m shrinking keywords
1117 overwriting m shrinking keywords
1120 overwriting x/a shrinking keywords
1118 overwriting x/a shrinking keywords
1121
1119
1122 Keywords shrunk in working directory, but not yet disabled
1120 Keywords shrunk in working directory, but not yet disabled
1123 - cat shows unexpanded keywords
1121 - cat shows unexpanded keywords
1124 - hg cat shows expanded keywords
1122 - hg cat shows expanded keywords
1125
1123
1126 $ cat a b
1124 $ cat a b
1127 expand $Id$
1125 expand $Id$
1128 do not process $Id:
1126 do not process $Id:
1129 xxx $
1127 xxx $
1130 $Xinfo$
1128 $Xinfo$
1131 ignore $Id$
1129 ignore $Id$
1132 $ hg cat sym a b && echo
1130 $ hg cat sym a b && echo
1133 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1131 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
1134 do not process $Id:
1132 do not process $Id:
1135 xxx $
1133 xxx $
1136 $Xinfo: User Name <user@example.com>: firstline $
1134 $Xinfo: User Name <user@example.com>: firstline $
1137 ignore $Id$
1135 ignore $Id$
1138 a
1136 a
1139
1137
1140 Now disable keyword expansion
1138 Now disable keyword expansion
1141
1139
1142 $ rm "$HGRCPATH"
1140 $ rm "$HGRCPATH"
1143 $ cat a b
1141 $ cat a b
1144 expand $Id$
1142 expand $Id$
1145 do not process $Id:
1143 do not process $Id:
1146 xxx $
1144 xxx $
1147 $Xinfo$
1145 $Xinfo$
1148 ignore $Id$
1146 ignore $Id$
1149 $ hg cat sym a b && echo
1147 $ hg cat sym a b && echo
1150 expand $Id$
1148 expand $Id$
1151 do not process $Id:
1149 do not process $Id:
1152 xxx $
1150 xxx $
1153 $Xinfo$
1151 $Xinfo$
1154 ignore $Id$
1152 ignore $Id$
1155 a
1153 a
1156
1154
1157 $ cd ..
1155 $ cd ..
@@ -1,1273 +1,1273 b''
1 The g is crafted to have 2 filelog topological heads in a linear
1 The g is crafted to have 2 filelog topological heads in a linear
2 changeset graph
2 changeset graph
3
3
4 $ hg init a
4 $ hg init a
5 $ cd a
5 $ cd a
6 $ echo a > a
6 $ echo a > a
7 $ echo f > f
7 $ echo f > f
8 $ hg ci -Ama -d '1 0'
8 $ hg ci -Ama -d '1 0'
9 adding a
9 adding a
10 adding f
10 adding f
11
11
12 $ hg cp a b
12 $ hg cp a b
13 $ hg cp f g
13 $ hg cp f g
14 $ hg ci -mb -d '2 0'
14 $ hg ci -mb -d '2 0'
15
15
16 $ mkdir dir
16 $ mkdir dir
17 $ hg mv b dir
17 $ hg mv b dir
18 $ echo g >> g
18 $ echo g >> g
19 $ echo f >> f
19 $ echo f >> f
20 $ hg ci -mc -d '3 0'
20 $ hg ci -mc -d '3 0'
21
21
22 $ hg mv a b
22 $ hg mv a b
23 $ hg cp -f f g
23 $ hg cp -f f g
24 $ echo a > d
24 $ echo a > d
25 $ hg add d
25 $ hg add d
26 $ hg ci -md -d '4 0'
26 $ hg ci -md -d '4 0'
27
27
28 $ hg mv dir/b e
28 $ hg mv dir/b e
29 $ hg ci -me -d '5 0'
29 $ hg ci -me -d '5 0'
30
30
31 $ hg log a
31 $ hg log a
32 changeset: 0:9161b9aeaf16
32 changeset: 0:9161b9aeaf16
33 user: test
33 user: test
34 date: Thu Jan 01 00:00:01 1970 +0000
34 date: Thu Jan 01 00:00:01 1970 +0000
35 summary: a
35 summary: a
36
36
37
37
38 -f, directory
38 -f, directory
39
39
40 $ hg log -f dir
40 $ hg log -f dir
41 abort: cannot follow file not in parent revision: "dir"
41 abort: cannot follow file not in parent revision: "dir"
42 [255]
42 [255]
43
43
44 -f, but no args
44 -f, but no args
45
45
46 $ hg log -f
46 $ hg log -f
47 changeset: 4:7e4639b4691b
47 changeset: 4:7e4639b4691b
48 tag: tip
48 tag: tip
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:05 1970 +0000
50 date: Thu Jan 01 00:00:05 1970 +0000
51 summary: e
51 summary: e
52
52
53 changeset: 3:2ca5ba701980
53 changeset: 3:2ca5ba701980
54 user: test
54 user: test
55 date: Thu Jan 01 00:00:04 1970 +0000
55 date: Thu Jan 01 00:00:04 1970 +0000
56 summary: d
56 summary: d
57
57
58 changeset: 2:f8954cd4dc1f
58 changeset: 2:f8954cd4dc1f
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:03 1970 +0000
60 date: Thu Jan 01 00:00:03 1970 +0000
61 summary: c
61 summary: c
62
62
63 changeset: 1:d89b0a12d229
63 changeset: 1:d89b0a12d229
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:02 1970 +0000
65 date: Thu Jan 01 00:00:02 1970 +0000
66 summary: b
66 summary: b
67
67
68 changeset: 0:9161b9aeaf16
68 changeset: 0:9161b9aeaf16
69 user: test
69 user: test
70 date: Thu Jan 01 00:00:01 1970 +0000
70 date: Thu Jan 01 00:00:01 1970 +0000
71 summary: a
71 summary: a
72
72
73
73
74 one rename
74 one rename
75
75
76 $ hg up -q 2
76 $ hg up -q 2
77 $ hg log -vf a
77 $ hg log -vf a
78 changeset: 0:9161b9aeaf16
78 changeset: 0:9161b9aeaf16
79 user: test
79 user: test
80 date: Thu Jan 01 00:00:01 1970 +0000
80 date: Thu Jan 01 00:00:01 1970 +0000
81 files: a f
81 files: a f
82 description:
82 description:
83 a
83 a
84
84
85
85
86
86
87 many renames
87 many renames
88
88
89 $ hg up -q tip
89 $ hg up -q tip
90 $ hg log -vf e
90 $ hg log -vf e
91 changeset: 4:7e4639b4691b
91 changeset: 4:7e4639b4691b
92 tag: tip
92 tag: tip
93 user: test
93 user: test
94 date: Thu Jan 01 00:00:05 1970 +0000
94 date: Thu Jan 01 00:00:05 1970 +0000
95 files: dir/b e
95 files: dir/b e
96 description:
96 description:
97 e
97 e
98
98
99
99
100 changeset: 2:f8954cd4dc1f
100 changeset: 2:f8954cd4dc1f
101 user: test
101 user: test
102 date: Thu Jan 01 00:00:03 1970 +0000
102 date: Thu Jan 01 00:00:03 1970 +0000
103 files: b dir/b f g
103 files: b dir/b f g
104 description:
104 description:
105 c
105 c
106
106
107
107
108 changeset: 1:d89b0a12d229
108 changeset: 1:d89b0a12d229
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:02 1970 +0000
110 date: Thu Jan 01 00:00:02 1970 +0000
111 files: b g
111 files: b g
112 description:
112 description:
113 b
113 b
114
114
115
115
116 changeset: 0:9161b9aeaf16
116 changeset: 0:9161b9aeaf16
117 user: test
117 user: test
118 date: Thu Jan 01 00:00:01 1970 +0000
118 date: Thu Jan 01 00:00:01 1970 +0000
119 files: a f
119 files: a f
120 description:
120 description:
121 a
121 a
122
122
123
123
124
124
125
125
126 log -pf dir/b
126 log -pf dir/b
127
127
128 $ hg up -q 3
128 $ hg up -q 3
129 $ hg log -pf dir/b
129 $ hg log -pf dir/b
130 changeset: 2:f8954cd4dc1f
130 changeset: 2:f8954cd4dc1f
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:03 1970 +0000
132 date: Thu Jan 01 00:00:03 1970 +0000
133 summary: c
133 summary: c
134
134
135 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
135 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
136 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
137 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
137 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
138 @@ -0,0 +1,1 @@
138 @@ -0,0 +1,1 @@
139 +a
139 +a
140
140
141 changeset: 1:d89b0a12d229
141 changeset: 1:d89b0a12d229
142 user: test
142 user: test
143 date: Thu Jan 01 00:00:02 1970 +0000
143 date: Thu Jan 01 00:00:02 1970 +0000
144 summary: b
144 summary: b
145
145
146 diff -r 9161b9aeaf16 -r d89b0a12d229 b
146 diff -r 9161b9aeaf16 -r d89b0a12d229 b
147 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
147 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
148 +++ b/b Thu Jan 01 00:00:02 1970 +0000
148 +++ b/b Thu Jan 01 00:00:02 1970 +0000
149 @@ -0,0 +1,1 @@
149 @@ -0,0 +1,1 @@
150 +a
150 +a
151
151
152 changeset: 0:9161b9aeaf16
152 changeset: 0:9161b9aeaf16
153 user: test
153 user: test
154 date: Thu Jan 01 00:00:01 1970 +0000
154 date: Thu Jan 01 00:00:01 1970 +0000
155 summary: a
155 summary: a
156
156
157 diff -r 000000000000 -r 9161b9aeaf16 a
157 diff -r 000000000000 -r 9161b9aeaf16 a
158 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
158 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
159 +++ b/a Thu Jan 01 00:00:01 1970 +0000
159 +++ b/a Thu Jan 01 00:00:01 1970 +0000
160 @@ -0,0 +1,1 @@
160 @@ -0,0 +1,1 @@
161 +a
161 +a
162
162
163
163
164 log -vf dir/b
164 log -vf dir/b
165
165
166 $ hg log -vf dir/b
166 $ hg log -vf dir/b
167 changeset: 2:f8954cd4dc1f
167 changeset: 2:f8954cd4dc1f
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:03 1970 +0000
169 date: Thu Jan 01 00:00:03 1970 +0000
170 files: b dir/b f g
170 files: b dir/b f g
171 description:
171 description:
172 c
172 c
173
173
174
174
175 changeset: 1:d89b0a12d229
175 changeset: 1:d89b0a12d229
176 user: test
176 user: test
177 date: Thu Jan 01 00:00:02 1970 +0000
177 date: Thu Jan 01 00:00:02 1970 +0000
178 files: b g
178 files: b g
179 description:
179 description:
180 b
180 b
181
181
182
182
183 changeset: 0:9161b9aeaf16
183 changeset: 0:9161b9aeaf16
184 user: test
184 user: test
185 date: Thu Jan 01 00:00:01 1970 +0000
185 date: Thu Jan 01 00:00:01 1970 +0000
186 files: a f
186 files: a f
187 description:
187 description:
188 a
188 a
189
189
190
190
191
191
192
192
193 -f and multiple filelog heads
193 -f and multiple filelog heads
194
194
195 $ hg up -q 2
195 $ hg up -q 2
196 $ hg log -f g --template '{rev}\n'
196 $ hg log -f g --template '{rev}\n'
197 2
197 2
198 1
198 1
199 0
199 0
200 $ hg up -q tip
200 $ hg up -q tip
201 $ hg log -f g --template '{rev}\n'
201 $ hg log -f g --template '{rev}\n'
202 3
202 3
203 2
203 2
204 0
204 0
205
205
206
206
207 log copies with --copies
207 log copies with --copies
208
208
209 $ hg log -vC --template '{rev} {file_copies}\n'
209 $ hg log -vC --template '{rev} {file_copies}\n'
210 4 e (dir/b)
210 4 e (dir/b)
211 3 b (a)g (f)
211 3 b (a)g (f)
212 2 dir/b (b)
212 2 dir/b (b)
213 1 b (a)g (f)
213 1 b (a)g (f)
214 0
214 0
215
215
216 log copies switch without --copies, with old filecopy template
216 log copies switch without --copies, with old filecopy template
217
217
218 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
218 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
219 4
219 4
220 3
220 3
221 2
221 2
222 1
222 1
223 0
223 0
224
224
225 log copies switch with --copies
225 log copies switch with --copies
226
226
227 $ hg log -vC --template '{rev} {file_copies_switch}\n'
227 $ hg log -vC --template '{rev} {file_copies_switch}\n'
228 4 e (dir/b)
228 4 e (dir/b)
229 3 b (a)g (f)
229 3 b (a)g (f)
230 2 dir/b (b)
230 2 dir/b (b)
231 1 b (a)g (f)
231 1 b (a)g (f)
232 0
232 0
233
233
234
234
235 log copies with hardcoded style and with --style=default
235 log copies with hardcoded style and with --style=default
236
236
237 $ hg log -vC -r4
237 $ hg log -vC -r4
238 changeset: 4:7e4639b4691b
238 changeset: 4:7e4639b4691b
239 tag: tip
239 tag: tip
240 user: test
240 user: test
241 date: Thu Jan 01 00:00:05 1970 +0000
241 date: Thu Jan 01 00:00:05 1970 +0000
242 files: dir/b e
242 files: dir/b e
243 copies: e (dir/b)
243 copies: e (dir/b)
244 description:
244 description:
245 e
245 e
246
246
247
247
248 $ hg log -vC -r4 --style=default
248 $ hg log -vC -r4 --style=default
249 changeset: 4:7e4639b4691b
249 changeset: 4:7e4639b4691b
250 tag: tip
250 tag: tip
251 user: test
251 user: test
252 date: Thu Jan 01 00:00:05 1970 +0000
252 date: Thu Jan 01 00:00:05 1970 +0000
253 files: dir/b e
253 files: dir/b e
254 copies: e (dir/b)
254 copies: e (dir/b)
255 description:
255 description:
256 e
256 e
257
257
258
258
259
259
260
260
261 log copies, non-linear manifest
261 log copies, non-linear manifest
262
262
263 $ hg up -C 3
263 $ hg up -C 3
264 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
264 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
265 $ hg mv dir/b e
265 $ hg mv dir/b e
266 $ echo foo > foo
266 $ echo foo > foo
267 $ hg ci -Ame2 -d '6 0'
267 $ hg ci -Ame2 -d '6 0'
268 adding foo
268 adding foo
269 created new head
269 created new head
270 $ hg log -v --template '{rev} {file_copies}\n' -r 5
270 $ hg log -v --template '{rev} {file_copies}\n' -r 5
271 5 e (dir/b)
271 5 e (dir/b)
272
272
273
273
274 log copies, execute bit set
274 log copies, execute bit set
275
275
276 #if execbit
276 #if execbit
277 $ chmod +x e
277 $ chmod +x e
278 $ hg ci -me3 -d '7 0'
278 $ hg ci -me3 -d '7 0'
279 $ hg log -v --template '{rev} {file_copies}\n' -r 6
279 $ hg log -v --template '{rev} {file_copies}\n' -r 6
280 6
280 6
281 #endif
281 #endif
282
282
283
283
284 log -p d
284 log -p d
285
285
286 $ hg log -pv d
286 $ hg log -pv d
287 changeset: 3:2ca5ba701980
287 changeset: 3:2ca5ba701980
288 user: test
288 user: test
289 date: Thu Jan 01 00:00:04 1970 +0000
289 date: Thu Jan 01 00:00:04 1970 +0000
290 files: a b d g
290 files: a b d g
291 description:
291 description:
292 d
292 d
293
293
294
294
295 diff -r f8954cd4dc1f -r 2ca5ba701980 d
295 diff -r f8954cd4dc1f -r 2ca5ba701980 d
296 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
296 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
297 +++ b/d Thu Jan 01 00:00:04 1970 +0000
297 +++ b/d Thu Jan 01 00:00:04 1970 +0000
298 @@ -0,0 +1,1 @@
298 @@ -0,0 +1,1 @@
299 +a
299 +a
300
300
301
301
302
302
303 log --removed file
303 log --removed file
304
304
305 $ hg log --removed -v a
305 $ hg log --removed -v a
306 changeset: 3:2ca5ba701980
306 changeset: 3:2ca5ba701980
307 user: test
307 user: test
308 date: Thu Jan 01 00:00:04 1970 +0000
308 date: Thu Jan 01 00:00:04 1970 +0000
309 files: a b d g
309 files: a b d g
310 description:
310 description:
311 d
311 d
312
312
313
313
314 changeset: 0:9161b9aeaf16
314 changeset: 0:9161b9aeaf16
315 user: test
315 user: test
316 date: Thu Jan 01 00:00:01 1970 +0000
316 date: Thu Jan 01 00:00:01 1970 +0000
317 files: a f
317 files: a f
318 description:
318 description:
319 a
319 a
320
320
321
321
322
322
323 log --removed revrange file
323 log --removed revrange file
324
324
325 $ hg log --removed -v -r0:2 a
325 $ hg log --removed -v -r0:2 a
326 changeset: 0:9161b9aeaf16
326 changeset: 0:9161b9aeaf16
327 user: test
327 user: test
328 date: Thu Jan 01 00:00:01 1970 +0000
328 date: Thu Jan 01 00:00:01 1970 +0000
329 files: a f
329 files: a f
330 description:
330 description:
331 a
331 a
332
332
333
333
334 $ cd ..
334 $ cd ..
335
335
336 log --follow tests
336 log --follow tests
337
337
338 $ hg init follow
338 $ hg init follow
339 $ cd follow
339 $ cd follow
340
340
341 $ echo base > base
341 $ echo base > base
342 $ hg ci -Ambase -d '1 0'
342 $ hg ci -Ambase -d '1 0'
343 adding base
343 adding base
344
344
345 $ echo r1 >> base
345 $ echo r1 >> base
346 $ hg ci -Amr1 -d '1 0'
346 $ hg ci -Amr1 -d '1 0'
347 $ echo r2 >> base
347 $ echo r2 >> base
348 $ hg ci -Amr2 -d '1 0'
348 $ hg ci -Amr2 -d '1 0'
349
349
350 $ hg up -C 1
350 $ hg up -C 1
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 $ echo b1 > b1
352 $ echo b1 > b1
353 $ hg ci -Amb1 -d '1 0'
353 $ hg ci -Amb1 -d '1 0'
354 adding b1
354 adding b1
355 created new head
355 created new head
356
356
357
357
358 log -f
358 log -f
359
359
360 $ hg log -f
360 $ hg log -f
361 changeset: 3:e62f78d544b4
361 changeset: 3:e62f78d544b4
362 tag: tip
362 tag: tip
363 parent: 1:3d5bf5654eda
363 parent: 1:3d5bf5654eda
364 user: test
364 user: test
365 date: Thu Jan 01 00:00:01 1970 +0000
365 date: Thu Jan 01 00:00:01 1970 +0000
366 summary: b1
366 summary: b1
367
367
368 changeset: 1:3d5bf5654eda
368 changeset: 1:3d5bf5654eda
369 user: test
369 user: test
370 date: Thu Jan 01 00:00:01 1970 +0000
370 date: Thu Jan 01 00:00:01 1970 +0000
371 summary: r1
371 summary: r1
372
372
373 changeset: 0:67e992f2c4f3
373 changeset: 0:67e992f2c4f3
374 user: test
374 user: test
375 date: Thu Jan 01 00:00:01 1970 +0000
375 date: Thu Jan 01 00:00:01 1970 +0000
376 summary: base
376 summary: base
377
377
378
378
379
379
380 log -f -r 1:tip
380 log -f -r 1:tip
381
381
382 $ hg up -C 0
382 $ hg up -C 0
383 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
383 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
384 $ echo b2 > b2
384 $ echo b2 > b2
385 $ hg ci -Amb2 -d '1 0'
385 $ hg ci -Amb2 -d '1 0'
386 adding b2
386 adding b2
387 created new head
387 created new head
388 $ hg log -f -r 1:tip
388 $ hg log -f -r 1:tip
389 changeset: 1:3d5bf5654eda
389 changeset: 1:3d5bf5654eda
390 user: test
390 user: test
391 date: Thu Jan 01 00:00:01 1970 +0000
391 date: Thu Jan 01 00:00:01 1970 +0000
392 summary: r1
392 summary: r1
393
393
394 changeset: 2:60c670bf5b30
394 changeset: 2:60c670bf5b30
395 user: test
395 user: test
396 date: Thu Jan 01 00:00:01 1970 +0000
396 date: Thu Jan 01 00:00:01 1970 +0000
397 summary: r2
397 summary: r2
398
398
399 changeset: 3:e62f78d544b4
399 changeset: 3:e62f78d544b4
400 parent: 1:3d5bf5654eda
400 parent: 1:3d5bf5654eda
401 user: test
401 user: test
402 date: Thu Jan 01 00:00:01 1970 +0000
402 date: Thu Jan 01 00:00:01 1970 +0000
403 summary: b1
403 summary: b1
404
404
405
405
406
406
407 log -r . with two parents
407 log -r . with two parents
408
408
409 $ hg up -C 3
409 $ hg up -C 3
410 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
410 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
411 $ hg merge tip
411 $ hg merge tip
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 (branch merge, don't forget to commit)
413 (branch merge, don't forget to commit)
414 $ hg log -r .
414 $ hg log -r .
415 changeset: 3:e62f78d544b4
415 changeset: 3:e62f78d544b4
416 parent: 1:3d5bf5654eda
416 parent: 1:3d5bf5654eda
417 user: test
417 user: test
418 date: Thu Jan 01 00:00:01 1970 +0000
418 date: Thu Jan 01 00:00:01 1970 +0000
419 summary: b1
419 summary: b1
420
420
421
421
422
422
423 log -r . with one parent
423 log -r . with one parent
424
424
425 $ hg ci -mm12 -d '1 0'
425 $ hg ci -mm12 -d '1 0'
426 $ hg log -r .
426 $ hg log -r .
427 changeset: 5:302e9dd6890d
427 changeset: 5:302e9dd6890d
428 tag: tip
428 tag: tip
429 parent: 3:e62f78d544b4
429 parent: 3:e62f78d544b4
430 parent: 4:ddb82e70d1a1
430 parent: 4:ddb82e70d1a1
431 user: test
431 user: test
432 date: Thu Jan 01 00:00:01 1970 +0000
432 date: Thu Jan 01 00:00:01 1970 +0000
433 summary: m12
433 summary: m12
434
434
435
435
436 $ echo postm >> b1
436 $ echo postm >> b1
437 $ hg ci -Amb1.1 -d'1 0'
437 $ hg ci -Amb1.1 -d'1 0'
438
438
439
439
440 log --follow-first
440 log --follow-first
441
441
442 $ hg log --follow-first
442 $ hg log --follow-first
443 changeset: 6:2404bbcab562
443 changeset: 6:2404bbcab562
444 tag: tip
444 tag: tip
445 user: test
445 user: test
446 date: Thu Jan 01 00:00:01 1970 +0000
446 date: Thu Jan 01 00:00:01 1970 +0000
447 summary: b1.1
447 summary: b1.1
448
448
449 changeset: 5:302e9dd6890d
449 changeset: 5:302e9dd6890d
450 parent: 3:e62f78d544b4
450 parent: 3:e62f78d544b4
451 parent: 4:ddb82e70d1a1
451 parent: 4:ddb82e70d1a1
452 user: test
452 user: test
453 date: Thu Jan 01 00:00:01 1970 +0000
453 date: Thu Jan 01 00:00:01 1970 +0000
454 summary: m12
454 summary: m12
455
455
456 changeset: 3:e62f78d544b4
456 changeset: 3:e62f78d544b4
457 parent: 1:3d5bf5654eda
457 parent: 1:3d5bf5654eda
458 user: test
458 user: test
459 date: Thu Jan 01 00:00:01 1970 +0000
459 date: Thu Jan 01 00:00:01 1970 +0000
460 summary: b1
460 summary: b1
461
461
462 changeset: 1:3d5bf5654eda
462 changeset: 1:3d5bf5654eda
463 user: test
463 user: test
464 date: Thu Jan 01 00:00:01 1970 +0000
464 date: Thu Jan 01 00:00:01 1970 +0000
465 summary: r1
465 summary: r1
466
466
467 changeset: 0:67e992f2c4f3
467 changeset: 0:67e992f2c4f3
468 user: test
468 user: test
469 date: Thu Jan 01 00:00:01 1970 +0000
469 date: Thu Jan 01 00:00:01 1970 +0000
470 summary: base
470 summary: base
471
471
472
472
473
473
474 log -P 2
474 log -P 2
475
475
476 $ hg log -P 2
476 $ hg log -P 2
477 changeset: 6:2404bbcab562
477 changeset: 6:2404bbcab562
478 tag: tip
478 tag: tip
479 user: test
479 user: test
480 date: Thu Jan 01 00:00:01 1970 +0000
480 date: Thu Jan 01 00:00:01 1970 +0000
481 summary: b1.1
481 summary: b1.1
482
482
483 changeset: 5:302e9dd6890d
483 changeset: 5:302e9dd6890d
484 parent: 3:e62f78d544b4
484 parent: 3:e62f78d544b4
485 parent: 4:ddb82e70d1a1
485 parent: 4:ddb82e70d1a1
486 user: test
486 user: test
487 date: Thu Jan 01 00:00:01 1970 +0000
487 date: Thu Jan 01 00:00:01 1970 +0000
488 summary: m12
488 summary: m12
489
489
490 changeset: 4:ddb82e70d1a1
490 changeset: 4:ddb82e70d1a1
491 parent: 0:67e992f2c4f3
491 parent: 0:67e992f2c4f3
492 user: test
492 user: test
493 date: Thu Jan 01 00:00:01 1970 +0000
493 date: Thu Jan 01 00:00:01 1970 +0000
494 summary: b2
494 summary: b2
495
495
496 changeset: 3:e62f78d544b4
496 changeset: 3:e62f78d544b4
497 parent: 1:3d5bf5654eda
497 parent: 1:3d5bf5654eda
498 user: test
498 user: test
499 date: Thu Jan 01 00:00:01 1970 +0000
499 date: Thu Jan 01 00:00:01 1970 +0000
500 summary: b1
500 summary: b1
501
501
502
502
503
503
504 log -r tip -p --git
504 log -r tip -p --git
505
505
506 $ hg log -r tip -p --git
506 $ hg log -r tip -p --git
507 changeset: 6:2404bbcab562
507 changeset: 6:2404bbcab562
508 tag: tip
508 tag: tip
509 user: test
509 user: test
510 date: Thu Jan 01 00:00:01 1970 +0000
510 date: Thu Jan 01 00:00:01 1970 +0000
511 summary: b1.1
511 summary: b1.1
512
512
513 diff --git a/b1 b/b1
513 diff --git a/b1 b/b1
514 --- a/b1
514 --- a/b1
515 +++ b/b1
515 +++ b/b1
516 @@ -1,1 +1,2 @@
516 @@ -1,1 +1,2 @@
517 b1
517 b1
518 +postm
518 +postm
519
519
520
520
521
521
522 log -r ""
522 log -r ""
523
523
524 $ hg log -r ''
524 $ hg log -r ''
525 hg: parse error: empty query
525 hg: parse error: empty query
526 [255]
526 [255]
527
527
528 log -r <some unknown node id>
528 log -r <some unknown node id>
529
529
530 $ hg log -r 1000000000000000000000000000000000000000
530 $ hg log -r 1000000000000000000000000000000000000000
531 abort: unknown revision '1000000000000000000000000000000000000000'!
531 abort: unknown revision '1000000000000000000000000000000000000000'!
532 [255]
532 [255]
533
533
534 log -k r1
534 log -k r1
535
535
536 $ hg log -k r1
536 $ hg log -k r1
537 changeset: 1:3d5bf5654eda
537 changeset: 1:3d5bf5654eda
538 user: test
538 user: test
539 date: Thu Jan 01 00:00:01 1970 +0000
539 date: Thu Jan 01 00:00:01 1970 +0000
540 summary: r1
540 summary: r1
541
541
542 log -p -l2 --color=always
542 log -p -l2 --color=always
543
543
544 $ hg --config extensions.color= --config color.mode=ansi \
544 $ hg --config extensions.color= --config color.mode=ansi \
545 > log -p -l2 --color=always
545 > log -p -l2 --color=always
546 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
546 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
547 tag: tip
547 tag: tip
548 user: test
548 user: test
549 date: Thu Jan 01 00:00:01 1970 +0000
549 date: Thu Jan 01 00:00:01 1970 +0000
550 summary: b1.1
550 summary: b1.1
551
551
552 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
552 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
553 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
553 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
554 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
554 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
555 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
555 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
556 b1
556 b1
557 \x1b[0;32m+postm\x1b[0m (esc)
557 \x1b[0;32m+postm\x1b[0m (esc)
558
558
559 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
559 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
560 parent: 3:e62f78d544b4
560 parent: 3:e62f78d544b4
561 parent: 4:ddb82e70d1a1
561 parent: 4:ddb82e70d1a1
562 user: test
562 user: test
563 date: Thu Jan 01 00:00:01 1970 +0000
563 date: Thu Jan 01 00:00:01 1970 +0000
564 summary: m12
564 summary: m12
565
565
566 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
566 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
567 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
567 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
568 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
568 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
569 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
569 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
570 \x1b[0;32m+b2\x1b[0m (esc)
570 \x1b[0;32m+b2\x1b[0m (esc)
571
571
572
572
573
573
574 log -r tip --stat
574 log -r tip --stat
575
575
576 $ hg log -r tip --stat
576 $ hg log -r tip --stat
577 changeset: 6:2404bbcab562
577 changeset: 6:2404bbcab562
578 tag: tip
578 tag: tip
579 user: test
579 user: test
580 date: Thu Jan 01 00:00:01 1970 +0000
580 date: Thu Jan 01 00:00:01 1970 +0000
581 summary: b1.1
581 summary: b1.1
582
582
583 b1 | 1 +
583 b1 | 1 +
584 1 files changed, 1 insertions(+), 0 deletions(-)
584 1 files changed, 1 insertions(+), 0 deletions(-)
585
585
586
586
587 $ cd ..
587 $ cd ..
588
588
589
589
590 User
590 User
591
591
592 $ hg init usertest
592 $ hg init usertest
593 $ cd usertest
593 $ cd usertest
594
594
595 $ echo a > a
595 $ echo a > a
596 $ hg ci -A -m "a" -u "User One <user1@example.org>"
596 $ hg ci -A -m "a" -u "User One <user1@example.org>"
597 adding a
597 adding a
598 $ echo b > b
598 $ echo b > b
599 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
599 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
600 adding b
600 adding b
601
601
602 $ hg log -u "User One <user1@example.org>"
602 $ hg log -u "User One <user1@example.org>"
603 changeset: 0:29a4c94f1924
603 changeset: 0:29a4c94f1924
604 user: User One <user1@example.org>
604 user: User One <user1@example.org>
605 date: Thu Jan 01 00:00:00 1970 +0000
605 date: Thu Jan 01 00:00:00 1970 +0000
606 summary: a
606 summary: a
607
607
608 $ hg log -u "user1" -u "user2"
608 $ hg log -u "user1" -u "user2"
609 changeset: 1:e834b5e69c0e
609 changeset: 1:e834b5e69c0e
610 tag: tip
610 tag: tip
611 user: User Two <user2@example.org>
611 user: User Two <user2@example.org>
612 date: Thu Jan 01 00:00:00 1970 +0000
612 date: Thu Jan 01 00:00:00 1970 +0000
613 summary: b
613 summary: b
614
614
615 changeset: 0:29a4c94f1924
615 changeset: 0:29a4c94f1924
616 user: User One <user1@example.org>
616 user: User One <user1@example.org>
617 date: Thu Jan 01 00:00:00 1970 +0000
617 date: Thu Jan 01 00:00:00 1970 +0000
618 summary: a
618 summary: a
619
619
620 $ hg log -u "user3"
620 $ hg log -u "user3"
621
621
622 $ cd ..
622 $ cd ..
623
623
624 $ hg init branches
624 $ hg init branches
625 $ cd branches
625 $ cd branches
626
626
627 $ echo a > a
627 $ echo a > a
628 $ hg ci -A -m "commit on default"
628 $ hg ci -A -m "commit on default"
629 adding a
629 adding a
630 $ hg branch test
630 $ hg branch test
631 marked working directory as branch test
631 marked working directory as branch test
632 (branches are permanent and global, did you want a bookmark?)
632 (branches are permanent and global, did you want a bookmark?)
633 $ echo b > b
633 $ echo b > b
634 $ hg ci -A -m "commit on test"
634 $ hg ci -A -m "commit on test"
635 adding b
635 adding b
636
636
637 $ hg up default
637 $ hg up default
638 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
638 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
639 $ echo c > c
639 $ echo c > c
640 $ hg ci -A -m "commit on default"
640 $ hg ci -A -m "commit on default"
641 adding c
641 adding c
642 $ hg up test
642 $ hg up test
643 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
643 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
644 $ echo c > c
644 $ echo c > c
645 $ hg ci -A -m "commit on test"
645 $ hg ci -A -m "commit on test"
646 adding c
646 adding c
647
647
648
648
649 log -b default
649 log -b default
650
650
651 $ hg log -b default
651 $ hg log -b default
652 changeset: 2:c3a4f03cc9a7
652 changeset: 2:c3a4f03cc9a7
653 parent: 0:24427303d56f
653 parent: 0:24427303d56f
654 user: test
654 user: test
655 date: Thu Jan 01 00:00:00 1970 +0000
655 date: Thu Jan 01 00:00:00 1970 +0000
656 summary: commit on default
656 summary: commit on default
657
657
658 changeset: 0:24427303d56f
658 changeset: 0:24427303d56f
659 user: test
659 user: test
660 date: Thu Jan 01 00:00:00 1970 +0000
660 date: Thu Jan 01 00:00:00 1970 +0000
661 summary: commit on default
661 summary: commit on default
662
662
663
663
664
664
665 log -b test
665 log -b test
666
666
667 $ hg log -b test
667 $ hg log -b test
668 changeset: 3:f5d8de11c2e2
668 changeset: 3:f5d8de11c2e2
669 branch: test
669 branch: test
670 tag: tip
670 tag: tip
671 parent: 1:d32277701ccb
671 parent: 1:d32277701ccb
672 user: test
672 user: test
673 date: Thu Jan 01 00:00:00 1970 +0000
673 date: Thu Jan 01 00:00:00 1970 +0000
674 summary: commit on test
674 summary: commit on test
675
675
676 changeset: 1:d32277701ccb
676 changeset: 1:d32277701ccb
677 branch: test
677 branch: test
678 user: test
678 user: test
679 date: Thu Jan 01 00:00:00 1970 +0000
679 date: Thu Jan 01 00:00:00 1970 +0000
680 summary: commit on test
680 summary: commit on test
681
681
682
682
683
683
684 log -b dummy
684 log -b dummy
685
685
686 $ hg log -b dummy
686 $ hg log -b dummy
687 abort: unknown revision 'dummy'!
687 abort: unknown revision 'dummy'!
688 [255]
688 [255]
689
689
690
690
691 log -b .
691 log -b .
692
692
693 $ hg log -b .
693 $ hg log -b .
694 changeset: 3:f5d8de11c2e2
694 changeset: 3:f5d8de11c2e2
695 branch: test
695 branch: test
696 tag: tip
696 tag: tip
697 parent: 1:d32277701ccb
697 parent: 1:d32277701ccb
698 user: test
698 user: test
699 date: Thu Jan 01 00:00:00 1970 +0000
699 date: Thu Jan 01 00:00:00 1970 +0000
700 summary: commit on test
700 summary: commit on test
701
701
702 changeset: 1:d32277701ccb
702 changeset: 1:d32277701ccb
703 branch: test
703 branch: test
704 user: test
704 user: test
705 date: Thu Jan 01 00:00:00 1970 +0000
705 date: Thu Jan 01 00:00:00 1970 +0000
706 summary: commit on test
706 summary: commit on test
707
707
708
708
709
709
710 log -b default -b test
710 log -b default -b test
711
711
712 $ hg log -b default -b test
712 $ hg log -b default -b test
713 changeset: 3:f5d8de11c2e2
713 changeset: 3:f5d8de11c2e2
714 branch: test
714 branch: test
715 tag: tip
715 tag: tip
716 parent: 1:d32277701ccb
716 parent: 1:d32277701ccb
717 user: test
717 user: test
718 date: Thu Jan 01 00:00:00 1970 +0000
718 date: Thu Jan 01 00:00:00 1970 +0000
719 summary: commit on test
719 summary: commit on test
720
720
721 changeset: 2:c3a4f03cc9a7
721 changeset: 2:c3a4f03cc9a7
722 parent: 0:24427303d56f
722 parent: 0:24427303d56f
723 user: test
723 user: test
724 date: Thu Jan 01 00:00:00 1970 +0000
724 date: Thu Jan 01 00:00:00 1970 +0000
725 summary: commit on default
725 summary: commit on default
726
726
727 changeset: 1:d32277701ccb
727 changeset: 1:d32277701ccb
728 branch: test
728 branch: test
729 user: test
729 user: test
730 date: Thu Jan 01 00:00:00 1970 +0000
730 date: Thu Jan 01 00:00:00 1970 +0000
731 summary: commit on test
731 summary: commit on test
732
732
733 changeset: 0:24427303d56f
733 changeset: 0:24427303d56f
734 user: test
734 user: test
735 date: Thu Jan 01 00:00:00 1970 +0000
735 date: Thu Jan 01 00:00:00 1970 +0000
736 summary: commit on default
736 summary: commit on default
737
737
738
738
739
739
740 log -b default -b .
740 log -b default -b .
741
741
742 $ hg log -b default -b .
742 $ hg log -b default -b .
743 changeset: 3:f5d8de11c2e2
743 changeset: 3:f5d8de11c2e2
744 branch: test
744 branch: test
745 tag: tip
745 tag: tip
746 parent: 1:d32277701ccb
746 parent: 1:d32277701ccb
747 user: test
747 user: test
748 date: Thu Jan 01 00:00:00 1970 +0000
748 date: Thu Jan 01 00:00:00 1970 +0000
749 summary: commit on test
749 summary: commit on test
750
750
751 changeset: 2:c3a4f03cc9a7
751 changeset: 2:c3a4f03cc9a7
752 parent: 0:24427303d56f
752 parent: 0:24427303d56f
753 user: test
753 user: test
754 date: Thu Jan 01 00:00:00 1970 +0000
754 date: Thu Jan 01 00:00:00 1970 +0000
755 summary: commit on default
755 summary: commit on default
756
756
757 changeset: 1:d32277701ccb
757 changeset: 1:d32277701ccb
758 branch: test
758 branch: test
759 user: test
759 user: test
760 date: Thu Jan 01 00:00:00 1970 +0000
760 date: Thu Jan 01 00:00:00 1970 +0000
761 summary: commit on test
761 summary: commit on test
762
762
763 changeset: 0:24427303d56f
763 changeset: 0:24427303d56f
764 user: test
764 user: test
765 date: Thu Jan 01 00:00:00 1970 +0000
765 date: Thu Jan 01 00:00:00 1970 +0000
766 summary: commit on default
766 summary: commit on default
767
767
768
768
769
769
770 log -b . -b test
770 log -b . -b test
771
771
772 $ hg log -b . -b test
772 $ hg log -b . -b test
773 changeset: 3:f5d8de11c2e2
773 changeset: 3:f5d8de11c2e2
774 branch: test
774 branch: test
775 tag: tip
775 tag: tip
776 parent: 1:d32277701ccb
776 parent: 1:d32277701ccb
777 user: test
777 user: test
778 date: Thu Jan 01 00:00:00 1970 +0000
778 date: Thu Jan 01 00:00:00 1970 +0000
779 summary: commit on test
779 summary: commit on test
780
780
781 changeset: 1:d32277701ccb
781 changeset: 1:d32277701ccb
782 branch: test
782 branch: test
783 user: test
783 user: test
784 date: Thu Jan 01 00:00:00 1970 +0000
784 date: Thu Jan 01 00:00:00 1970 +0000
785 summary: commit on test
785 summary: commit on test
786
786
787
787
788
788
789 log -b 2
789 log -b 2
790
790
791 $ hg log -b 2
791 $ hg log -b 2
792 changeset: 2:c3a4f03cc9a7
792 changeset: 2:c3a4f03cc9a7
793 parent: 0:24427303d56f
793 parent: 0:24427303d56f
794 user: test
794 user: test
795 date: Thu Jan 01 00:00:00 1970 +0000
795 date: Thu Jan 01 00:00:00 1970 +0000
796 summary: commit on default
796 summary: commit on default
797
797
798 changeset: 0:24427303d56f
798 changeset: 0:24427303d56f
799 user: test
799 user: test
800 date: Thu Jan 01 00:00:00 1970 +0000
800 date: Thu Jan 01 00:00:00 1970 +0000
801 summary: commit on default
801 summary: commit on default
802
802
803
803
804
804
805 log -p --cwd dir (in subdir)
805 log -p --cwd dir (in subdir)
806
806
807 $ mkdir dir
807 $ mkdir dir
808 $ hg log -p --cwd dir
808 $ hg log -p --cwd dir
809 changeset: 3:f5d8de11c2e2
809 changeset: 3:f5d8de11c2e2
810 branch: test
810 branch: test
811 tag: tip
811 tag: tip
812 parent: 1:d32277701ccb
812 parent: 1:d32277701ccb
813 user: test
813 user: test
814 date: Thu Jan 01 00:00:00 1970 +0000
814 date: Thu Jan 01 00:00:00 1970 +0000
815 summary: commit on test
815 summary: commit on test
816
816
817 diff -r d32277701ccb -r f5d8de11c2e2 c
817 diff -r d32277701ccb -r f5d8de11c2e2 c
818 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
818 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
819 +++ b/c Thu Jan 01 00:00:00 1970 +0000
819 +++ b/c Thu Jan 01 00:00:00 1970 +0000
820 @@ -0,0 +1,1 @@
820 @@ -0,0 +1,1 @@
821 +c
821 +c
822
822
823 changeset: 2:c3a4f03cc9a7
823 changeset: 2:c3a4f03cc9a7
824 parent: 0:24427303d56f
824 parent: 0:24427303d56f
825 user: test
825 user: test
826 date: Thu Jan 01 00:00:00 1970 +0000
826 date: Thu Jan 01 00:00:00 1970 +0000
827 summary: commit on default
827 summary: commit on default
828
828
829 diff -r 24427303d56f -r c3a4f03cc9a7 c
829 diff -r 24427303d56f -r c3a4f03cc9a7 c
830 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
830 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
831 +++ b/c Thu Jan 01 00:00:00 1970 +0000
831 +++ b/c Thu Jan 01 00:00:00 1970 +0000
832 @@ -0,0 +1,1 @@
832 @@ -0,0 +1,1 @@
833 +c
833 +c
834
834
835 changeset: 1:d32277701ccb
835 changeset: 1:d32277701ccb
836 branch: test
836 branch: test
837 user: test
837 user: test
838 date: Thu Jan 01 00:00:00 1970 +0000
838 date: Thu Jan 01 00:00:00 1970 +0000
839 summary: commit on test
839 summary: commit on test
840
840
841 diff -r 24427303d56f -r d32277701ccb b
841 diff -r 24427303d56f -r d32277701ccb b
842 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
842 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
843 +++ b/b Thu Jan 01 00:00:00 1970 +0000
843 +++ b/b Thu Jan 01 00:00:00 1970 +0000
844 @@ -0,0 +1,1 @@
844 @@ -0,0 +1,1 @@
845 +b
845 +b
846
846
847 changeset: 0:24427303d56f
847 changeset: 0:24427303d56f
848 user: test
848 user: test
849 date: Thu Jan 01 00:00:00 1970 +0000
849 date: Thu Jan 01 00:00:00 1970 +0000
850 summary: commit on default
850 summary: commit on default
851
851
852 diff -r 000000000000 -r 24427303d56f a
852 diff -r 000000000000 -r 24427303d56f a
853 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
853 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
854 +++ b/a Thu Jan 01 00:00:00 1970 +0000
854 +++ b/a Thu Jan 01 00:00:00 1970 +0000
855 @@ -0,0 +1,1 @@
855 @@ -0,0 +1,1 @@
856 +a
856 +a
857
857
858
858
859
859
860 log -p -R repo
860 log -p -R repo
861
861
862 $ cd dir
862 $ cd dir
863 $ hg log -p -R .. ../a
863 $ hg log -p -R .. ../a
864 changeset: 0:24427303d56f
864 changeset: 0:24427303d56f
865 user: test
865 user: test
866 date: Thu Jan 01 00:00:00 1970 +0000
866 date: Thu Jan 01 00:00:00 1970 +0000
867 summary: commit on default
867 summary: commit on default
868
868
869 diff -r 000000000000 -r 24427303d56f a
869 diff -r 000000000000 -r 24427303d56f a
870 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
870 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
871 +++ b/a Thu Jan 01 00:00:00 1970 +0000
871 +++ b/a Thu Jan 01 00:00:00 1970 +0000
872 @@ -0,0 +1,1 @@
872 @@ -0,0 +1,1 @@
873 +a
873 +a
874
874
875
875
876 $ cd ../..
876 $ cd ../..
877
877
878 $ hg init follow2
878 $ hg init follow2
879 $ cd follow2
879 $ cd follow2
880
880
881 # Build the following history:
881 # Build the following history:
882 # tip - o - x - o - x - x
882 # tip - o - x - o - x - x
883 # \ /
883 # \ /
884 # o - o - o - x
884 # o - o - o - x
885 # \ /
885 # \ /
886 # o
886 # o
887 #
887 #
888 # Where "o" is a revision containing "foo" and
888 # Where "o" is a revision containing "foo" and
889 # "x" is a revision without "foo"
889 # "x" is a revision without "foo"
890
890
891 $ touch init
891 $ touch init
892 $ hg ci -A -m "init, unrelated"
892 $ hg ci -A -m "init, unrelated"
893 adding init
893 adding init
894 $ echo 'foo' > init
894 $ echo 'foo' > init
895 $ hg ci -m "change, unrelated"
895 $ hg ci -m "change, unrelated"
896 $ echo 'foo' > foo
896 $ echo 'foo' > foo
897 $ hg ci -A -m "add unrelated old foo"
897 $ hg ci -A -m "add unrelated old foo"
898 adding foo
898 adding foo
899 $ hg rm foo
899 $ hg rm foo
900 $ hg ci -m "delete foo, unrelated"
900 $ hg ci -m "delete foo, unrelated"
901 $ echo 'related' > foo
901 $ echo 'related' > foo
902 $ hg ci -A -m "add foo, related"
902 $ hg ci -A -m "add foo, related"
903 adding foo
903 adding foo
904
904
905 $ hg up 0
905 $ hg up 0
906 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
906 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
907 $ touch branch
907 $ touch branch
908 $ hg ci -A -m "first branch, unrelated"
908 $ hg ci -A -m "first branch, unrelated"
909 adding branch
909 adding branch
910 created new head
910 created new head
911 $ touch foo
911 $ touch foo
912 $ hg ci -A -m "create foo, related"
912 $ hg ci -A -m "create foo, related"
913 adding foo
913 adding foo
914 $ echo 'change' > foo
914 $ echo 'change' > foo
915 $ hg ci -m "change foo, related"
915 $ hg ci -m "change foo, related"
916
916
917 $ hg up 6
917 $ hg up 6
918 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
918 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
919 $ echo 'change foo in branch' > foo
919 $ echo 'change foo in branch' > foo
920 $ hg ci -m "change foo in branch, related"
920 $ hg ci -m "change foo in branch, related"
921 created new head
921 created new head
922 $ hg merge 7
922 $ hg merge 7
923 merging foo
923 merging foo
924 warning: conflicts during merge.
924 warning: conflicts during merge.
925 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
925 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
926 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
926 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
927 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
927 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
928 [1]
928 [1]
929 $ echo 'merge 1' > foo
929 $ echo 'merge 1' > foo
930 $ hg resolve -m foo
930 $ hg resolve -m foo
931 $ hg ci -m "First merge, related"
931 $ hg ci -m "First merge, related"
932
932
933 $ hg merge 4
933 $ hg merge 4
934 merging foo
934 merging foo
935 warning: conflicts during merge.
935 warning: conflicts during merge.
936 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
936 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
937 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
937 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
938 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
938 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
939 [1]
939 [1]
940 $ echo 'merge 2' > foo
940 $ echo 'merge 2' > foo
941 $ hg resolve -m foo
941 $ hg resolve -m foo
942 $ hg ci -m "Last merge, related"
942 $ hg ci -m "Last merge, related"
943
943
944 $ hg log --graph
944 $ hg log --graph
945 @ changeset: 10:4dae8563d2c5
945 @ changeset: 10:4dae8563d2c5
946 |\ tag: tip
946 |\ tag: tip
947 | | parent: 9:7b35701b003e
947 | | parent: 9:7b35701b003e
948 | | parent: 4:88176d361b69
948 | | parent: 4:88176d361b69
949 | | user: test
949 | | user: test
950 | | date: Thu Jan 01 00:00:00 1970 +0000
950 | | date: Thu Jan 01 00:00:00 1970 +0000
951 | | summary: Last merge, related
951 | | summary: Last merge, related
952 | |
952 | |
953 | o changeset: 9:7b35701b003e
953 | o changeset: 9:7b35701b003e
954 | |\ parent: 8:e5416ad8a855
954 | |\ parent: 8:e5416ad8a855
955 | | | parent: 7:87fe3144dcfa
955 | | | parent: 7:87fe3144dcfa
956 | | | user: test
956 | | | user: test
957 | | | date: Thu Jan 01 00:00:00 1970 +0000
957 | | | date: Thu Jan 01 00:00:00 1970 +0000
958 | | | summary: First merge, related
958 | | | summary: First merge, related
959 | | |
959 | | |
960 | | o changeset: 8:e5416ad8a855
960 | | o changeset: 8:e5416ad8a855
961 | | | parent: 6:dc6c325fe5ee
961 | | | parent: 6:dc6c325fe5ee
962 | | | user: test
962 | | | user: test
963 | | | date: Thu Jan 01 00:00:00 1970 +0000
963 | | | date: Thu Jan 01 00:00:00 1970 +0000
964 | | | summary: change foo in branch, related
964 | | | summary: change foo in branch, related
965 | | |
965 | | |
966 | o | changeset: 7:87fe3144dcfa
966 | o | changeset: 7:87fe3144dcfa
967 | |/ user: test
967 | |/ user: test
968 | | date: Thu Jan 01 00:00:00 1970 +0000
968 | | date: Thu Jan 01 00:00:00 1970 +0000
969 | | summary: change foo, related
969 | | summary: change foo, related
970 | |
970 | |
971 | o changeset: 6:dc6c325fe5ee
971 | o changeset: 6:dc6c325fe5ee
972 | | user: test
972 | | user: test
973 | | date: Thu Jan 01 00:00:00 1970 +0000
973 | | date: Thu Jan 01 00:00:00 1970 +0000
974 | | summary: create foo, related
974 | | summary: create foo, related
975 | |
975 | |
976 | o changeset: 5:73db34516eb9
976 | o changeset: 5:73db34516eb9
977 | | parent: 0:e87515fd044a
977 | | parent: 0:e87515fd044a
978 | | user: test
978 | | user: test
979 | | date: Thu Jan 01 00:00:00 1970 +0000
979 | | date: Thu Jan 01 00:00:00 1970 +0000
980 | | summary: first branch, unrelated
980 | | summary: first branch, unrelated
981 | |
981 | |
982 o | changeset: 4:88176d361b69
982 o | changeset: 4:88176d361b69
983 | | user: test
983 | | user: test
984 | | date: Thu Jan 01 00:00:00 1970 +0000
984 | | date: Thu Jan 01 00:00:00 1970 +0000
985 | | summary: add foo, related
985 | | summary: add foo, related
986 | |
986 | |
987 o | changeset: 3:dd78ae4afb56
987 o | changeset: 3:dd78ae4afb56
988 | | user: test
988 | | user: test
989 | | date: Thu Jan 01 00:00:00 1970 +0000
989 | | date: Thu Jan 01 00:00:00 1970 +0000
990 | | summary: delete foo, unrelated
990 | | summary: delete foo, unrelated
991 | |
991 | |
992 o | changeset: 2:c4c64aedf0f7
992 o | changeset: 2:c4c64aedf0f7
993 | | user: test
993 | | user: test
994 | | date: Thu Jan 01 00:00:00 1970 +0000
994 | | date: Thu Jan 01 00:00:00 1970 +0000
995 | | summary: add unrelated old foo
995 | | summary: add unrelated old foo
996 | |
996 | |
997 o | changeset: 1:e5faa7440653
997 o | changeset: 1:e5faa7440653
998 |/ user: test
998 |/ user: test
999 | date: Thu Jan 01 00:00:00 1970 +0000
999 | date: Thu Jan 01 00:00:00 1970 +0000
1000 | summary: change, unrelated
1000 | summary: change, unrelated
1001 |
1001 |
1002 o changeset: 0:e87515fd044a
1002 o changeset: 0:e87515fd044a
1003 user: test
1003 user: test
1004 date: Thu Jan 01 00:00:00 1970 +0000
1004 date: Thu Jan 01 00:00:00 1970 +0000
1005 summary: init, unrelated
1005 summary: init, unrelated
1006
1006
1007
1007
1008 $ hg --traceback log -f foo
1008 $ hg --traceback log -f foo
1009 changeset: 10:4dae8563d2c5
1009 changeset: 10:4dae8563d2c5
1010 tag: tip
1010 tag: tip
1011 parent: 9:7b35701b003e
1011 parent: 9:7b35701b003e
1012 parent: 4:88176d361b69
1012 parent: 4:88176d361b69
1013 user: test
1013 user: test
1014 date: Thu Jan 01 00:00:00 1970 +0000
1014 date: Thu Jan 01 00:00:00 1970 +0000
1015 summary: Last merge, related
1015 summary: Last merge, related
1016
1016
1017 changeset: 9:7b35701b003e
1017 changeset: 9:7b35701b003e
1018 parent: 8:e5416ad8a855
1018 parent: 8:e5416ad8a855
1019 parent: 7:87fe3144dcfa
1019 parent: 7:87fe3144dcfa
1020 user: test
1020 user: test
1021 date: Thu Jan 01 00:00:00 1970 +0000
1021 date: Thu Jan 01 00:00:00 1970 +0000
1022 summary: First merge, related
1022 summary: First merge, related
1023
1023
1024 changeset: 8:e5416ad8a855
1024 changeset: 8:e5416ad8a855
1025 parent: 6:dc6c325fe5ee
1025 parent: 6:dc6c325fe5ee
1026 user: test
1026 user: test
1027 date: Thu Jan 01 00:00:00 1970 +0000
1027 date: Thu Jan 01 00:00:00 1970 +0000
1028 summary: change foo in branch, related
1028 summary: change foo in branch, related
1029
1029
1030 changeset: 7:87fe3144dcfa
1030 changeset: 7:87fe3144dcfa
1031 user: test
1031 user: test
1032 date: Thu Jan 01 00:00:00 1970 +0000
1032 date: Thu Jan 01 00:00:00 1970 +0000
1033 summary: change foo, related
1033 summary: change foo, related
1034
1034
1035 changeset: 6:dc6c325fe5ee
1035 changeset: 6:dc6c325fe5ee
1036 user: test
1036 user: test
1037 date: Thu Jan 01 00:00:00 1970 +0000
1037 date: Thu Jan 01 00:00:00 1970 +0000
1038 summary: create foo, related
1038 summary: create foo, related
1039
1039
1040 changeset: 4:88176d361b69
1040 changeset: 4:88176d361b69
1041 user: test
1041 user: test
1042 date: Thu Jan 01 00:00:00 1970 +0000
1042 date: Thu Jan 01 00:00:00 1970 +0000
1043 summary: add foo, related
1043 summary: add foo, related
1044
1044
1045
1045
1046 Also check when maxrev < lastrevfilelog
1046 Also check when maxrev < lastrevfilelog
1047
1047
1048 $ hg --traceback log -f -r4 foo
1048 $ hg --traceback log -f -r4 foo
1049 changeset: 4:88176d361b69
1049 changeset: 4:88176d361b69
1050 user: test
1050 user: test
1051 date: Thu Jan 01 00:00:00 1970 +0000
1051 date: Thu Jan 01 00:00:00 1970 +0000
1052 summary: add foo, related
1052 summary: add foo, related
1053
1053
1054 $ cd ..
1054 $ cd ..
1055
1055
1056 Issue2383: hg log showing _less_ differences than hg diff
1056 Issue2383: hg log showing _less_ differences than hg diff
1057
1057
1058 $ hg init issue2383
1058 $ hg init issue2383
1059 $ cd issue2383
1059 $ cd issue2383
1060
1060
1061 Create a test repo:
1061 Create a test repo:
1062
1062
1063 $ echo a > a
1063 $ echo a > a
1064 $ hg ci -Am0
1064 $ hg ci -Am0
1065 adding a
1065 adding a
1066 $ echo b > b
1066 $ echo b > b
1067 $ hg ci -Am1
1067 $ hg ci -Am1
1068 adding b
1068 adding b
1069 $ hg co 0
1069 $ hg co 0
1070 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1070 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1071 $ echo b > a
1071 $ echo b > a
1072 $ hg ci -m2
1072 $ hg ci -m2
1073 created new head
1073 created new head
1074
1074
1075 Merge:
1075 Merge:
1076
1076
1077 $ hg merge
1077 $ hg merge
1078 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1078 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1079 (branch merge, don't forget to commit)
1079 (branch merge, don't forget to commit)
1080
1080
1081 Make sure there's a file listed in the merge to trigger the bug:
1081 Make sure there's a file listed in the merge to trigger the bug:
1082
1082
1083 $ echo c > a
1083 $ echo c > a
1084 $ hg ci -m3
1084 $ hg ci -m3
1085
1085
1086 Two files shown here in diff:
1086 Two files shown here in diff:
1087
1087
1088 $ hg diff --rev 2:3
1088 $ hg diff --rev 2:3
1089 diff -r b09be438c43a -r 8e07aafe1edc a
1089 diff -r b09be438c43a -r 8e07aafe1edc a
1090 --- a/a Thu Jan 01 00:00:00 1970 +0000
1090 --- a/a Thu Jan 01 00:00:00 1970 +0000
1091 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1091 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1092 @@ -1,1 +1,1 @@
1092 @@ -1,1 +1,1 @@
1093 -b
1093 -b
1094 +c
1094 +c
1095 diff -r b09be438c43a -r 8e07aafe1edc b
1095 diff -r b09be438c43a -r 8e07aafe1edc b
1096 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1096 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1097 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1097 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1098 @@ -0,0 +1,1 @@
1098 @@ -0,0 +1,1 @@
1099 +b
1099 +b
1100
1100
1101 Diff here should be the same:
1101 Diff here should be the same:
1102
1102
1103 $ hg log -vpr 3
1103 $ hg log -vpr 3
1104 changeset: 3:8e07aafe1edc
1104 changeset: 3:8e07aafe1edc
1105 tag: tip
1105 tag: tip
1106 parent: 2:b09be438c43a
1106 parent: 2:b09be438c43a
1107 parent: 1:925d80f479bb
1107 parent: 1:925d80f479bb
1108 user: test
1108 user: test
1109 date: Thu Jan 01 00:00:00 1970 +0000
1109 date: Thu Jan 01 00:00:00 1970 +0000
1110 files: a
1110 files: a
1111 description:
1111 description:
1112 3
1112 3
1113
1113
1114
1114
1115 diff -r b09be438c43a -r 8e07aafe1edc a
1115 diff -r b09be438c43a -r 8e07aafe1edc a
1116 --- a/a Thu Jan 01 00:00:00 1970 +0000
1116 --- a/a Thu Jan 01 00:00:00 1970 +0000
1117 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1117 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1118 @@ -1,1 +1,1 @@
1118 @@ -1,1 +1,1 @@
1119 -b
1119 -b
1120 +c
1120 +c
1121 diff -r b09be438c43a -r 8e07aafe1edc b
1121 diff -r b09be438c43a -r 8e07aafe1edc b
1122 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1122 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1123 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1123 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1124 @@ -0,0 +1,1 @@
1124 @@ -0,0 +1,1 @@
1125 +b
1125 +b
1126
1126
1127 $ cd ..
1127 $ cd ..
1128
1128
1129 'hg log -r rev fn' when last(filelog(fn)) != rev
1129 'hg log -r rev fn' when last(filelog(fn)) != rev
1130
1130
1131 $ hg init simplelog
1131 $ hg init simplelog
1132 $ cd simplelog
1132 $ cd simplelog
1133 $ echo f > a
1133 $ echo f > a
1134 $ hg ci -Am'a' -d '0 0'
1134 $ hg ci -Am'a' -d '0 0'
1135 adding a
1135 adding a
1136 $ echo f >> a
1136 $ echo f >> a
1137 $ hg ci -Am'a bis' -d '1 0'
1137 $ hg ci -Am'a bis' -d '1 0'
1138
1138
1139 $ hg log -r0 a
1139 $ hg log -r0 a
1140 changeset: 0:9f758d63dcde
1140 changeset: 0:9f758d63dcde
1141 user: test
1141 user: test
1142 date: Thu Jan 01 00:00:00 1970 +0000
1142 date: Thu Jan 01 00:00:00 1970 +0000
1143 summary: a
1143 summary: a
1144
1144
1145 enable obsolete to test hidden feature
1145 enable obsolete to test hidden feature
1146
1146
1147 $ cat > ${TESTTMP}/obs.py << EOF
1147 $ cat > ${TESTTMP}/obs.py << EOF
1148 > import mercurial.obsolete
1148 > import mercurial.obsolete
1149 > mercurial.obsolete._enabled = True
1149 > mercurial.obsolete._enabled = True
1150 > EOF
1150 > EOF
1151 $ echo '[extensions]' >> $HGRCPATH
1151 $ echo '[extensions]' >> $HGRCPATH
1152 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
1152 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
1153
1153
1154 $ hg log --template='{rev}:{node}\n'
1154 $ hg log --template='{rev}:{node}\n'
1155 1:a765632148dc55d38c35c4f247c618701886cb2f
1155 1:a765632148dc55d38c35c4f247c618701886cb2f
1156 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1156 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1157 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1157 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1158 $ hg up null -q
1158 $ hg up null -q
1159 $ hg log --template='{rev}:{node}\n'
1159 $ hg log --template='{rev}:{node}\n'
1160 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1160 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1161 $ hg log --template='{rev}:{node}\n' --hidden
1161 $ hg log --template='{rev}:{node}\n' --hidden
1162 1:a765632148dc55d38c35c4f247c618701886cb2f
1162 1:a765632148dc55d38c35c4f247c618701886cb2f
1163 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1163 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1164
1164
1165 test that parent prevent a changeset to be hidden
1165 test that parent prevent a changeset to be hidden
1166
1166
1167 $ hg up 1 -q
1167 $ hg up 1 -q --hidden
1168 $ hg log --template='{rev}:{node}\n'
1168 $ hg log --template='{rev}:{node}\n'
1169 1:a765632148dc55d38c35c4f247c618701886cb2f
1169 1:a765632148dc55d38c35c4f247c618701886cb2f
1170 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1170 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1171
1171
1172 test that second parent prevent a changeset to be hidden too
1172 test that second parent prevent a changeset to be hidden too
1173
1173
1174 $ hg debugsetparents 0 1 # nothing suitable to merge here
1174 $ hg debugsetparents 0 1 # nothing suitable to merge here
1175 $ hg log --template='{rev}:{node}\n'
1175 $ hg log --template='{rev}:{node}\n'
1176 1:a765632148dc55d38c35c4f247c618701886cb2f
1176 1:a765632148dc55d38c35c4f247c618701886cb2f
1177 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1177 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1178
1178
1179 clear extensions configuration
1179 clear extensions configuration
1180 $ echo '[extensions]' >> $HGRCPATH
1180 $ echo '[extensions]' >> $HGRCPATH
1181 $ echo "obs=!" >> $HGRCPATH
1181 $ echo "obs=!" >> $HGRCPATH
1182 $ cd ..
1182 $ cd ..
1183
1183
1184 test -u/-k for problematic encoding
1184 test -u/-k for problematic encoding
1185 # unicode: cp932:
1185 # unicode: cp932:
1186 # u30A2 0x83 0x41(= 'A')
1186 # u30A2 0x83 0x41(= 'A')
1187 # u30C2 0x83 0x61(= 'a')
1187 # u30C2 0x83 0x61(= 'a')
1188
1188
1189 $ hg init problematicencoding
1189 $ hg init problematicencoding
1190 $ cd problematicencoding
1190 $ cd problematicencoding
1191
1191
1192 $ python > setup.sh <<EOF
1192 $ python > setup.sh <<EOF
1193 > print u'''
1193 > print u'''
1194 > echo a > text
1194 > echo a > text
1195 > hg add text
1195 > hg add text
1196 > hg --encoding utf-8 commit -u '\u30A2' -m none
1196 > hg --encoding utf-8 commit -u '\u30A2' -m none
1197 > echo b > text
1197 > echo b > text
1198 > hg --encoding utf-8 commit -u '\u30C2' -m none
1198 > hg --encoding utf-8 commit -u '\u30C2' -m none
1199 > echo c > text
1199 > echo c > text
1200 > hg --encoding utf-8 commit -u none -m '\u30A2'
1200 > hg --encoding utf-8 commit -u none -m '\u30A2'
1201 > echo d > text
1201 > echo d > text
1202 > hg --encoding utf-8 commit -u none -m '\u30C2'
1202 > hg --encoding utf-8 commit -u none -m '\u30C2'
1203 > '''.encode('utf-8')
1203 > '''.encode('utf-8')
1204 > EOF
1204 > EOF
1205 $ sh < setup.sh
1205 $ sh < setup.sh
1206
1206
1207 test in problematic encoding
1207 test in problematic encoding
1208 $ python > test.sh <<EOF
1208 $ python > test.sh <<EOF
1209 > print u'''
1209 > print u'''
1210 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1210 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1211 > echo ====
1211 > echo ====
1212 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1212 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1213 > echo ====
1213 > echo ====
1214 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1214 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1215 > echo ====
1215 > echo ====
1216 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1216 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1217 > '''.encode('cp932')
1217 > '''.encode('cp932')
1218 > EOF
1218 > EOF
1219 $ sh < test.sh
1219 $ sh < test.sh
1220 0
1220 0
1221 ====
1221 ====
1222 1
1222 1
1223 ====
1223 ====
1224 2
1224 2
1225 0
1225 0
1226 ====
1226 ====
1227 3
1227 3
1228 1
1228 1
1229
1229
1230 $ cd ..
1230 $ cd ..
1231
1231
1232 test hg log on non-existent files and on directories
1232 test hg log on non-existent files and on directories
1233 $ hg init issue1340
1233 $ hg init issue1340
1234 $ cd issue1340
1234 $ cd issue1340
1235 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1235 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1236 $ echo 1 > d1/f1
1236 $ echo 1 > d1/f1
1237 $ echo 1 > D2/f1
1237 $ echo 1 > D2/f1
1238 $ echo 1 > D3.i/f1
1238 $ echo 1 > D3.i/f1
1239 $ echo 1 > d4.hg/f1
1239 $ echo 1 > d4.hg/f1
1240 $ echo 1 > d5.d/f1
1240 $ echo 1 > d5.d/f1
1241 $ echo 1 > .d6/f1
1241 $ echo 1 > .d6/f1
1242 $ hg -q add .
1242 $ hg -q add .
1243 $ hg commit -m "a bunch of weird directories"
1243 $ hg commit -m "a bunch of weird directories"
1244 $ hg log -l1 d1/f1 | grep changeset
1244 $ hg log -l1 d1/f1 | grep changeset
1245 changeset: 0:65624cd9070a
1245 changeset: 0:65624cd9070a
1246 $ hg log -l1 f1
1246 $ hg log -l1 f1
1247 $ hg log -l1 . | grep changeset
1247 $ hg log -l1 . | grep changeset
1248 changeset: 0:65624cd9070a
1248 changeset: 0:65624cd9070a
1249 $ hg log -l1 ./ | grep changeset
1249 $ hg log -l1 ./ | grep changeset
1250 changeset: 0:65624cd9070a
1250 changeset: 0:65624cd9070a
1251 $ hg log -l1 d1 | grep changeset
1251 $ hg log -l1 d1 | grep changeset
1252 changeset: 0:65624cd9070a
1252 changeset: 0:65624cd9070a
1253 $ hg log -l1 D2 | grep changeset
1253 $ hg log -l1 D2 | grep changeset
1254 changeset: 0:65624cd9070a
1254 changeset: 0:65624cd9070a
1255 $ hg log -l1 D2/f1 | grep changeset
1255 $ hg log -l1 D2/f1 | grep changeset
1256 changeset: 0:65624cd9070a
1256 changeset: 0:65624cd9070a
1257 $ hg log -l1 D3.i | grep changeset
1257 $ hg log -l1 D3.i | grep changeset
1258 changeset: 0:65624cd9070a
1258 changeset: 0:65624cd9070a
1259 $ hg log -l1 D3.i/f1 | grep changeset
1259 $ hg log -l1 D3.i/f1 | grep changeset
1260 changeset: 0:65624cd9070a
1260 changeset: 0:65624cd9070a
1261 $ hg log -l1 d4.hg | grep changeset
1261 $ hg log -l1 d4.hg | grep changeset
1262 changeset: 0:65624cd9070a
1262 changeset: 0:65624cd9070a
1263 $ hg log -l1 d4.hg/f1 | grep changeset
1263 $ hg log -l1 d4.hg/f1 | grep changeset
1264 changeset: 0:65624cd9070a
1264 changeset: 0:65624cd9070a
1265 $ hg log -l1 d5.d | grep changeset
1265 $ hg log -l1 d5.d | grep changeset
1266 changeset: 0:65624cd9070a
1266 changeset: 0:65624cd9070a
1267 $ hg log -l1 d5.d/f1 | grep changeset
1267 $ hg log -l1 d5.d/f1 | grep changeset
1268 changeset: 0:65624cd9070a
1268 changeset: 0:65624cd9070a
1269 $ hg log -l1 .d6 | grep changeset
1269 $ hg log -l1 .d6 | grep changeset
1270 changeset: 0:65624cd9070a
1270 changeset: 0:65624cd9070a
1271 $ hg log -l1 .d6/f1 | grep changeset
1271 $ hg log -l1 .d6/f1 | grep changeset
1272 changeset: 0:65624cd9070a
1272 changeset: 0:65624cd9070a
1273 $ cd ..
1273 $ cd ..
@@ -1,345 +1,344 b''
1 $ branchcache=.hg/cache/branchheads
1 $ branchcache=.hg/cache/branchheads
2
2
3 $ listbranchcaches() {
3 $ listbranchcaches() {
4 > for f in .hg/cache/branchheads*;
4 > for f in .hg/cache/branchheads*;
5 > do echo === $f ===;
5 > do echo === $f ===;
6 > cat $f;
6 > cat $f;
7 > done;
7 > done;
8 > }
8 > }
9 $ purgebranchcaches() {
9 $ purgebranchcaches() {
10 > rm .hg/cache/branchheads*
10 > rm .hg/cache/branchheads*
11 > }
11 > }
12
12
13 $ hg init t
13 $ hg init t
14 $ cd t
14 $ cd t
15
15
16 $ hg branches
16 $ hg branches
17 $ echo foo > a
17 $ echo foo > a
18 $ hg add a
18 $ hg add a
19 $ hg ci -m "initial"
19 $ hg ci -m "initial"
20 $ hg branch foo
20 $ hg branch foo
21 marked working directory as branch foo
21 marked working directory as branch foo
22 (branches are permanent and global, did you want a bookmark?)
22 (branches are permanent and global, did you want a bookmark?)
23 $ hg branch
23 $ hg branch
24 foo
24 foo
25 $ hg ci -m "add branch name"
25 $ hg ci -m "add branch name"
26 $ hg branch bar
26 $ hg branch bar
27 marked working directory as branch bar
27 marked working directory as branch bar
28 (branches are permanent and global, did you want a bookmark?)
28 (branches are permanent and global, did you want a bookmark?)
29 $ hg ci -m "change branch name"
29 $ hg ci -m "change branch name"
30
30
31 Branch shadowing:
31 Branch shadowing:
32
32
33 $ hg branch default
33 $ hg branch default
34 abort: a branch of the same name already exists
34 abort: a branch of the same name already exists
35 (use 'hg update' to switch to it)
35 (use 'hg update' to switch to it)
36 [255]
36 [255]
37
37
38 $ hg branch -f default
38 $ hg branch -f default
39 marked working directory as branch default
39 marked working directory as branch default
40 (branches are permanent and global, did you want a bookmark?)
40 (branches are permanent and global, did you want a bookmark?)
41
41
42 $ hg ci -m "clear branch name"
42 $ hg ci -m "clear branch name"
43 created new head
43 created new head
44
44
45 There should be only one default branch head
45 There should be only one default branch head
46
46
47 $ hg heads .
47 $ hg heads .
48 changeset: 3:1c28f494dae6
48 changeset: 3:1c28f494dae6
49 tag: tip
49 tag: tip
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52 summary: clear branch name
52 summary: clear branch name
53
53
54
54
55 $ hg co foo
55 $ hg co foo
56 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 $ hg branch
57 $ hg branch
58 foo
58 foo
59 $ echo bleah > a
59 $ echo bleah > a
60 $ hg ci -m "modify a branch"
60 $ hg ci -m "modify a branch"
61
61
62 $ hg merge default
62 $ hg merge default
63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 (branch merge, don't forget to commit)
64 (branch merge, don't forget to commit)
65
65
66 $ hg branch
66 $ hg branch
67 foo
67 foo
68 $ hg ci -m "merge"
68 $ hg ci -m "merge"
69
69
70 $ hg log
70 $ hg log
71 changeset: 5:530046499edf
71 changeset: 5:530046499edf
72 branch: foo
72 branch: foo
73 tag: tip
73 tag: tip
74 parent: 4:adf1a74a7f7b
74 parent: 4:adf1a74a7f7b
75 parent: 3:1c28f494dae6
75 parent: 3:1c28f494dae6
76 user: test
76 user: test
77 date: Thu Jan 01 00:00:00 1970 +0000
77 date: Thu Jan 01 00:00:00 1970 +0000
78 summary: merge
78 summary: merge
79
79
80 changeset: 4:adf1a74a7f7b
80 changeset: 4:adf1a74a7f7b
81 branch: foo
81 branch: foo
82 parent: 1:6c0e42da283a
82 parent: 1:6c0e42da283a
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85 summary: modify a branch
85 summary: modify a branch
86
86
87 changeset: 3:1c28f494dae6
87 changeset: 3:1c28f494dae6
88 user: test
88 user: test
89 date: Thu Jan 01 00:00:00 1970 +0000
89 date: Thu Jan 01 00:00:00 1970 +0000
90 summary: clear branch name
90 summary: clear branch name
91
91
92 changeset: 2:c21617b13b22
92 changeset: 2:c21617b13b22
93 branch: bar
93 branch: bar
94 user: test
94 user: test
95 date: Thu Jan 01 00:00:00 1970 +0000
95 date: Thu Jan 01 00:00:00 1970 +0000
96 summary: change branch name
96 summary: change branch name
97
97
98 changeset: 1:6c0e42da283a
98 changeset: 1:6c0e42da283a
99 branch: foo
99 branch: foo
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:00 1970 +0000
101 date: Thu Jan 01 00:00:00 1970 +0000
102 summary: add branch name
102 summary: add branch name
103
103
104 changeset: 0:db01e8ea3388
104 changeset: 0:db01e8ea3388
105 user: test
105 user: test
106 date: Thu Jan 01 00:00:00 1970 +0000
106 date: Thu Jan 01 00:00:00 1970 +0000
107 summary: initial
107 summary: initial
108
108
109 $ hg branches
109 $ hg branches
110 foo 5:530046499edf
110 foo 5:530046499edf
111 default 3:1c28f494dae6 (inactive)
111 default 3:1c28f494dae6 (inactive)
112 bar 2:c21617b13b22 (inactive)
112 bar 2:c21617b13b22 (inactive)
113
113
114 $ hg branches -q
114 $ hg branches -q
115 foo
115 foo
116 default
116 default
117 bar
117 bar
118
118
119 Test for invalid branch cache:
119 Test for invalid branch cache:
120
120
121 $ hg rollback
121 $ hg rollback
122 repository tip rolled back to revision 4 (undo commit)
122 repository tip rolled back to revision 4 (undo commit)
123 working directory now based on revisions 4 and 3
123 working directory now based on revisions 4 and 3
124
124
125 $ cp ${branchcache}-unserved .hg/bc-invalid
125 $ cp ${branchcache}-unserved .hg/bc-invalid
126
126
127 $ hg log -r foo
127 $ hg log -r foo
128 changeset: 4:adf1a74a7f7b
128 changeset: 4:adf1a74a7f7b
129 branch: foo
129 branch: foo
130 tag: tip
130 tag: tip
131 parent: 1:6c0e42da283a
131 parent: 1:6c0e42da283a
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:00 1970 +0000
133 date: Thu Jan 01 00:00:00 1970 +0000
134 summary: modify a branch
134 summary: modify a branch
135
135
136 $ cp .hg/bc-invalid $branchcache
136 $ cp .hg/bc-invalid $branchcache
137
137
138 $ hg --debug log -r foo
138 $ hg --debug log -r foo
139 invalid branchheads cache: tip differs
140 changeset: 4:adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6
139 changeset: 4:adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6
141 branch: foo
140 branch: foo
142 tag: tip
141 tag: tip
143 phase: draft
142 phase: draft
144 parent: 1:6c0e42da283a56b5edc5b4fadb491365ec7f5fa8
143 parent: 1:6c0e42da283a56b5edc5b4fadb491365ec7f5fa8
145 parent: -1:0000000000000000000000000000000000000000
144 parent: -1:0000000000000000000000000000000000000000
146 manifest: 1:8c342a37dfba0b3d3ce073562a00d8a813c54ffe
145 manifest: 1:8c342a37dfba0b3d3ce073562a00d8a813c54ffe
147 user: test
146 user: test
148 date: Thu Jan 01 00:00:00 1970 +0000
147 date: Thu Jan 01 00:00:00 1970 +0000
149 files: a
148 files: a
150 extra: branch=foo
149 extra: branch=foo
151 description:
150 description:
152 modify a branch
151 modify a branch
153
152
154
153
155 $ purgebranchcaches
154 $ purgebranchcaches
156 $ echo corrupted > $branchcache
155 $ echo corrupted > $branchcache
157
156
158 $ hg log -qr foo
157 $ hg log -qr foo
159 4:adf1a74a7f7b
158 4:adf1a74a7f7b
160
159
161 $ listbranchcaches
160 $ listbranchcaches
162 === .hg/cache/branchheads ===
161 === .hg/cache/branchheads ===
163 corrupted
162 corrupted
164 === .hg/cache/branchheads-unserved ===
163 === .hg/cache/branchheads-unserved ===
165 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
164 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
166 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
165 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
167 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
166 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
168 c21617b13b220988e7a2e26290fbe4325ffa7139 bar
167 c21617b13b220988e7a2e26290fbe4325ffa7139 bar
169
168
170 Push should update the branch cache:
169 Push should update the branch cache:
171
170
172 $ hg init ../target
171 $ hg init ../target
173
172
174 Pushing just rev 0:
173 Pushing just rev 0:
175
174
176 $ hg push -qr 0 ../target
175 $ hg push -qr 0 ../target
177
176
178 $ (cd ../target/; listbranchcaches)
177 $ (cd ../target/; listbranchcaches)
179 === .hg/cache/branchheads-impactable ===
178 === .hg/cache/branchheads-impactable ===
180 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 0
179 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 0
181 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 default
180 db01e8ea3388fd3c7c94e1436ea2bd6a53d581c5 default
182
181
183 Pushing everything:
182 Pushing everything:
184
183
185 $ hg push -qf ../target
184 $ hg push -qf ../target
186
185
187 $ (cd ../target/; listbranchcaches)
186 $ (cd ../target/; listbranchcaches)
188 === .hg/cache/branchheads-impactable ===
187 === .hg/cache/branchheads-impactable ===
189 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
188 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 4
190 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
189 1c28f494dae69a2f8fc815059d257eccf3fcfe75 default
191 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
190 adf1a74a7f7b4cd193d12992f5d0d6a004ed21d6 foo
192 c21617b13b220988e7a2e26290fbe4325ffa7139 bar
191 c21617b13b220988e7a2e26290fbe4325ffa7139 bar
193
192
194 Update with no arguments: tipmost revision of the current branch:
193 Update with no arguments: tipmost revision of the current branch:
195
194
196 $ hg up -q -C 0
195 $ hg up -q -C 0
197 $ hg up -q
196 $ hg up -q
198 $ hg id
197 $ hg id
199 1c28f494dae6
198 1c28f494dae6
200
199
201 $ hg up -q 1
200 $ hg up -q 1
202 $ hg up -q
201 $ hg up -q
203 $ hg id
202 $ hg id
204 adf1a74a7f7b (foo) tip
203 adf1a74a7f7b (foo) tip
205
204
206 $ hg branch foobar
205 $ hg branch foobar
207 marked working directory as branch foobar
206 marked working directory as branch foobar
208 (branches are permanent and global, did you want a bookmark?)
207 (branches are permanent and global, did you want a bookmark?)
209
208
210 $ hg up
209 $ hg up
211 abort: branch foobar not found
210 abort: branch foobar not found
212 [255]
211 [255]
213
212
214 Fastforward merge:
213 Fastforward merge:
215
214
216 $ hg branch ff
215 $ hg branch ff
217 marked working directory as branch ff
216 marked working directory as branch ff
218 (branches are permanent and global, did you want a bookmark?)
217 (branches are permanent and global, did you want a bookmark?)
219
218
220 $ echo ff > ff
219 $ echo ff > ff
221 $ hg ci -Am'fast forward'
220 $ hg ci -Am'fast forward'
222 adding ff
221 adding ff
223
222
224 $ hg up foo
223 $ hg up foo
225 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
224 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
226
225
227 $ hg merge ff
226 $ hg merge ff
228 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 (branch merge, don't forget to commit)
228 (branch merge, don't forget to commit)
230
229
231 $ hg branch
230 $ hg branch
232 foo
231 foo
233 $ hg commit -m'Merge ff into foo'
232 $ hg commit -m'Merge ff into foo'
234 $ hg parents
233 $ hg parents
235 changeset: 6:185ffbfefa30
234 changeset: 6:185ffbfefa30
236 branch: foo
235 branch: foo
237 tag: tip
236 tag: tip
238 parent: 4:adf1a74a7f7b
237 parent: 4:adf1a74a7f7b
239 parent: 5:1a3c27dc5e11
238 parent: 5:1a3c27dc5e11
240 user: test
239 user: test
241 date: Thu Jan 01 00:00:00 1970 +0000
240 date: Thu Jan 01 00:00:00 1970 +0000
242 summary: Merge ff into foo
241 summary: Merge ff into foo
243
242
244 $ hg manifest
243 $ hg manifest
245 a
244 a
246 ff
245 ff
247
246
248
247
249 Test merging, add 3 default heads and one test head:
248 Test merging, add 3 default heads and one test head:
250
249
251 $ cd ..
250 $ cd ..
252 $ hg init merges
251 $ hg init merges
253 $ cd merges
252 $ cd merges
254 $ echo a > a
253 $ echo a > a
255 $ hg ci -Ama
254 $ hg ci -Ama
256 adding a
255 adding a
257
256
258 $ echo b > b
257 $ echo b > b
259 $ hg ci -Amb
258 $ hg ci -Amb
260 adding b
259 adding b
261
260
262 $ hg up 0
261 $ hg up 0
263 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
264 $ echo c > c
263 $ echo c > c
265 $ hg ci -Amc
264 $ hg ci -Amc
266 adding c
265 adding c
267 created new head
266 created new head
268
267
269 $ hg up 0
268 $ hg up 0
270 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
269 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
271 $ echo d > d
270 $ echo d > d
272 $ hg ci -Amd
271 $ hg ci -Amd
273 adding d
272 adding d
274 created new head
273 created new head
275
274
276 $ hg up 0
275 $ hg up 0
277 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
276 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
278 $ hg branch test
277 $ hg branch test
279 marked working directory as branch test
278 marked working directory as branch test
280 (branches are permanent and global, did you want a bookmark?)
279 (branches are permanent and global, did you want a bookmark?)
281 $ echo e >> e
280 $ echo e >> e
282 $ hg ci -Ame
281 $ hg ci -Ame
283 adding e
282 adding e
284
283
285 $ hg log
284 $ hg log
286 changeset: 4:3a1e01ed1df4
285 changeset: 4:3a1e01ed1df4
287 branch: test
286 branch: test
288 tag: tip
287 tag: tip
289 parent: 0:cb9a9f314b8b
288 parent: 0:cb9a9f314b8b
290 user: test
289 user: test
291 date: Thu Jan 01 00:00:00 1970 +0000
290 date: Thu Jan 01 00:00:00 1970 +0000
292 summary: e
291 summary: e
293
292
294 changeset: 3:980f7dc84c29
293 changeset: 3:980f7dc84c29
295 parent: 0:cb9a9f314b8b
294 parent: 0:cb9a9f314b8b
296 user: test
295 user: test
297 date: Thu Jan 01 00:00:00 1970 +0000
296 date: Thu Jan 01 00:00:00 1970 +0000
298 summary: d
297 summary: d
299
298
300 changeset: 2:d36c0562f908
299 changeset: 2:d36c0562f908
301 parent: 0:cb9a9f314b8b
300 parent: 0:cb9a9f314b8b
302 user: test
301 user: test
303 date: Thu Jan 01 00:00:00 1970 +0000
302 date: Thu Jan 01 00:00:00 1970 +0000
304 summary: c
303 summary: c
305
304
306 changeset: 1:d2ae7f538514
305 changeset: 1:d2ae7f538514
307 user: test
306 user: test
308 date: Thu Jan 01 00:00:00 1970 +0000
307 date: Thu Jan 01 00:00:00 1970 +0000
309 summary: b
308 summary: b
310
309
311 changeset: 0:cb9a9f314b8b
310 changeset: 0:cb9a9f314b8b
312 user: test
311 user: test
313 date: Thu Jan 01 00:00:00 1970 +0000
312 date: Thu Jan 01 00:00:00 1970 +0000
314 summary: a
313 summary: a
315
314
316 Implicit merge with test branch as parent:
315 Implicit merge with test branch as parent:
317
316
318 $ hg merge
317 $ hg merge
319 abort: branch 'test' has one head - please merge with an explicit rev
318 abort: branch 'test' has one head - please merge with an explicit rev
320 (run 'hg heads' to see all heads)
319 (run 'hg heads' to see all heads)
321 [255]
320 [255]
322 $ hg up -C default
321 $ hg up -C default
323 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
322 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
324
323
325 Implicit merge with default branch as parent:
324 Implicit merge with default branch as parent:
326
325
327 $ hg merge
326 $ hg merge
328 abort: branch 'default' has 3 heads - please merge with an explicit rev
327 abort: branch 'default' has 3 heads - please merge with an explicit rev
329 (run 'hg heads .' to see heads)
328 (run 'hg heads .' to see heads)
330 [255]
329 [255]
331
330
332 3 branch heads, explicit merge required:
331 3 branch heads, explicit merge required:
333
332
334 $ hg merge 2
333 $ hg merge 2
335 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 (branch merge, don't forget to commit)
335 (branch merge, don't forget to commit)
337 $ hg ci -m merge
336 $ hg ci -m merge
338
337
339 2 branch heads, implicit merge works:
338 2 branch heads, implicit merge works:
340
339
341 $ hg merge
340 $ hg merge
342 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 (branch merge, don't forget to commit)
342 (branch merge, don't forget to commit)
344
343
345 $ cd ..
344 $ cd ..
@@ -1,447 +1,447 b''
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
2
2
3 This is the most complexe troubles from far so we isolate it in a dedicated
3 This is the most complexe troubles from far so we isolate it in a dedicated
4 file.
4 file.
5
5
6 Enable obsolete
6 Enable obsolete
7
7
8 $ cat > obs.py << EOF
8 $ cat > obs.py << EOF
9 > import mercurial.obsolete
9 > import mercurial.obsolete
10 > mercurial.obsolete._enabled = True
10 > mercurial.obsolete._enabled = True
11 > EOF
11 > EOF
12 $ cat >> $HGRCPATH << EOF
12 $ cat >> $HGRCPATH << EOF
13 > [ui]
13 > [ui]
14 > logtemplate = {rev}:{node|short} {desc}\n
14 > logtemplate = {rev}:{node|short} {desc}\n
15 > [extensions]
15 > [extensions]
16 > obs=${TESTTMP}/obs.py
16 > obs=${TESTTMP}/obs.py
17 > [alias]
17 > [alias]
18 > debugobsolete = debugobsolete -d '0 0'
18 > debugobsolete = debugobsolete -d '0 0'
19 > [phases]
19 > [phases]
20 > publish=False
20 > publish=False
21 > EOF
21 > EOF
22
22
23
23
24 $ mkcommit() {
24 $ mkcommit() {
25 > echo "$1" > "$1"
25 > echo "$1" > "$1"
26 > hg add "$1"
26 > hg add "$1"
27 > hg ci -m "$1"
27 > hg ci -m "$1"
28 > }
28 > }
29 $ getid() {
29 $ getid() {
30 > hg id --debug -ir "desc('$1')"
30 > hg id --debug --hidden -ir "desc('$1')"
31 > }
31 > }
32
32
33 setup repo
33 setup repo
34
34
35 $ hg init reference
35 $ hg init reference
36 $ cd reference
36 $ cd reference
37 $ mkcommit base
37 $ mkcommit base
38 $ mkcommit A_0
38 $ mkcommit A_0
39 $ hg up 0
39 $ hg up 0
40 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
41 $ mkcommit A_1
41 $ mkcommit A_1
42 created new head
42 created new head
43 $ hg up 0
43 $ hg up 0
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 $ mkcommit A_2
45 $ mkcommit A_2
46 created new head
46 created new head
47 $ hg up 0
47 $ hg up 0
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 $ cd ..
49 $ cd ..
50
50
51
51
52 $ newcase() {
52 $ newcase() {
53 > hg clone -u 0 -q reference $1
53 > hg clone -u 0 -q reference $1
54 > cd $1
54 > cd $1
55 > }
55 > }
56
56
57 direct divergence
57 direct divergence
58 -----------------
58 -----------------
59
59
60 A_1 have two direct and divergent successors A_1 and A_1
60 A_1 have two direct and divergent successors A_1 and A_1
61
61
62 $ newcase direct
62 $ newcase direct
63 $ hg debugobsolete `getid A_0` `getid A_1`
63 $ hg debugobsolete `getid A_0` `getid A_1`
64 $ hg debugobsolete `getid A_0` `getid A_2`
64 $ hg debugobsolete `getid A_0` `getid A_2`
65 invalid branchheads cache (unserved): tip differs
65 invalid branchheads cache (unserved): tip differs
66 $ hg log -G --hidden
66 $ hg log -G --hidden
67 o 3:392fd25390da A_2
67 o 3:392fd25390da A_2
68 |
68 |
69 | o 2:82623d38b9ba A_1
69 | o 2:82623d38b9ba A_1
70 |/
70 |/
71 | x 1:007dc284c1f8 A_0
71 | x 1:007dc284c1f8 A_0
72 |/
72 |/
73 @ 0:d20a80d4def3 base
73 @ 0:d20a80d4def3 base
74
74
75 $ hg debugsuccessorssets 'all()'
75 $ hg debugsuccessorssets --hidden 'all()'
76 d20a80d4def3
76 d20a80d4def3
77 d20a80d4def3
77 d20a80d4def3
78 007dc284c1f8
78 007dc284c1f8
79 392fd25390da
79 392fd25390da
80 82623d38b9ba
80 82623d38b9ba
81 82623d38b9ba
81 82623d38b9ba
82 82623d38b9ba
82 82623d38b9ba
83 392fd25390da
83 392fd25390da
84 392fd25390da
84 392fd25390da
85 $ hg log -r 'divergent()'
85 $ hg log -r 'divergent()'
86 2:82623d38b9ba A_1
86 2:82623d38b9ba A_1
87 3:392fd25390da A_2
87 3:392fd25390da A_2
88
88
89 check that mercurial refuse to push
89 check that mercurial refuse to push
90
90
91 $ hg init ../other
91 $ hg init ../other
92 $ hg push ../other
92 $ hg push ../other
93 pushing to ../other
93 pushing to ../other
94 searching for changes
94 searching for changes
95 abort: push includes divergent changeset: 392fd25390da!
95 abort: push includes divergent changeset: 392fd25390da!
96 [255]
96 [255]
97
97
98 $ cd ..
98 $ cd ..
99
99
100
100
101 indirect divergence with known changeset
101 indirect divergence with known changeset
102 -------------------------------------------
102 -------------------------------------------
103
103
104 $ newcase indirect_known
104 $ newcase indirect_known
105 $ hg debugobsolete `getid A_0` `getid A_1`
105 $ hg debugobsolete `getid A_0` `getid A_1`
106 $ hg debugobsolete `getid A_0` `getid A_2`
106 $ hg debugobsolete `getid A_0` `getid A_2`
107 invalid branchheads cache (unserved): tip differs
107 invalid branchheads cache (unserved): tip differs
108 $ mkcommit A_3
108 $ mkcommit A_3
109 created new head
109 created new head
110 $ hg debugobsolete `getid A_2` `getid A_3`
110 $ hg debugobsolete `getid A_2` `getid A_3`
111 $ hg log -G --hidden
111 $ hg log -G --hidden
112 @ 4:01f36c5a8fda A_3
112 @ 4:01f36c5a8fda A_3
113 |
113 |
114 | x 3:392fd25390da A_2
114 | x 3:392fd25390da A_2
115 |/
115 |/
116 | o 2:82623d38b9ba A_1
116 | o 2:82623d38b9ba A_1
117 |/
117 |/
118 | x 1:007dc284c1f8 A_0
118 | x 1:007dc284c1f8 A_0
119 |/
119 |/
120 o 0:d20a80d4def3 base
120 o 0:d20a80d4def3 base
121
121
122 $ hg debugsuccessorssets 'all()'
122 $ hg debugsuccessorssets --hidden 'all()'
123 d20a80d4def3
123 d20a80d4def3
124 d20a80d4def3
124 d20a80d4def3
125 007dc284c1f8
125 007dc284c1f8
126 01f36c5a8fda
126 01f36c5a8fda
127 82623d38b9ba
127 82623d38b9ba
128 82623d38b9ba
128 82623d38b9ba
129 82623d38b9ba
129 82623d38b9ba
130 392fd25390da
130 392fd25390da
131 01f36c5a8fda
131 01f36c5a8fda
132 01f36c5a8fda
132 01f36c5a8fda
133 01f36c5a8fda
133 01f36c5a8fda
134 $ hg log -r 'divergent()'
134 $ hg log -r 'divergent()'
135 2:82623d38b9ba A_1
135 2:82623d38b9ba A_1
136 4:01f36c5a8fda A_3
136 4:01f36c5a8fda A_3
137 $ cd ..
137 $ cd ..
138
138
139
139
140 indirect divergence with known changeset
140 indirect divergence with known changeset
141 -------------------------------------------
141 -------------------------------------------
142
142
143 $ newcase indirect_unknown
143 $ newcase indirect_unknown
144 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
144 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
145 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
145 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
146 invalid branchheads cache (unserved): tip differs
146 invalid branchheads cache (unserved): tip differs
147 $ hg debugobsolete `getid A_0` `getid A_2`
147 $ hg debugobsolete `getid A_0` `getid A_2`
148 $ hg log -G --hidden
148 $ hg log -G --hidden
149 o 3:392fd25390da A_2
149 o 3:392fd25390da A_2
150 |
150 |
151 | o 2:82623d38b9ba A_1
151 | o 2:82623d38b9ba A_1
152 |/
152 |/
153 | x 1:007dc284c1f8 A_0
153 | x 1:007dc284c1f8 A_0
154 |/
154 |/
155 @ 0:d20a80d4def3 base
155 @ 0:d20a80d4def3 base
156
156
157 $ hg debugsuccessorssets 'all()'
157 $ hg debugsuccessorssets --hidden 'all()'
158 d20a80d4def3
158 d20a80d4def3
159 d20a80d4def3
159 d20a80d4def3
160 007dc284c1f8
160 007dc284c1f8
161 392fd25390da
161 392fd25390da
162 82623d38b9ba
162 82623d38b9ba
163 82623d38b9ba
163 82623d38b9ba
164 82623d38b9ba
164 82623d38b9ba
165 392fd25390da
165 392fd25390da
166 392fd25390da
166 392fd25390da
167 $ hg log -r 'divergent()'
167 $ hg log -r 'divergent()'
168 2:82623d38b9ba A_1
168 2:82623d38b9ba A_1
169 3:392fd25390da A_2
169 3:392fd25390da A_2
170 $ cd ..
170 $ cd ..
171
171
172 do not take unknown node in account if they are final
172 do not take unknown node in account if they are final
173 -----------------------------------------------------
173 -----------------------------------------------------
174
174
175 $ newcase final-unknown
175 $ newcase final-unknown
176 $ hg debugobsolete `getid A_0` `getid A_1`
176 $ hg debugobsolete `getid A_0` `getid A_1`
177 $ hg debugobsolete `getid A_1` `getid A_2`
177 $ hg debugobsolete `getid A_1` `getid A_2`
178 invalid branchheads cache (unserved): tip differs
178 invalid branchheads cache (unserved): tip differs
179 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
179 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
180 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
180 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
181 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
181 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
182
182
183 $ hg debugsuccessorssets 'desc('A_0')'
183 $ hg debugsuccessorssets --hidden 'desc('A_0')'
184 007dc284c1f8
184 007dc284c1f8
185 392fd25390da
185 392fd25390da
186
186
187 $ cd ..
187 $ cd ..
188
188
189 divergence that converge again is not divergence anymore
189 divergence that converge again is not divergence anymore
190 -----------------------------------------------------
190 -----------------------------------------------------
191
191
192 $ newcase converged_divergence
192 $ newcase converged_divergence
193 $ hg debugobsolete `getid A_0` `getid A_1`
193 $ hg debugobsolete `getid A_0` `getid A_1`
194 $ hg debugobsolete `getid A_0` `getid A_2`
194 $ hg debugobsolete `getid A_0` `getid A_2`
195 invalid branchheads cache (unserved): tip differs
195 invalid branchheads cache (unserved): tip differs
196 $ mkcommit A_3
196 $ mkcommit A_3
197 created new head
197 created new head
198 $ hg debugobsolete `getid A_1` `getid A_3`
198 $ hg debugobsolete `getid A_1` `getid A_3`
199 $ hg debugobsolete `getid A_2` `getid A_3`
199 $ hg debugobsolete `getid A_2` `getid A_3`
200 $ hg log -G --hidden
200 $ hg log -G --hidden
201 @ 4:01f36c5a8fda A_3
201 @ 4:01f36c5a8fda A_3
202 |
202 |
203 | x 3:392fd25390da A_2
203 | x 3:392fd25390da A_2
204 |/
204 |/
205 | x 2:82623d38b9ba A_1
205 | x 2:82623d38b9ba A_1
206 |/
206 |/
207 | x 1:007dc284c1f8 A_0
207 | x 1:007dc284c1f8 A_0
208 |/
208 |/
209 o 0:d20a80d4def3 base
209 o 0:d20a80d4def3 base
210
210
211 $ hg debugsuccessorssets 'all()'
211 $ hg debugsuccessorssets --hidden 'all()'
212 d20a80d4def3
212 d20a80d4def3
213 d20a80d4def3
213 d20a80d4def3
214 007dc284c1f8
214 007dc284c1f8
215 01f36c5a8fda
215 01f36c5a8fda
216 82623d38b9ba
216 82623d38b9ba
217 01f36c5a8fda
217 01f36c5a8fda
218 392fd25390da
218 392fd25390da
219 01f36c5a8fda
219 01f36c5a8fda
220 01f36c5a8fda
220 01f36c5a8fda
221 01f36c5a8fda
221 01f36c5a8fda
222 $ hg log -r 'divergent()'
222 $ hg log -r 'divergent()'
223 $ cd ..
223 $ cd ..
224
224
225 split is not divergences
225 split is not divergences
226 -----------------------------
226 -----------------------------
227
227
228 $ newcase split
228 $ newcase split
229 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
229 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
230 $ hg log -G --hidden
230 $ hg log -G --hidden
231 o 3:392fd25390da A_2
231 o 3:392fd25390da A_2
232 |
232 |
233 | o 2:82623d38b9ba A_1
233 | o 2:82623d38b9ba A_1
234 |/
234 |/
235 | x 1:007dc284c1f8 A_0
235 | x 1:007dc284c1f8 A_0
236 |/
236 |/
237 @ 0:d20a80d4def3 base
237 @ 0:d20a80d4def3 base
238
238
239 $ hg debugsuccessorssets 'all()'
239 $ hg debugsuccessorssets --hidden 'all()'
240 d20a80d4def3
240 d20a80d4def3
241 d20a80d4def3
241 d20a80d4def3
242 007dc284c1f8
242 007dc284c1f8
243 82623d38b9ba 392fd25390da
243 82623d38b9ba 392fd25390da
244 82623d38b9ba
244 82623d38b9ba
245 82623d38b9ba
245 82623d38b9ba
246 392fd25390da
246 392fd25390da
247 392fd25390da
247 392fd25390da
248 $ hg log -r 'divergent()'
248 $ hg log -r 'divergent()'
249
249
250 Even when subsequente rewriting happen
250 Even when subsequente rewriting happen
251
251
252 $ mkcommit A_3
252 $ mkcommit A_3
253 created new head
253 created new head
254 $ hg debugobsolete `getid A_1` `getid A_3`
254 $ hg debugobsolete `getid A_1` `getid A_3`
255 $ hg up 0
255 $ hg up 0
256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
257 $ mkcommit A_4
257 $ mkcommit A_4
258 created new head
258 created new head
259 $ hg debugobsolete `getid A_2` `getid A_4`
259 $ hg debugobsolete `getid A_2` `getid A_4`
260 $ hg up 0
260 $ hg up 0
261 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
261 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 $ mkcommit A_5
262 $ mkcommit A_5
263 created new head
263 created new head
264 $ hg debugobsolete `getid A_4` `getid A_5`
264 $ hg debugobsolete `getid A_4` `getid A_5`
265 $ hg log -G --hidden
265 $ hg log -G --hidden
266 @ 6:e442cfc57690 A_5
266 @ 6:e442cfc57690 A_5
267 |
267 |
268 | x 5:6a411f0d7a0a A_4
268 | x 5:6a411f0d7a0a A_4
269 |/
269 |/
270 | o 4:01f36c5a8fda A_3
270 | o 4:01f36c5a8fda A_3
271 |/
271 |/
272 | x 3:392fd25390da A_2
272 | x 3:392fd25390da A_2
273 |/
273 |/
274 | x 2:82623d38b9ba A_1
274 | x 2:82623d38b9ba A_1
275 |/
275 |/
276 | x 1:007dc284c1f8 A_0
276 | x 1:007dc284c1f8 A_0
277 |/
277 |/
278 o 0:d20a80d4def3 base
278 o 0:d20a80d4def3 base
279
279
280 $ hg debugsuccessorssets 'all()'
280 $ hg debugsuccessorssets --hidden 'all()'
281 d20a80d4def3
281 d20a80d4def3
282 d20a80d4def3
282 d20a80d4def3
283 007dc284c1f8
283 007dc284c1f8
284 01f36c5a8fda e442cfc57690
284 01f36c5a8fda e442cfc57690
285 82623d38b9ba
285 82623d38b9ba
286 01f36c5a8fda
286 01f36c5a8fda
287 392fd25390da
287 392fd25390da
288 e442cfc57690
288 e442cfc57690
289 01f36c5a8fda
289 01f36c5a8fda
290 01f36c5a8fda
290 01f36c5a8fda
291 6a411f0d7a0a
291 6a411f0d7a0a
292 e442cfc57690
292 e442cfc57690
293 e442cfc57690
293 e442cfc57690
294 e442cfc57690
294 e442cfc57690
295 $ hg log -r 'divergent()'
295 $ hg log -r 'divergent()'
296
296
297 Check more complexe obsolescence graft (with divergence)
297 Check more complexe obsolescence graft (with divergence)
298
298
299 $ mkcommit B_0; hg up 0
299 $ mkcommit B_0; hg up 0
300 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
300 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
301 $ hg debugobsolete `getid B_0` `getid A_2`
301 $ hg debugobsolete `getid B_0` `getid A_2`
302 $ mkcommit A_7; hg up 0
302 $ mkcommit A_7; hg up 0
303 created new head
303 created new head
304 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
304 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 $ mkcommit A_8; hg up 0
305 $ mkcommit A_8; hg up 0
306 created new head
306 created new head
307 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
307 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
308 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
309 $ mkcommit A_9; hg up 0
309 $ mkcommit A_9; hg up 0
310 created new head
310 created new head
311 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
311 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
312 $ hg debugobsolete `getid A_5` `getid A_9`
312 $ hg debugobsolete `getid A_5` `getid A_9`
313 $ hg log -G --hidden
313 $ hg log -G --hidden
314 o 10:bed64f5d2f5a A_9
314 o 10:bed64f5d2f5a A_9
315 |
315 |
316 | o 9:14608b260df8 A_8
316 | o 9:14608b260df8 A_8
317 |/
317 |/
318 | o 8:7ae126973a96 A_7
318 | o 8:7ae126973a96 A_7
319 |/
319 |/
320 | x 7:3750ebee865d B_0
320 | x 7:3750ebee865d B_0
321 | |
321 | |
322 | x 6:e442cfc57690 A_5
322 | x 6:e442cfc57690 A_5
323 |/
323 |/
324 | x 5:6a411f0d7a0a A_4
324 | x 5:6a411f0d7a0a A_4
325 |/
325 |/
326 | o 4:01f36c5a8fda A_3
326 | o 4:01f36c5a8fda A_3
327 |/
327 |/
328 | x 3:392fd25390da A_2
328 | x 3:392fd25390da A_2
329 |/
329 |/
330 | x 2:82623d38b9ba A_1
330 | x 2:82623d38b9ba A_1
331 |/
331 |/
332 | x 1:007dc284c1f8 A_0
332 | x 1:007dc284c1f8 A_0
333 |/
333 |/
334 @ 0:d20a80d4def3 base
334 @ 0:d20a80d4def3 base
335
335
336 $ hg debugsuccessorssets 'all()'
336 $ hg debugsuccessorssets --hidden 'all()'
337 d20a80d4def3
337 d20a80d4def3
338 d20a80d4def3
338 d20a80d4def3
339 007dc284c1f8
339 007dc284c1f8
340 01f36c5a8fda bed64f5d2f5a
340 01f36c5a8fda bed64f5d2f5a
341 01f36c5a8fda 7ae126973a96 14608b260df8
341 01f36c5a8fda 7ae126973a96 14608b260df8
342 82623d38b9ba
342 82623d38b9ba
343 01f36c5a8fda
343 01f36c5a8fda
344 392fd25390da
344 392fd25390da
345 bed64f5d2f5a
345 bed64f5d2f5a
346 7ae126973a96 14608b260df8
346 7ae126973a96 14608b260df8
347 01f36c5a8fda
347 01f36c5a8fda
348 01f36c5a8fda
348 01f36c5a8fda
349 6a411f0d7a0a
349 6a411f0d7a0a
350 bed64f5d2f5a
350 bed64f5d2f5a
351 7ae126973a96 14608b260df8
351 7ae126973a96 14608b260df8
352 e442cfc57690
352 e442cfc57690
353 bed64f5d2f5a
353 bed64f5d2f5a
354 7ae126973a96 14608b260df8
354 7ae126973a96 14608b260df8
355 3750ebee865d
355 3750ebee865d
356 bed64f5d2f5a
356 bed64f5d2f5a
357 7ae126973a96 14608b260df8
357 7ae126973a96 14608b260df8
358 7ae126973a96
358 7ae126973a96
359 7ae126973a96
359 7ae126973a96
360 14608b260df8
360 14608b260df8
361 14608b260df8
361 14608b260df8
362 bed64f5d2f5a
362 bed64f5d2f5a
363 bed64f5d2f5a
363 bed64f5d2f5a
364 $ hg log -r 'divergent()'
364 $ hg log -r 'divergent()'
365 4:01f36c5a8fda A_3
365 4:01f36c5a8fda A_3
366 8:7ae126973a96 A_7
366 8:7ae126973a96 A_7
367 9:14608b260df8 A_8
367 9:14608b260df8 A_8
368 10:bed64f5d2f5a A_9
368 10:bed64f5d2f5a A_9
369
369
370 fix the divergence
370 fix the divergence
371
371
372 $ mkcommit A_A; hg up 0
372 $ mkcommit A_A; hg up 0
373 created new head
373 created new head
374 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
374 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
375 $ hg debugobsolete `getid A_9` `getid A_A`
375 $ hg debugobsolete `getid A_9` `getid A_A`
376 $ hg debugobsolete `getid A_7` `getid A_A`
376 $ hg debugobsolete `getid A_7` `getid A_A`
377 $ hg debugobsolete `getid A_8` `getid A_A`
377 $ hg debugobsolete `getid A_8` `getid A_A`
378 $ hg log -G --hidden
378 $ hg log -G --hidden
379 o 11:a139f71be9da A_A
379 o 11:a139f71be9da A_A
380 |
380 |
381 | x 10:bed64f5d2f5a A_9
381 | x 10:bed64f5d2f5a A_9
382 |/
382 |/
383 | x 9:14608b260df8 A_8
383 | x 9:14608b260df8 A_8
384 |/
384 |/
385 | x 8:7ae126973a96 A_7
385 | x 8:7ae126973a96 A_7
386 |/
386 |/
387 | x 7:3750ebee865d B_0
387 | x 7:3750ebee865d B_0
388 | |
388 | |
389 | x 6:e442cfc57690 A_5
389 | x 6:e442cfc57690 A_5
390 |/
390 |/
391 | x 5:6a411f0d7a0a A_4
391 | x 5:6a411f0d7a0a A_4
392 |/
392 |/
393 | o 4:01f36c5a8fda A_3
393 | o 4:01f36c5a8fda A_3
394 |/
394 |/
395 | x 3:392fd25390da A_2
395 | x 3:392fd25390da A_2
396 |/
396 |/
397 | x 2:82623d38b9ba A_1
397 | x 2:82623d38b9ba A_1
398 |/
398 |/
399 | x 1:007dc284c1f8 A_0
399 | x 1:007dc284c1f8 A_0
400 |/
400 |/
401 @ 0:d20a80d4def3 base
401 @ 0:d20a80d4def3 base
402
402
403 $ hg debugsuccessorssets 'all()'
403 $ hg debugsuccessorssets --hidden 'all()'
404 d20a80d4def3
404 d20a80d4def3
405 d20a80d4def3
405 d20a80d4def3
406 007dc284c1f8
406 007dc284c1f8
407 01f36c5a8fda a139f71be9da
407 01f36c5a8fda a139f71be9da
408 82623d38b9ba
408 82623d38b9ba
409 01f36c5a8fda
409 01f36c5a8fda
410 392fd25390da
410 392fd25390da
411 a139f71be9da
411 a139f71be9da
412 01f36c5a8fda
412 01f36c5a8fda
413 01f36c5a8fda
413 01f36c5a8fda
414 6a411f0d7a0a
414 6a411f0d7a0a
415 a139f71be9da
415 a139f71be9da
416 e442cfc57690
416 e442cfc57690
417 a139f71be9da
417 a139f71be9da
418 3750ebee865d
418 3750ebee865d
419 a139f71be9da
419 a139f71be9da
420 7ae126973a96
420 7ae126973a96
421 a139f71be9da
421 a139f71be9da
422 14608b260df8
422 14608b260df8
423 a139f71be9da
423 a139f71be9da
424 bed64f5d2f5a
424 bed64f5d2f5a
425 a139f71be9da
425 a139f71be9da
426 a139f71be9da
426 a139f71be9da
427 a139f71be9da
427 a139f71be9da
428 $ hg log -r 'divergent()'
428 $ hg log -r 'divergent()'
429
429
430 $ cd ..
430 $ cd ..
431
431
432
432
433 Subset does not diverge
433 Subset does not diverge
434 ------------------------------
434 ------------------------------
435
435
436 Do not report divergent successors-set if it is a subset of another
436 Do not report divergent successors-set if it is a subset of another
437 successors-set. (report [A,B] not [A] + [A,B])
437 successors-set. (report [A,B] not [A] + [A,B])
438
438
439 $ newcase subset
439 $ newcase subset
440 $ hg debugobsolete `getid A_0` `getid A_2`
440 $ hg debugobsolete `getid A_0` `getid A_2`
441 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
441 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
442 invalid branchheads cache (unserved): tip differs
442 invalid branchheads cache (unserved): tip differs
443 $ hg debugsuccessorssets 'desc('A_0')'
443 $ hg debugsuccessorssets --hidden 'desc('A_0')'
444 007dc284c1f8
444 007dc284c1f8
445 82623d38b9ba 392fd25390da
445 82623d38b9ba 392fd25390da
446
446
447 $ cd ..
447 $ cd ..
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now