##// END OF EJS Templates
add -b/--branch option to clone, bundle, incoming, outgoing, pull, push
Sune Foldager -
r10379:a78bfaf9 default
parent child Browse files
Show More
@@ -1,377 +1,377 b''
1 1 # ASCII graph log extension for Mercurial
2 2 #
3 3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''command to view revision graphs from a shell
9 9
10 10 This extension adds a --graph option to the incoming, outgoing and log
11 11 commands. When this options is given, an ASCII representation of the
12 12 revision graph is also shown.
13 13 '''
14 14
15 15 import os
16 16 from mercurial.cmdutil import revrange, show_changeset
17 17 from mercurial.commands import templateopts
18 18 from mercurial.i18n import _
19 19 from mercurial.node import nullrev
20 20 from mercurial import bundlerepo, changegroup, cmdutil, commands, extensions
21 21 from mercurial import hg, url, util, graphmod
22 22
23 23 ASCIIDATA = 'ASC'
24 24
25 25 def asciiedges(seen, rev, parents):
26 26 """adds edge info to changelog DAG walk suitable for ascii()"""
27 27 if rev not in seen:
28 28 seen.append(rev)
29 29 nodeidx = seen.index(rev)
30 30
31 31 knownparents = []
32 32 newparents = []
33 33 for parent in parents:
34 34 if parent in seen:
35 35 knownparents.append(parent)
36 36 else:
37 37 newparents.append(parent)
38 38
39 39 ncols = len(seen)
40 40 seen[nodeidx:nodeidx + 1] = newparents
41 41 edges = [(nodeidx, seen.index(p)) for p in knownparents]
42 42
43 43 if len(newparents) > 0:
44 44 edges.append((nodeidx, nodeidx))
45 45 if len(newparents) > 1:
46 46 edges.append((nodeidx, nodeidx + 1))
47 47
48 48 nmorecols = len(seen) - ncols
49 49 return nodeidx, edges, ncols, nmorecols
50 50
51 51 def fix_long_right_edges(edges):
52 52 for (i, (start, end)) in enumerate(edges):
53 53 if end > start:
54 54 edges[i] = (start, end + 1)
55 55
56 56 def get_nodeline_edges_tail(
57 57 node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
58 58 if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
59 59 # Still going in the same non-vertical direction.
60 60 if n_columns_diff == -1:
61 61 start = max(node_index + 1, p_node_index)
62 62 tail = ["|", " "] * (start - node_index - 1)
63 63 tail.extend(["/", " "] * (n_columns - start))
64 64 return tail
65 65 else:
66 66 return ["\\", " "] * (n_columns - node_index - 1)
67 67 else:
68 68 return ["|", " "] * (n_columns - node_index - 1)
69 69
70 70 def draw_edges(edges, nodeline, interline):
71 71 for (start, end) in edges:
72 72 if start == end + 1:
73 73 interline[2 * end + 1] = "/"
74 74 elif start == end - 1:
75 75 interline[2 * start + 1] = "\\"
76 76 elif start == end:
77 77 interline[2 * start] = "|"
78 78 else:
79 79 nodeline[2 * end] = "+"
80 80 if start > end:
81 81 (start, end) = (end, start)
82 82 for i in range(2 * start + 1, 2 * end):
83 83 if nodeline[i] != "+":
84 84 nodeline[i] = "-"
85 85
86 86 def get_padding_line(ni, n_columns, edges):
87 87 line = []
88 88 line.extend(["|", " "] * ni)
89 89 if (ni, ni - 1) in edges or (ni, ni) in edges:
90 90 # (ni, ni - 1) (ni, ni)
91 91 # | | | | | | | |
92 92 # +---o | | o---+
93 93 # | | c | | c | |
94 94 # | |/ / | |/ /
95 95 # | | | | | |
96 96 c = "|"
97 97 else:
98 98 c = " "
99 99 line.extend([c, " "])
100 100 line.extend(["|", " "] * (n_columns - ni - 1))
101 101 return line
102 102
103 103 def asciistate():
104 104 """returns the initial value for the "state" argument to ascii()"""
105 105 return [0, 0]
106 106
107 107 def ascii(ui, state, type, char, text, coldata):
108 108 """prints an ASCII graph of the DAG
109 109
110 110 takes the following arguments (one call per node in the graph):
111 111
112 112 - ui to write to
113 113 - Somewhere to keep the needed state in (init to asciistate())
114 114 - Column of the current node in the set of ongoing edges.
115 115 - Type indicator of node data == ASCIIDATA.
116 116 - Payload: (char, lines):
117 117 - Character to use as node's symbol.
118 118 - List of lines to display as the node's text.
119 119 - Edges; a list of (col, next_col) indicating the edges between
120 120 the current node and its parents.
121 121 - Number of columns (ongoing edges) in the current revision.
122 122 - The difference between the number of columns (ongoing edges)
123 123 in the next revision and the number of columns (ongoing edges)
124 124 in the current revision. That is: -1 means one column removed;
125 125 0 means no columns added or removed; 1 means one column added.
126 126 """
127 127
128 128 idx, edges, ncols, coldiff = coldata
129 129 assert -2 < coldiff < 2
130 130 if coldiff == -1:
131 131 # Transform
132 132 #
133 133 # | | | | | |
134 134 # o | | into o---+
135 135 # |X / |/ /
136 136 # | | | |
137 137 fix_long_right_edges(edges)
138 138
139 139 # add_padding_line says whether to rewrite
140 140 #
141 141 # | | | | | | | |
142 142 # | o---+ into | o---+
143 143 # | / / | | | # <--- padding line
144 144 # o | | | / /
145 145 # o | |
146 146 add_padding_line = (len(text) > 2 and coldiff == -1 and
147 147 [x for (x, y) in edges if x + 1 < y])
148 148
149 149 # fix_nodeline_tail says whether to rewrite
150 150 #
151 151 # | | o | | | | o | |
152 152 # | | |/ / | | |/ /
153 153 # | o | | into | o / / # <--- fixed nodeline tail
154 154 # | |/ / | |/ /
155 155 # o | | o | |
156 156 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
157 157
158 158 # nodeline is the line containing the node character (typically o)
159 159 nodeline = ["|", " "] * idx
160 160 nodeline.extend([char, " "])
161 161
162 162 nodeline.extend(
163 163 get_nodeline_edges_tail(idx, state[1], ncols, coldiff,
164 164 state[0], fix_nodeline_tail))
165 165
166 166 # shift_interline is the line containing the non-vertical
167 167 # edges between this entry and the next
168 168 shift_interline = ["|", " "] * idx
169 169 if coldiff == -1:
170 170 n_spaces = 1
171 171 edge_ch = "/"
172 172 elif coldiff == 0:
173 173 n_spaces = 2
174 174 edge_ch = "|"
175 175 else:
176 176 n_spaces = 3
177 177 edge_ch = "\\"
178 178 shift_interline.extend(n_spaces * [" "])
179 179 shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
180 180
181 181 # draw edges from the current node to its parents
182 182 draw_edges(edges, nodeline, shift_interline)
183 183
184 184 # lines is the list of all graph lines to print
185 185 lines = [nodeline]
186 186 if add_padding_line:
187 187 lines.append(get_padding_line(idx, ncols, edges))
188 188 lines.append(shift_interline)
189 189
190 190 # make sure that there are as many graph lines as there are
191 191 # log strings
192 192 while len(text) < len(lines):
193 193 text.append("")
194 194 if len(lines) < len(text):
195 195 extra_interline = ["|", " "] * (ncols + coldiff)
196 196 while len(lines) < len(text):
197 197 lines.append(extra_interline)
198 198
199 199 # print lines
200 200 indentation_level = max(ncols, ncols + coldiff)
201 201 for (line, logstr) in zip(lines, text):
202 202 ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr)
203 203 ui.write(ln.rstrip() + '\n')
204 204
205 205 # ... and start over
206 206 state[0] = coldiff
207 207 state[1] = idx
208 208
209 209 def get_revs(repo, rev_opt):
210 210 if rev_opt:
211 211 revs = revrange(repo, rev_opt)
212 212 return (max(revs), min(revs))
213 213 else:
214 214 return (len(repo) - 1, 0)
215 215
216 216 def check_unsupported_flags(opts):
217 217 for op in ["follow", "follow_first", "date", "copies", "keyword", "remove",
218 218 "only_merges", "user", "only_branch", "prune", "newest_first",
219 219 "no_merges", "include", "exclude"]:
220 220 if op in opts and opts[op]:
221 221 raise util.Abort(_("--graph option is incompatible with --%s")
222 222 % op.replace("_", "-"))
223 223
224 224 def generate(ui, dag, displayer, showparents, edgefn):
225 225 seen, state = [], asciistate()
226 226 for rev, type, ctx, parents in dag:
227 227 char = ctx.node() in showparents and '@' or 'o'
228 228 displayer.show(ctx)
229 229 lines = displayer.hunk.pop(rev).split('\n')[:-1]
230 230 ascii(ui, state, type, char, lines, edgefn(seen, rev, parents))
231 231
232 232 def graphlog(ui, repo, path=None, **opts):
233 233 """show revision history alongside an ASCII revision graph
234 234
235 235 Print a revision history alongside a revision graph drawn with
236 236 ASCII characters.
237 237
238 238 Nodes printed as an @ character are parents of the working
239 239 directory.
240 240 """
241 241
242 242 check_unsupported_flags(opts)
243 243 limit = cmdutil.loglimit(opts)
244 244 start, stop = get_revs(repo, opts["rev"])
245 245 if start == nullrev:
246 246 return
247 247
248 248 if path:
249 249 path = util.canonpath(repo.root, os.getcwd(), path)
250 250 if path: # could be reset in canonpath
251 251 revdag = graphmod.filerevs(repo, path, start, stop, limit)
252 252 else:
253 253 if limit is not None:
254 254 stop = max(stop, start - limit + 1)
255 255 revdag = graphmod.revisions(repo, start, stop)
256 256
257 257 displayer = show_changeset(ui, repo, opts, buffered=True)
258 258 showparents = [ctx.node() for ctx in repo[None].parents()]
259 259 generate(ui, revdag, displayer, showparents, asciiedges)
260 260
261 261 def graphrevs(repo, nodes, opts):
262 262 limit = cmdutil.loglimit(opts)
263 263 nodes.reverse()
264 264 if limit is not None:
265 265 nodes = nodes[:limit]
266 266 return graphmod.nodes(repo, nodes)
267 267
268 268 def goutgoing(ui, repo, dest=None, **opts):
269 269 """show the outgoing changesets alongside an ASCII revision graph
270 270
271 271 Print the outgoing changesets alongside a revision graph drawn with
272 272 ASCII characters.
273 273
274 274 Nodes printed as an @ character are parents of the working
275 275 directory.
276 276 """
277 277
278 278 check_unsupported_flags(opts)
279 279 dest = ui.expandpath(dest or 'default-push', dest or 'default')
280 dest, branches = hg.parseurl(dest)
280 dest, branches = hg.parseurl(dest, opts.get('branch'))
281 281 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
282 282 other = hg.repository(cmdutil.remoteui(ui, opts), dest)
283 283 if revs:
284 284 revs = [repo.lookup(rev) for rev in revs]
285 285 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
286 286 o = repo.findoutgoing(other, force=opts.get('force'))
287 287 if not o:
288 288 ui.status(_("no changes found\n"))
289 289 return
290 290
291 291 o = repo.changelog.nodesbetween(o, revs)[0]
292 292 revdag = graphrevs(repo, o, opts)
293 293 displayer = show_changeset(ui, repo, opts, buffered=True)
294 294 showparents = [ctx.node() for ctx in repo[None].parents()]
295 295 generate(ui, revdag, displayer, showparents, asciiedges)
296 296
297 297 def gincoming(ui, repo, source="default", **opts):
298 298 """show the incoming changesets alongside an ASCII revision graph
299 299
300 300 Print the incoming changesets alongside a revision graph drawn with
301 301 ASCII characters.
302 302
303 303 Nodes printed as an @ character are parents of the working
304 304 directory.
305 305 """
306 306
307 307 check_unsupported_flags(opts)
308 source, branches = hg.parseurl(ui.expandpath(source))
308 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
309 309 other = hg.repository(cmdutil.remoteui(repo, opts), source)
310 310 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
311 311 ui.status(_('comparing with %s\n') % url.hidepassword(source))
312 312 if revs:
313 313 revs = [other.lookup(rev) for rev in revs]
314 314 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
315 315 if not incoming:
316 316 try:
317 317 os.unlink(opts["bundle"])
318 318 except:
319 319 pass
320 320 ui.status(_("no changes found\n"))
321 321 return
322 322
323 323 cleanup = None
324 324 try:
325 325
326 326 fname = opts["bundle"]
327 327 if fname or not other.local():
328 328 # create a bundle (uncompressed if other repo is not local)
329 329 if revs is None:
330 330 cg = other.changegroup(incoming, "incoming")
331 331 else:
332 332 cg = other.changegroupsubset(incoming, revs, 'incoming')
333 333 bundletype = other.local() and "HG10BZ" or "HG10UN"
334 334 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
335 335 # keep written bundle?
336 336 if opts["bundle"]:
337 337 cleanup = None
338 338 if not other.local():
339 339 # use the created uncompressed bundlerepo
340 340 other = bundlerepo.bundlerepository(ui, repo.root, fname)
341 341
342 342 chlist = other.changelog.nodesbetween(incoming, revs)[0]
343 343 revdag = graphrevs(other, chlist, opts)
344 344 displayer = show_changeset(ui, other, opts, buffered=True)
345 345 showparents = [ctx.node() for ctx in repo[None].parents()]
346 346 generate(ui, revdag, displayer, showparents, asciiedges)
347 347
348 348 finally:
349 349 if hasattr(other, 'close'):
350 350 other.close()
351 351 if cleanup:
352 352 os.unlink(cleanup)
353 353
354 354 def uisetup(ui):
355 355 '''Initialize the extension.'''
356 356 _wrapcmd(ui, 'log', commands.table, graphlog)
357 357 _wrapcmd(ui, 'incoming', commands.table, gincoming)
358 358 _wrapcmd(ui, 'outgoing', commands.table, goutgoing)
359 359
360 360 def _wrapcmd(ui, cmd, table, wrapfn):
361 361 '''wrap the command'''
362 362 def graph(orig, *args, **kwargs):
363 363 if kwargs['graph']:
364 364 return wrapfn(*args, **kwargs)
365 365 return orig(*args, **kwargs)
366 366 entry = extensions.wrapcommand(table, cmd, graph)
367 367 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
368 368
369 369 cmdtable = {
370 370 "glog":
371 371 (graphlog,
372 372 [('l', 'limit', '', _('limit number of changes displayed')),
373 373 ('p', 'patch', False, _('show patch')),
374 374 ('r', 'rev', [], _('show the specified revision or range')),
375 375 ] + templateopts,
376 376 _('hg glog [OPTION]... [FILE]')),
377 377 }
@@ -1,3765 +1,3779 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _, gettext
11 11 import os, re, sys, difflib, time, tempfile
12 12 import hg, util, revlog, bundlerepo, extensions, copies, error
13 13 import patch, help, mdiff, url, encoding, templatekw
14 14 import archival, changegroup, cmdutil, sshserver, hbisect
15 15 from hgweb import server
16 16 import merge as merge_
17 17 import minirst
18 18
19 19 # Commands start here, listed alphabetically
20 20
21 21 def add(ui, repo, *pats, **opts):
22 22 """add the specified files on the next commit
23 23
24 24 Schedule files to be version controlled and added to the
25 25 repository.
26 26
27 27 The files will be added to the repository at the next commit. To
28 28 undo an add before that, see hg forget.
29 29
30 30 If no names are given, add all files to the repository.
31 31 """
32 32
33 33 bad = []
34 34 names = []
35 35 m = cmdutil.match(repo, pats, opts)
36 36 oldbad = m.bad
37 37 m.bad = lambda x, y: bad.append(x) or oldbad(x, y)
38 38
39 39 for f in repo.walk(m):
40 40 exact = m.exact(f)
41 41 if exact or f not in repo.dirstate:
42 42 names.append(f)
43 43 if ui.verbose or not exact:
44 44 ui.status(_('adding %s\n') % m.rel(f))
45 45 if not opts.get('dry_run'):
46 46 bad += [f for f in repo.add(names) if f in m.files()]
47 47 return bad and 1 or 0
48 48
49 49 def addremove(ui, repo, *pats, **opts):
50 50 """add all new files, delete all missing files
51 51
52 52 Add all new files and remove all missing files from the
53 53 repository.
54 54
55 55 New files are ignored if they match any of the patterns in
56 56 .hgignore. As with add, these changes take effect at the next
57 57 commit.
58 58
59 59 Use the -s/--similarity option to detect renamed files. With a
60 60 parameter greater than 0, this compares every removed file with
61 61 every added file and records those similar enough as renames. This
62 62 option takes a percentage between 0 (disabled) and 100 (files must
63 63 be identical) as its parameter. Detecting renamed files this way
64 64 can be expensive.
65 65 """
66 66 try:
67 67 sim = float(opts.get('similarity') or 0)
68 68 except ValueError:
69 69 raise util.Abort(_('similarity must be a number'))
70 70 if sim < 0 or sim > 100:
71 71 raise util.Abort(_('similarity must be between 0 and 100'))
72 72 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
73 73
74 74 def annotate(ui, repo, *pats, **opts):
75 75 """show changeset information by line for each file
76 76
77 77 List changes in files, showing the revision id responsible for
78 78 each line
79 79
80 80 This command is useful for discovering when a change was made and
81 81 by whom.
82 82
83 83 Without the -a/--text option, annotate will avoid processing files
84 84 it detects as binary. With -a, annotate will annotate the file
85 85 anyway, although the results will probably be neither useful
86 86 nor desirable.
87 87 """
88 88 datefunc = ui.quiet and util.shortdate or util.datestr
89 89 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
90 90
91 91 if not pats:
92 92 raise util.Abort(_('at least one filename or pattern is required'))
93 93
94 94 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
95 95 ('number', lambda x: str(x[0].rev())),
96 96 ('changeset', lambda x: short(x[0].node())),
97 97 ('date', getdate),
98 98 ('file', lambda x: x[0].path()),
99 99 ]
100 100
101 101 if (not opts.get('user') and not opts.get('changeset')
102 102 and not opts.get('date') and not opts.get('file')):
103 103 opts['number'] = 1
104 104
105 105 linenumber = opts.get('line_number') is not None
106 106 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
107 107 raise util.Abort(_('at least one of -n/-c is required for -l'))
108 108
109 109 funcmap = [func for op, func in opmap if opts.get(op)]
110 110 if linenumber:
111 111 lastfunc = funcmap[-1]
112 112 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
113 113
114 114 ctx = repo[opts.get('rev')]
115 115 m = cmdutil.match(repo, pats, opts)
116 116 follow = not opts.get('no_follow')
117 117 for abs in ctx.walk(m):
118 118 fctx = ctx[abs]
119 119 if not opts.get('text') and util.binary(fctx.data()):
120 120 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
121 121 continue
122 122
123 123 lines = fctx.annotate(follow=follow, linenumber=linenumber)
124 124 pieces = []
125 125
126 126 for f in funcmap:
127 127 l = [f(n) for n, dummy in lines]
128 128 if l:
129 129 ml = max(map(len, l))
130 130 pieces.append(["%*s" % (ml, x) for x in l])
131 131
132 132 if pieces:
133 133 for p, l in zip(zip(*pieces), lines):
134 134 ui.write("%s: %s" % (" ".join(p), l[1]))
135 135
136 136 def archive(ui, repo, dest, **opts):
137 137 '''create an unversioned archive of a repository revision
138 138
139 139 By default, the revision used is the parent of the working
140 140 directory; use -r/--rev to specify a different revision.
141 141
142 142 To specify the type of archive to create, use -t/--type. Valid
143 143 types are:
144 144
145 145 :``files``: a directory full of files (default)
146 146 :``tar``: tar archive, uncompressed
147 147 :``tbz2``: tar archive, compressed using bzip2
148 148 :``tgz``: tar archive, compressed using gzip
149 149 :``uzip``: zip archive, uncompressed
150 150 :``zip``: zip archive, compressed using deflate
151 151
152 152 The exact name of the destination archive or directory is given
153 153 using a format string; see 'hg help export' for details.
154 154
155 155 Each member added to an archive file has a directory prefix
156 156 prepended. Use -p/--prefix to specify a format string for the
157 157 prefix. The default is the basename of the archive, with suffixes
158 158 removed.
159 159 '''
160 160
161 161 ctx = repo[opts.get('rev')]
162 162 if not ctx:
163 163 raise util.Abort(_('no working directory: please specify a revision'))
164 164 node = ctx.node()
165 165 dest = cmdutil.make_filename(repo, dest, node)
166 166 if os.path.realpath(dest) == repo.root:
167 167 raise util.Abort(_('repository root cannot be destination'))
168 168 matchfn = cmdutil.match(repo, [], opts)
169 169 kind = opts.get('type') or 'files'
170 170 prefix = opts.get('prefix')
171 171 if dest == '-':
172 172 if kind == 'files':
173 173 raise util.Abort(_('cannot archive plain files to stdout'))
174 174 dest = sys.stdout
175 175 if not prefix:
176 176 prefix = os.path.basename(repo.root) + '-%h'
177 177 prefix = cmdutil.make_filename(repo, prefix, node)
178 178 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
179 179 matchfn, prefix)
180 180
181 181 def backout(ui, repo, node=None, rev=None, **opts):
182 182 '''reverse effect of earlier changeset
183 183
184 184 Commit the backed out changes as a new changeset. The new
185 185 changeset is a child of the backed out changeset.
186 186
187 187 If you backout a changeset other than the tip, a new head is
188 188 created. This head will be the new tip and you should merge this
189 189 backout changeset with another head.
190 190
191 191 The --merge option remembers the parent of the working directory
192 192 before starting the backout, then merges the new head with that
193 193 changeset afterwards. This saves you from doing the merge by hand.
194 194 The result of this merge is not committed, as with a normal merge.
195 195
196 196 See 'hg help dates' for a list of formats valid for -d/--date.
197 197 '''
198 198 if rev and node:
199 199 raise util.Abort(_("please specify just one revision"))
200 200
201 201 if not rev:
202 202 rev = node
203 203
204 204 if not rev:
205 205 raise util.Abort(_("please specify a revision to backout"))
206 206
207 207 date = opts.get('date')
208 208 if date:
209 209 opts['date'] = util.parsedate(date)
210 210
211 211 cmdutil.bail_if_changed(repo)
212 212 node = repo.lookup(rev)
213 213
214 214 op1, op2 = repo.dirstate.parents()
215 215 a = repo.changelog.ancestor(op1, node)
216 216 if a != node:
217 217 raise util.Abort(_('cannot backout change on a different branch'))
218 218
219 219 p1, p2 = repo.changelog.parents(node)
220 220 if p1 == nullid:
221 221 raise util.Abort(_('cannot backout a change with no parents'))
222 222 if p2 != nullid:
223 223 if not opts.get('parent'):
224 224 raise util.Abort(_('cannot backout a merge changeset without '
225 225 '--parent'))
226 226 p = repo.lookup(opts['parent'])
227 227 if p not in (p1, p2):
228 228 raise util.Abort(_('%s is not a parent of %s') %
229 229 (short(p), short(node)))
230 230 parent = p
231 231 else:
232 232 if opts.get('parent'):
233 233 raise util.Abort(_('cannot use --parent on non-merge changeset'))
234 234 parent = p1
235 235
236 236 # the backout should appear on the same branch
237 237 branch = repo.dirstate.branch()
238 238 hg.clean(repo, node, show_stats=False)
239 239 repo.dirstate.setbranch(branch)
240 240 revert_opts = opts.copy()
241 241 revert_opts['date'] = None
242 242 revert_opts['all'] = True
243 243 revert_opts['rev'] = hex(parent)
244 244 revert_opts['no_backup'] = None
245 245 revert(ui, repo, **revert_opts)
246 246 commit_opts = opts.copy()
247 247 commit_opts['addremove'] = False
248 248 if not commit_opts['message'] and not commit_opts['logfile']:
249 249 # we don't translate commit messages
250 250 commit_opts['message'] = "Backed out changeset %s" % short(node)
251 251 commit_opts['force_editor'] = True
252 252 commit(ui, repo, **commit_opts)
253 253 def nice(node):
254 254 return '%d:%s' % (repo.changelog.rev(node), short(node))
255 255 ui.status(_('changeset %s backs out changeset %s\n') %
256 256 (nice(repo.changelog.tip()), nice(node)))
257 257 if op1 != node:
258 258 hg.clean(repo, op1, show_stats=False)
259 259 if opts.get('merge'):
260 260 ui.status(_('merging with changeset %s\n')
261 261 % nice(repo.changelog.tip()))
262 262 hg.merge(repo, hex(repo.changelog.tip()))
263 263 else:
264 264 ui.status(_('the backout changeset is a new head - '
265 265 'do not forget to merge\n'))
266 266 ui.status(_('(use "backout --merge" '
267 267 'if you want to auto-merge)\n'))
268 268
269 269 def bisect(ui, repo, rev=None, extra=None, command=None,
270 270 reset=None, good=None, bad=None, skip=None, noupdate=None):
271 271 """subdivision search of changesets
272 272
273 273 This command helps to find changesets which introduce problems. To
274 274 use, mark the earliest changeset you know exhibits the problem as
275 275 bad, then mark the latest changeset which is free from the problem
276 276 as good. Bisect will update your working directory to a revision
277 277 for testing (unless the -U/--noupdate option is specified). Once
278 278 you have performed tests, mark the working directory as good or
279 279 bad, and bisect will either update to another candidate changeset
280 280 or announce that it has found the bad revision.
281 281
282 282 As a shortcut, you can also use the revision argument to mark a
283 283 revision as good or bad without checking it out first.
284 284
285 285 If you supply a command, it will be used for automatic bisection.
286 286 Its exit status will be used to mark revisions as good or bad:
287 287 status 0 means good, 125 means to skip the revision, 127
288 288 (command not found) will abort the bisection, and any other
289 289 non-zero exit status means the revision is bad.
290 290 """
291 291 def print_result(nodes, good):
292 292 displayer = cmdutil.show_changeset(ui, repo, {})
293 293 if len(nodes) == 1:
294 294 # narrowed it down to a single revision
295 295 if good:
296 296 ui.write(_("The first good revision is:\n"))
297 297 else:
298 298 ui.write(_("The first bad revision is:\n"))
299 299 displayer.show(repo[nodes[0]])
300 300 else:
301 301 # multiple possible revisions
302 302 if good:
303 303 ui.write(_("Due to skipped revisions, the first "
304 304 "good revision could be any of:\n"))
305 305 else:
306 306 ui.write(_("Due to skipped revisions, the first "
307 307 "bad revision could be any of:\n"))
308 308 for n in nodes:
309 309 displayer.show(repo[n])
310 310 displayer.close()
311 311
312 312 def check_state(state, interactive=True):
313 313 if not state['good'] or not state['bad']:
314 314 if (good or bad or skip or reset) and interactive:
315 315 return
316 316 if not state['good']:
317 317 raise util.Abort(_('cannot bisect (no known good revisions)'))
318 318 else:
319 319 raise util.Abort(_('cannot bisect (no known bad revisions)'))
320 320 return True
321 321
322 322 # backward compatibility
323 323 if rev in "good bad reset init".split():
324 324 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
325 325 cmd, rev, extra = rev, extra, None
326 326 if cmd == "good":
327 327 good = True
328 328 elif cmd == "bad":
329 329 bad = True
330 330 else:
331 331 reset = True
332 332 elif extra or good + bad + skip + reset + bool(command) > 1:
333 333 raise util.Abort(_('incompatible arguments'))
334 334
335 335 if reset:
336 336 p = repo.join("bisect.state")
337 337 if os.path.exists(p):
338 338 os.unlink(p)
339 339 return
340 340
341 341 state = hbisect.load_state(repo)
342 342
343 343 if command:
344 344 changesets = 1
345 345 try:
346 346 while changesets:
347 347 # update state
348 348 status = util.system(command)
349 349 if status == 125:
350 350 transition = "skip"
351 351 elif status == 0:
352 352 transition = "good"
353 353 # status < 0 means process was killed
354 354 elif status == 127:
355 355 raise util.Abort(_("failed to execute %s") % command)
356 356 elif status < 0:
357 357 raise util.Abort(_("%s killed") % command)
358 358 else:
359 359 transition = "bad"
360 360 ctx = repo[rev or '.']
361 361 state[transition].append(ctx.node())
362 362 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
363 363 check_state(state, interactive=False)
364 364 # bisect
365 365 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
366 366 # update to next check
367 367 cmdutil.bail_if_changed(repo)
368 368 hg.clean(repo, nodes[0], show_stats=False)
369 369 finally:
370 370 hbisect.save_state(repo, state)
371 371 return print_result(nodes, good)
372 372
373 373 # update state
374 374 node = repo.lookup(rev or '.')
375 375 if good or bad or skip:
376 376 if good:
377 377 state['good'].append(node)
378 378 elif bad:
379 379 state['bad'].append(node)
380 380 elif skip:
381 381 state['skip'].append(node)
382 382 hbisect.save_state(repo, state)
383 383
384 384 if not check_state(state):
385 385 return
386 386
387 387 # actually bisect
388 388 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
389 389 if changesets == 0:
390 390 print_result(nodes, good)
391 391 else:
392 392 assert len(nodes) == 1 # only a single node can be tested next
393 393 node = nodes[0]
394 394 # compute the approximate number of remaining tests
395 395 tests, size = 0, 2
396 396 while size <= changesets:
397 397 tests, size = tests + 1, size * 2
398 398 rev = repo.changelog.rev(node)
399 399 ui.write(_("Testing changeset %d:%s "
400 400 "(%d changesets remaining, ~%d tests)\n")
401 401 % (rev, short(node), changesets, tests))
402 402 if not noupdate:
403 403 cmdutil.bail_if_changed(repo)
404 404 return hg.clean(repo, node)
405 405
406 406 def branch(ui, repo, label=None, **opts):
407 407 """set or show the current branch name
408 408
409 409 With no argument, show the current branch name. With one argument,
410 410 set the working directory branch name (the branch will not exist
411 411 in the repository until the next commit). Standard practice
412 412 recommends that primary development take place on the 'default'
413 413 branch.
414 414
415 415 Unless -f/--force is specified, branch will not let you set a
416 416 branch name that already exists, even if it's inactive.
417 417
418 418 Use -C/--clean to reset the working directory branch to that of
419 419 the parent of the working directory, negating a previous branch
420 420 change.
421 421
422 422 Use the command 'hg update' to switch to an existing branch. Use
423 423 'hg commit --close-branch' to mark this branch as closed.
424 424 """
425 425
426 426 if opts.get('clean'):
427 427 label = repo[None].parents()[0].branch()
428 428 repo.dirstate.setbranch(label)
429 429 ui.status(_('reset working directory to branch %s\n') % label)
430 430 elif label:
431 431 utflabel = encoding.fromlocal(label)
432 432 if not opts.get('force') and utflabel in repo.branchtags():
433 433 if label not in [p.branch() for p in repo.parents()]:
434 434 raise util.Abort(_('a branch of the same name already exists'
435 435 ' (use --force to override)'))
436 436 repo.dirstate.setbranch(utflabel)
437 437 ui.status(_('marked working directory as branch %s\n') % label)
438 438 else:
439 439 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
440 440
441 441 def branches(ui, repo, active=False, closed=False):
442 442 """list repository named branches
443 443
444 444 List the repository's named branches, indicating which ones are
445 445 inactive. If -c/--closed is specified, also list branches which have
446 446 been marked closed (see hg commit --close-branch).
447 447
448 448 If -a/--active is specified, only show active branches. A branch
449 449 is considered active if it contains repository heads.
450 450
451 451 Use the command 'hg update' to switch to an existing branch.
452 452 """
453 453
454 454 hexfunc = ui.debugflag and hex or short
455 455 activebranches = [repo[n].branch() for n in repo.heads()]
456 456 def testactive(tag, node):
457 457 realhead = tag in activebranches
458 458 open = node in repo.branchheads(tag, closed=False)
459 459 return realhead and open
460 460 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
461 461 for tag, node in repo.branchtags().items()],
462 462 reverse=True)
463 463
464 464 for isactive, node, tag in branches:
465 465 if (not active) or isactive:
466 466 encodedtag = encoding.tolocal(tag)
467 467 if ui.quiet:
468 468 ui.write("%s\n" % encodedtag)
469 469 else:
470 470 hn = repo.lookup(node)
471 471 if isactive:
472 472 notice = ''
473 473 elif hn not in repo.branchheads(tag, closed=False):
474 474 if not closed:
475 475 continue
476 476 notice = _(' (closed)')
477 477 else:
478 478 notice = _(' (inactive)')
479 479 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
480 480 data = encodedtag, rev, hexfunc(hn), notice
481 481 ui.write("%s %s:%s%s\n" % data)
482 482
483 483 def bundle(ui, repo, fname, dest=None, **opts):
484 484 """create a changegroup file
485 485
486 486 Generate a compressed changegroup file collecting changesets not
487 487 known to be in another repository.
488 488
489 489 If you omit the destination repository, then hg assumes the
490 490 destination will have all the nodes you specify with --base
491 491 parameters. To create a bundle containing all changesets, use
492 492 -a/--all (or --base null).
493 493
494 494 You can change compression method with the -t/--type option.
495 495 The available compression methods are: none, bzip2, and
496 496 gzip (by default, bundles are compressed using bzip2).
497 497
498 498 The bundle file can then be transferred using conventional means
499 499 and applied to another repository with the unbundle or pull
500 500 command. This is useful when direct push and pull are not
501 501 available or when exporting an entire repository is undesirable.
502 502
503 503 Applying bundles preserves all changeset contents including
504 504 permissions, copy/rename information, and revision history.
505 505 """
506 506 revs = opts.get('rev') or None
507 507 if revs:
508 508 revs = [repo.lookup(rev) for rev in revs]
509 509 if opts.get('all'):
510 510 base = ['null']
511 511 else:
512 512 base = opts.get('base')
513 513 if base:
514 514 if dest:
515 515 raise util.Abort(_("--base is incompatible with specifying "
516 516 "a destination"))
517 517 base = [repo.lookup(rev) for rev in base]
518 518 # create the right base
519 519 # XXX: nodesbetween / changegroup* should be "fixed" instead
520 520 o = []
521 521 has = set((nullid,))
522 522 for n in base:
523 523 has.update(repo.changelog.reachable(n))
524 524 if revs:
525 525 visit = list(revs)
526 526 else:
527 527 visit = repo.changelog.heads()
528 528 seen = {}
529 529 while visit:
530 530 n = visit.pop(0)
531 531 parents = [p for p in repo.changelog.parents(n) if p not in has]
532 532 if len(parents) == 0:
533 533 o.insert(0, n)
534 534 else:
535 535 for p in parents:
536 536 if p not in seen:
537 537 seen[p] = 1
538 538 visit.append(p)
539 539 else:
540 540 dest = ui.expandpath(dest or 'default-push', dest or 'default')
541 dest, branches = hg.parseurl(dest)
541 dest, branches = hg.parseurl(dest, opts.get('branch'))
542 542 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
543 543 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
544 544 o = repo.findoutgoing(other, force=opts.get('force'))
545 545
546 546 if revs:
547 547 cg = repo.changegroupsubset(o, revs, 'bundle')
548 548 else:
549 549 cg = repo.changegroup(o, 'bundle')
550 550
551 551 bundletype = opts.get('type', 'bzip2').lower()
552 552 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
553 553 bundletype = btypes.get(bundletype)
554 554 if bundletype not in changegroup.bundletypes:
555 555 raise util.Abort(_('unknown bundle type specified with --type'))
556 556
557 557 changegroup.writebundle(cg, fname, bundletype)
558 558
559 559 def cat(ui, repo, file1, *pats, **opts):
560 560 """output the current or given revision of files
561 561
562 562 Print the specified files as they were at the given revision. If
563 563 no revision is given, the parent of the working directory is used,
564 564 or tip if no revision is checked out.
565 565
566 566 Output may be to a file, in which case the name of the file is
567 567 given using a format string. The formatting rules are the same as
568 568 for the export command, with the following additions:
569 569
570 570 :``%s``: basename of file being printed
571 571 :``%d``: dirname of file being printed, or '.' if in repository root
572 572 :``%p``: root-relative path name of file being printed
573 573 """
574 574 ctx = repo[opts.get('rev')]
575 575 err = 1
576 576 m = cmdutil.match(repo, (file1,) + pats, opts)
577 577 for abs in ctx.walk(m):
578 578 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
579 579 data = ctx[abs].data()
580 580 if opts.get('decode'):
581 581 data = repo.wwritedata(abs, data)
582 582 fp.write(data)
583 583 err = 0
584 584 return err
585 585
586 586 def clone(ui, source, dest=None, **opts):
587 587 """make a copy of an existing repository
588 588
589 589 Create a copy of an existing repository in a new directory.
590 590
591 591 If no destination directory name is specified, it defaults to the
592 592 basename of the source.
593 593
594 594 The location of the source is added to the new repository's
595 595 .hg/hgrc file, as the default to be used for future pulls.
596 596
597 597 See 'hg help urls' for valid source format details.
598 598
599 599 It is possible to specify an ``ssh://`` URL as the destination, but no
600 600 .hg/hgrc and working directory will be created on the remote side.
601 601 Please see 'hg help urls' for important details about ``ssh://`` URLs.
602 602
603 603 If the -U/--noupdate option is specified, the new clone will contain
604 604 only a repository (.hg) and no working copy (the working copy parent
605 605 will be the null changeset). Otherwise, clone will initially check
606 606 out (in order of precedence):
607 607
608 608 a) the changeset, tag or branch specified with -u/--updaterev
609 609 b) the changeset, tag or branch given with the first -r/--rev
610 c) the branch given with the url#branch source syntax
611 d) the head of the default branch
610 c) the branch given with the first -b/--branch
611 d) the branch given with the url#branch source syntax
612 e) the head of the default branch
612 613
613 614 Use 'hg clone -u . src dst' to checkout the source repository's
614 615 parent changeset (applicable for local source repositories only).
615 616
616 617 A set of changesets (tags, or branch names) to pull may be specified
617 618 by listing each changeset (tag, or branch name) with -r/--rev.
618 619 If -r/--rev is used, the cloned repository will contain only a subset
619 620 of the changesets of the source repository. Only the set of changesets
620 621 defined by all -r/--rev options (including all their ancestors)
621 622 will be pulled into the destination repository.
622 623 No subsequent changesets (including subsequent tags) will be present
623 624 in the destination.
624 625
625 626 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
626 627 local source repositories.
627 628
628 629 For efficiency, hardlinks are used for cloning whenever the source
629 630 and destination are on the same filesystem (note this applies only
630 631 to the repository data, not to the checked out files). Some
631 632 filesystems, such as AFS, implement hardlinking incorrectly, but
632 633 do not report errors. In these cases, use the --pull option to
633 634 avoid hardlinking.
634 635
635 636 In some cases, you can clone repositories and checked out files
636 637 using full hardlinks with ::
637 638
638 639 $ cp -al REPO REPOCLONE
639 640
640 641 This is the fastest way to clone, but it is not always safe. The
641 642 operation is not atomic (making sure REPO is not modified during
642 643 the operation is up to you) and you have to make sure your editor
643 644 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
644 645 this is not compatible with certain extensions that place their
645 646 metadata under the .hg directory, such as mq.
646 647 """
647 648 if opts.get('noupdate') and opts.get('updaterev'):
648 649 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
649 650
650 651 hg.clone(cmdutil.remoteui(ui, opts), source, dest,
651 652 pull=opts.get('pull'),
652 653 stream=opts.get('uncompressed'),
653 654 rev=opts.get('rev'),
654 update=opts.get('updaterev') or not opts.get('noupdate'))
655 update=opts.get('updaterev') or not opts.get('noupdate'),
656 branch=opts.get('branch'))
655 657
656 658 def commit(ui, repo, *pats, **opts):
657 659 """commit the specified files or all outstanding changes
658 660
659 661 Commit changes to the given files into the repository. Unlike a
660 662 centralized RCS, this operation is a local operation. See hg push
661 663 for a way to actively distribute your changes.
662 664
663 665 If a list of files is omitted, all changes reported by "hg status"
664 666 will be committed.
665 667
666 668 If you are committing the result of a merge, do not provide any
667 669 filenames or -I/-X filters.
668 670
669 671 If no commit message is specified, the configured editor is
670 672 started to prompt you for a message.
671 673
672 674 See 'hg help dates' for a list of formats valid for -d/--date.
673 675 """
674 676 extra = {}
675 677 if opts.get('close_branch'):
676 678 extra['close'] = 1
677 679 e = cmdutil.commiteditor
678 680 if opts.get('force_editor'):
679 681 e = cmdutil.commitforceeditor
680 682
681 683 def commitfunc(ui, repo, message, match, opts):
682 684 return repo.commit(message, opts.get('user'), opts.get('date'), match,
683 685 editor=e, extra=extra)
684 686
685 687 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
686 688 if not node:
687 689 ui.status(_("nothing changed\n"))
688 690 return
689 691 cl = repo.changelog
690 692 rev = cl.rev(node)
691 693 parents = cl.parentrevs(rev)
692 694 if rev - 1 in parents:
693 695 # one of the parents was the old tip
694 696 pass
695 697 elif (parents == (nullrev, nullrev) or
696 698 len(cl.heads(cl.node(parents[0]))) > 1 and
697 699 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
698 700 ui.status(_('created new head\n'))
699 701
700 702 if ui.debugflag:
701 703 ui.write(_('committed changeset %d:%s\n') % (rev, hex(node)))
702 704 elif ui.verbose:
703 705 ui.write(_('committed changeset %d:%s\n') % (rev, short(node)))
704 706
705 707 def copy(ui, repo, *pats, **opts):
706 708 """mark files as copied for the next commit
707 709
708 710 Mark dest as having copies of source files. If dest is a
709 711 directory, copies are put in that directory. If dest is a file,
710 712 the source must be a single file.
711 713
712 714 By default, this command copies the contents of files as they
713 715 exist in the working directory. If invoked with -A/--after, the
714 716 operation is recorded, but no copying is performed.
715 717
716 718 This command takes effect with the next commit. To undo a copy
717 719 before that, see hg revert.
718 720 """
719 721 wlock = repo.wlock(False)
720 722 try:
721 723 return cmdutil.copy(ui, repo, pats, opts)
722 724 finally:
723 725 wlock.release()
724 726
725 727 def debugancestor(ui, repo, *args):
726 728 """find the ancestor revision of two revisions in a given index"""
727 729 if len(args) == 3:
728 730 index, rev1, rev2 = args
729 731 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
730 732 lookup = r.lookup
731 733 elif len(args) == 2:
732 734 if not repo:
733 735 raise util.Abort(_("There is no Mercurial repository here "
734 736 "(.hg not found)"))
735 737 rev1, rev2 = args
736 738 r = repo.changelog
737 739 lookup = repo.lookup
738 740 else:
739 741 raise util.Abort(_('either two or three arguments required'))
740 742 a = r.ancestor(lookup(rev1), lookup(rev2))
741 743 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
742 744
743 745 def debugcommands(ui, cmd='', *args):
744 746 for cmd, vals in sorted(table.iteritems()):
745 747 cmd = cmd.split('|')[0].strip('^')
746 748 opts = ', '.join([i[1] for i in vals[1]])
747 749 ui.write('%s: %s\n' % (cmd, opts))
748 750
749 751 def debugcomplete(ui, cmd='', **opts):
750 752 """returns the completion list associated with the given command"""
751 753
752 754 if opts.get('options'):
753 755 options = []
754 756 otables = [globalopts]
755 757 if cmd:
756 758 aliases, entry = cmdutil.findcmd(cmd, table, False)
757 759 otables.append(entry[1])
758 760 for t in otables:
759 761 for o in t:
760 762 if o[0]:
761 763 options.append('-%s' % o[0])
762 764 options.append('--%s' % o[1])
763 765 ui.write("%s\n" % "\n".join(options))
764 766 return
765 767
766 768 cmdlist = cmdutil.findpossible(cmd, table)
767 769 if ui.verbose:
768 770 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
769 771 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
770 772
771 773 def debugfsinfo(ui, path = "."):
772 774 open('.debugfsinfo', 'w').write('')
773 775 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
774 776 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
775 777 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
776 778 and 'yes' or 'no'))
777 779 os.unlink('.debugfsinfo')
778 780
779 781 def debugrebuildstate(ui, repo, rev="tip"):
780 782 """rebuild the dirstate as it would look like for the given revision"""
781 783 ctx = repo[rev]
782 784 wlock = repo.wlock()
783 785 try:
784 786 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
785 787 finally:
786 788 wlock.release()
787 789
788 790 def debugcheckstate(ui, repo):
789 791 """validate the correctness of the current dirstate"""
790 792 parent1, parent2 = repo.dirstate.parents()
791 793 m1 = repo[parent1].manifest()
792 794 m2 = repo[parent2].manifest()
793 795 errors = 0
794 796 for f in repo.dirstate:
795 797 state = repo.dirstate[f]
796 798 if state in "nr" and f not in m1:
797 799 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
798 800 errors += 1
799 801 if state in "a" and f in m1:
800 802 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
801 803 errors += 1
802 804 if state in "m" and f not in m1 and f not in m2:
803 805 ui.warn(_("%s in state %s, but not in either manifest\n") %
804 806 (f, state))
805 807 errors += 1
806 808 for f in m1:
807 809 state = repo.dirstate[f]
808 810 if state not in "nrm":
809 811 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
810 812 errors += 1
811 813 if errors:
812 814 error = _(".hg/dirstate inconsistent with current parent's manifest")
813 815 raise util.Abort(error)
814 816
815 817 def showconfig(ui, repo, *values, **opts):
816 818 """show combined config settings from all hgrc files
817 819
818 820 With no arguments, print names and values of all config items.
819 821
820 822 With one argument of the form section.name, print just the value
821 823 of that config item.
822 824
823 825 With multiple arguments, print names and values of all config
824 826 items with matching section names.
825 827
826 828 With --debug, the source (filename and line number) is printed
827 829 for each config item.
828 830 """
829 831
830 832 untrusted = bool(opts.get('untrusted'))
831 833 if values:
832 834 if len([v for v in values if '.' in v]) > 1:
833 835 raise util.Abort(_('only one config item permitted'))
834 836 for section, name, value in ui.walkconfig(untrusted=untrusted):
835 837 sectname = section + '.' + name
836 838 if values:
837 839 for v in values:
838 840 if v == section:
839 841 ui.debug('%s: ' %
840 842 ui.configsource(section, name, untrusted))
841 843 ui.write('%s=%s\n' % (sectname, value))
842 844 elif v == sectname:
843 845 ui.debug('%s: ' %
844 846 ui.configsource(section, name, untrusted))
845 847 ui.write(value, '\n')
846 848 else:
847 849 ui.debug('%s: ' %
848 850 ui.configsource(section, name, untrusted))
849 851 ui.write('%s=%s\n' % (sectname, value))
850 852
851 853 def debugsetparents(ui, repo, rev1, rev2=None):
852 854 """manually set the parents of the current working directory
853 855
854 856 This is useful for writing repository conversion tools, but should
855 857 be used with care.
856 858 """
857 859
858 860 if not rev2:
859 861 rev2 = hex(nullid)
860 862
861 863 wlock = repo.wlock()
862 864 try:
863 865 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
864 866 finally:
865 867 wlock.release()
866 868
867 869 def debugstate(ui, repo, nodates=None):
868 870 """show the contents of the current dirstate"""
869 871 timestr = ""
870 872 showdate = not nodates
871 873 for file_, ent in sorted(repo.dirstate._map.iteritems()):
872 874 if showdate:
873 875 if ent[3] == -1:
874 876 # Pad or slice to locale representation
875 877 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
876 878 time.localtime(0)))
877 879 timestr = 'unset'
878 880 timestr = (timestr[:locale_len] +
879 881 ' ' * (locale_len - len(timestr)))
880 882 else:
881 883 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
882 884 time.localtime(ent[3]))
883 885 if ent[1] & 020000:
884 886 mode = 'lnk'
885 887 else:
886 888 mode = '%3o' % (ent[1] & 0777)
887 889 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
888 890 for f in repo.dirstate.copies():
889 891 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
890 892
891 893 def debugsub(ui, repo, rev=None):
892 894 if rev == '':
893 895 rev = None
894 896 for k, v in sorted(repo[rev].substate.items()):
895 897 ui.write('path %s\n' % k)
896 898 ui.write(' source %s\n' % v[0])
897 899 ui.write(' revision %s\n' % v[1])
898 900
899 901 def debugdata(ui, file_, rev):
900 902 """dump the contents of a data file revision"""
901 903 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
902 904 try:
903 905 ui.write(r.revision(r.lookup(rev)))
904 906 except KeyError:
905 907 raise util.Abort(_('invalid revision identifier %s') % rev)
906 908
907 909 def debugdate(ui, date, range=None, **opts):
908 910 """parse and display a date"""
909 911 if opts["extended"]:
910 912 d = util.parsedate(date, util.extendeddateformats)
911 913 else:
912 914 d = util.parsedate(date)
913 915 ui.write("internal: %s %s\n" % d)
914 916 ui.write("standard: %s\n" % util.datestr(d))
915 917 if range:
916 918 m = util.matchdate(range)
917 919 ui.write("match: %s\n" % m(d[0]))
918 920
919 921 def debugindex(ui, file_):
920 922 """dump the contents of an index file"""
921 923 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
922 924 ui.write(" rev offset length base linkrev"
923 925 " nodeid p1 p2\n")
924 926 for i in r:
925 927 node = r.node(i)
926 928 try:
927 929 pp = r.parents(node)
928 930 except:
929 931 pp = [nullid, nullid]
930 932 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
931 933 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
932 934 short(node), short(pp[0]), short(pp[1])))
933 935
934 936 def debugindexdot(ui, file_):
935 937 """dump an index DAG as a graphviz dot file"""
936 938 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
937 939 ui.write("digraph G {\n")
938 940 for i in r:
939 941 node = r.node(i)
940 942 pp = r.parents(node)
941 943 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
942 944 if pp[1] != nullid:
943 945 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
944 946 ui.write("}\n")
945 947
946 948 def debuginstall(ui):
947 949 '''test Mercurial installation'''
948 950
949 951 def writetemp(contents):
950 952 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
951 953 f = os.fdopen(fd, "wb")
952 954 f.write(contents)
953 955 f.close()
954 956 return name
955 957
956 958 problems = 0
957 959
958 960 # encoding
959 961 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
960 962 try:
961 963 encoding.fromlocal("test")
962 964 except util.Abort, inst:
963 965 ui.write(" %s\n" % inst)
964 966 ui.write(_(" (check that your locale is properly set)\n"))
965 967 problems += 1
966 968
967 969 # compiled modules
968 970 ui.status(_("Checking extensions...\n"))
969 971 try:
970 972 import bdiff, mpatch, base85
971 973 except Exception, inst:
972 974 ui.write(" %s\n" % inst)
973 975 ui.write(_(" One or more extensions could not be found"))
974 976 ui.write(_(" (check that you compiled the extensions)\n"))
975 977 problems += 1
976 978
977 979 # templates
978 980 ui.status(_("Checking templates...\n"))
979 981 try:
980 982 import templater
981 983 templater.templater(templater.templatepath("map-cmdline.default"))
982 984 except Exception, inst:
983 985 ui.write(" %s\n" % inst)
984 986 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
985 987 problems += 1
986 988
987 989 # patch
988 990 ui.status(_("Checking patch...\n"))
989 991 patchproblems = 0
990 992 a = "1\n2\n3\n4\n"
991 993 b = "1\n2\n3\ninsert\n4\n"
992 994 fa = writetemp(a)
993 995 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
994 996 os.path.basename(fa))
995 997 fd = writetemp(d)
996 998
997 999 files = {}
998 1000 try:
999 1001 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1000 1002 except util.Abort, e:
1001 1003 ui.write(_(" patch call failed:\n"))
1002 1004 ui.write(" " + str(e) + "\n")
1003 1005 patchproblems += 1
1004 1006 else:
1005 1007 if list(files) != [os.path.basename(fa)]:
1006 1008 ui.write(_(" unexpected patch output!\n"))
1007 1009 patchproblems += 1
1008 1010 a = open(fa).read()
1009 1011 if a != b:
1010 1012 ui.write(_(" patch test failed!\n"))
1011 1013 patchproblems += 1
1012 1014
1013 1015 if patchproblems:
1014 1016 if ui.config('ui', 'patch'):
1015 1017 ui.write(_(" (Current patch tool may be incompatible with patch,"
1016 1018 " or misconfigured. Please check your .hgrc file)\n"))
1017 1019 else:
1018 1020 ui.write(_(" Internal patcher failure, please report this error"
1019 1021 " to http://mercurial.selenic.com/bts/\n"))
1020 1022 problems += patchproblems
1021 1023
1022 1024 os.unlink(fa)
1023 1025 os.unlink(fd)
1024 1026
1025 1027 # editor
1026 1028 ui.status(_("Checking commit editor...\n"))
1027 1029 editor = ui.geteditor()
1028 1030 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1029 1031 if not cmdpath:
1030 1032 if editor == 'vi':
1031 1033 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1032 1034 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1033 1035 else:
1034 1036 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1035 1037 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
1036 1038 problems += 1
1037 1039
1038 1040 # check username
1039 1041 ui.status(_("Checking username...\n"))
1040 1042 try:
1041 1043 user = ui.username()
1042 1044 except util.Abort, e:
1043 1045 ui.write(" %s\n" % e)
1044 1046 ui.write(_(" (specify a username in your .hgrc file)\n"))
1045 1047 problems += 1
1046 1048
1047 1049 if not problems:
1048 1050 ui.status(_("No problems detected\n"))
1049 1051 else:
1050 1052 ui.write(_("%s problems detected,"
1051 1053 " please check your install!\n") % problems)
1052 1054
1053 1055 return problems
1054 1056
1055 1057 def debugrename(ui, repo, file1, *pats, **opts):
1056 1058 """dump rename information"""
1057 1059
1058 1060 ctx = repo[opts.get('rev')]
1059 1061 m = cmdutil.match(repo, (file1,) + pats, opts)
1060 1062 for abs in ctx.walk(m):
1061 1063 fctx = ctx[abs]
1062 1064 o = fctx.filelog().renamed(fctx.filenode())
1063 1065 rel = m.rel(abs)
1064 1066 if o:
1065 1067 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1066 1068 else:
1067 1069 ui.write(_("%s not renamed\n") % rel)
1068 1070
1069 1071 def debugwalk(ui, repo, *pats, **opts):
1070 1072 """show how files match on given patterns"""
1071 1073 m = cmdutil.match(repo, pats, opts)
1072 1074 items = list(repo.walk(m))
1073 1075 if not items:
1074 1076 return
1075 1077 fmt = 'f %%-%ds %%-%ds %%s' % (
1076 1078 max([len(abs) for abs in items]),
1077 1079 max([len(m.rel(abs)) for abs in items]))
1078 1080 for abs in items:
1079 1081 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1080 1082 ui.write("%s\n" % line.rstrip())
1081 1083
1082 1084 def diff(ui, repo, *pats, **opts):
1083 1085 """diff repository (or selected files)
1084 1086
1085 1087 Show differences between revisions for the specified files.
1086 1088
1087 1089 Differences between files are shown using the unified diff format.
1088 1090
1089 1091 NOTE: diff may generate unexpected results for merges, as it will
1090 1092 default to comparing against the working directory's first parent
1091 1093 changeset if no revisions are specified.
1092 1094
1093 1095 When two revision arguments are given, then changes are shown
1094 1096 between those revisions. If only one revision is specified then
1095 1097 that revision is compared to the working directory, and, when no
1096 1098 revisions are specified, the working directory files are compared
1097 1099 to its parent.
1098 1100
1099 1101 Without the -a/--text option, diff will avoid generating diffs of
1100 1102 files it detects as binary. With -a, diff will generate a diff
1101 1103 anyway, probably with undesirable results.
1102 1104
1103 1105 Use the -g/--git option to generate diffs in the git extended diff
1104 1106 format. For more information, read 'hg help diffs'.
1105 1107 """
1106 1108
1107 1109 revs = opts.get('rev')
1108 1110 change = opts.get('change')
1109 1111 stat = opts.get('stat')
1110 1112 reverse = opts.get('reverse')
1111 1113
1112 1114 if revs and change:
1113 1115 msg = _('cannot specify --rev and --change at the same time')
1114 1116 raise util.Abort(msg)
1115 1117 elif change:
1116 1118 node2 = repo.lookup(change)
1117 1119 node1 = repo[node2].parents()[0].node()
1118 1120 else:
1119 1121 node1, node2 = cmdutil.revpair(repo, revs)
1120 1122
1121 1123 if reverse:
1122 1124 node1, node2 = node2, node1
1123 1125
1124 1126 if stat:
1125 1127 opts['unified'] = '0'
1126 1128 diffopts = patch.diffopts(ui, opts)
1127 1129
1128 1130 m = cmdutil.match(repo, pats, opts)
1129 1131 it = patch.diff(repo, node1, node2, match=m, opts=diffopts)
1130 1132 if stat:
1131 1133 width = ui.interactive() and util.termwidth() or 80
1132 1134 ui.write(patch.diffstat(util.iterlines(it), width=width,
1133 1135 git=diffopts.git))
1134 1136 else:
1135 1137 for chunk in it:
1136 1138 ui.write(chunk)
1137 1139
1138 1140 def export(ui, repo, *changesets, **opts):
1139 1141 """dump the header and diffs for one or more changesets
1140 1142
1141 1143 Print the changeset header and diffs for one or more revisions.
1142 1144
1143 1145 The information shown in the changeset header is: author, date,
1144 1146 branch name (if non-default), changeset hash, parent(s) and commit
1145 1147 comment.
1146 1148
1147 1149 NOTE: export may generate unexpected diff output for merge
1148 1150 changesets, as it will compare the merge changeset against its
1149 1151 first parent only.
1150 1152
1151 1153 Output may be to a file, in which case the name of the file is
1152 1154 given using a format string. The formatting rules are as follows:
1153 1155
1154 1156 :``%%``: literal "%" character
1155 1157 :``%H``: changeset hash (40 bytes of hexadecimal)
1156 1158 :``%N``: number of patches being generated
1157 1159 :``%R``: changeset revision number
1158 1160 :``%b``: basename of the exporting repository
1159 1161 :``%h``: short-form changeset hash (12 bytes of hexadecimal)
1160 1162 :``%n``: zero-padded sequence number, starting at 1
1161 1163 :``%r``: zero-padded changeset revision number
1162 1164
1163 1165 Without the -a/--text option, export will avoid generating diffs
1164 1166 of files it detects as binary. With -a, export will generate a
1165 1167 diff anyway, probably with undesirable results.
1166 1168
1167 1169 Use the -g/--git option to generate diffs in the git extended diff
1168 1170 format. See 'hg help diffs' for more information.
1169 1171
1170 1172 With the --switch-parent option, the diff will be against the
1171 1173 second parent. It can be useful to review a merge.
1172 1174 """
1173 1175 changesets += tuple(opts.get('rev', []))
1174 1176 if not changesets:
1175 1177 raise util.Abort(_("export requires at least one changeset"))
1176 1178 revs = cmdutil.revrange(repo, changesets)
1177 1179 if len(revs) > 1:
1178 1180 ui.note(_('exporting patches:\n'))
1179 1181 else:
1180 1182 ui.note(_('exporting patch:\n'))
1181 1183 patch.export(repo, revs, template=opts.get('output'),
1182 1184 switch_parent=opts.get('switch_parent'),
1183 1185 opts=patch.diffopts(ui, opts))
1184 1186
1185 1187 def forget(ui, repo, *pats, **opts):
1186 1188 """forget the specified files on the next commit
1187 1189
1188 1190 Mark the specified files so they will no longer be tracked
1189 1191 after the next commit.
1190 1192
1191 1193 This only removes files from the current branch, not from the
1192 1194 entire project history, and it does not delete them from the
1193 1195 working directory.
1194 1196
1195 1197 To undo a forget before the next commit, see hg add.
1196 1198 """
1197 1199
1198 1200 if not pats:
1199 1201 raise util.Abort(_('no files specified'))
1200 1202
1201 1203 m = cmdutil.match(repo, pats, opts)
1202 1204 s = repo.status(match=m, clean=True)
1203 1205 forget = sorted(s[0] + s[1] + s[3] + s[6])
1204 1206
1205 1207 for f in m.files():
1206 1208 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1207 1209 ui.warn(_('not removing %s: file is already untracked\n')
1208 1210 % m.rel(f))
1209 1211
1210 1212 for f in forget:
1211 1213 if ui.verbose or not m.exact(f):
1212 1214 ui.status(_('removing %s\n') % m.rel(f))
1213 1215
1214 1216 repo.remove(forget, unlink=False)
1215 1217
1216 1218 def grep(ui, repo, pattern, *pats, **opts):
1217 1219 """search for a pattern in specified files and revisions
1218 1220
1219 1221 Search revisions of files for a regular expression.
1220 1222
1221 1223 This command behaves differently than Unix grep. It only accepts
1222 1224 Python/Perl regexps. It searches repository history, not the
1223 1225 working directory. It always prints the revision number in which a
1224 1226 match appears.
1225 1227
1226 1228 By default, grep only prints output for the first revision of a
1227 1229 file in which it finds a match. To get it to print every revision
1228 1230 that contains a change in match status ("-" for a match that
1229 1231 becomes a non-match, or "+" for a non-match that becomes a match),
1230 1232 use the --all flag.
1231 1233 """
1232 1234 reflags = 0
1233 1235 if opts.get('ignore_case'):
1234 1236 reflags |= re.I
1235 1237 try:
1236 1238 regexp = re.compile(pattern, reflags)
1237 1239 except Exception, inst:
1238 1240 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1239 1241 return None
1240 1242 sep, eol = ':', '\n'
1241 1243 if opts.get('print0'):
1242 1244 sep = eol = '\0'
1243 1245
1244 1246 getfile = util.lrucachefunc(repo.file)
1245 1247
1246 1248 def matchlines(body):
1247 1249 begin = 0
1248 1250 linenum = 0
1249 1251 while True:
1250 1252 match = regexp.search(body, begin)
1251 1253 if not match:
1252 1254 break
1253 1255 mstart, mend = match.span()
1254 1256 linenum += body.count('\n', begin, mstart) + 1
1255 1257 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1256 1258 begin = body.find('\n', mend) + 1 or len(body)
1257 1259 lend = begin - 1
1258 1260 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1259 1261
1260 1262 class linestate(object):
1261 1263 def __init__(self, line, linenum, colstart, colend):
1262 1264 self.line = line
1263 1265 self.linenum = linenum
1264 1266 self.colstart = colstart
1265 1267 self.colend = colend
1266 1268
1267 1269 def __hash__(self):
1268 1270 return hash((self.linenum, self.line))
1269 1271
1270 1272 def __eq__(self, other):
1271 1273 return self.line == other.line
1272 1274
1273 1275 matches = {}
1274 1276 copies = {}
1275 1277 def grepbody(fn, rev, body):
1276 1278 matches[rev].setdefault(fn, [])
1277 1279 m = matches[rev][fn]
1278 1280 for lnum, cstart, cend, line in matchlines(body):
1279 1281 s = linestate(line, lnum, cstart, cend)
1280 1282 m.append(s)
1281 1283
1282 1284 def difflinestates(a, b):
1283 1285 sm = difflib.SequenceMatcher(None, a, b)
1284 1286 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1285 1287 if tag == 'insert':
1286 1288 for i in xrange(blo, bhi):
1287 1289 yield ('+', b[i])
1288 1290 elif tag == 'delete':
1289 1291 for i in xrange(alo, ahi):
1290 1292 yield ('-', a[i])
1291 1293 elif tag == 'replace':
1292 1294 for i in xrange(alo, ahi):
1293 1295 yield ('-', a[i])
1294 1296 for i in xrange(blo, bhi):
1295 1297 yield ('+', b[i])
1296 1298
1297 1299 def display(fn, ctx, pstates, states):
1298 1300 rev = ctx.rev()
1299 1301 datefunc = ui.quiet and util.shortdate or util.datestr
1300 1302 found = False
1301 1303 filerevmatches = {}
1302 1304 if opts.get('all'):
1303 1305 iter = difflinestates(pstates, states)
1304 1306 else:
1305 1307 iter = [('', l) for l in states]
1306 1308 for change, l in iter:
1307 1309 cols = [fn, str(rev)]
1308 1310 if opts.get('line_number'):
1309 1311 cols.append(str(l.linenum))
1310 1312 if opts.get('all'):
1311 1313 cols.append(change)
1312 1314 if opts.get('user'):
1313 1315 cols.append(ui.shortuser(ctx.user()))
1314 1316 if opts.get('date'):
1315 1317 cols.append(datefunc(ctx.date()))
1316 1318 if opts.get('files_with_matches'):
1317 1319 c = (fn, rev)
1318 1320 if c in filerevmatches:
1319 1321 continue
1320 1322 filerevmatches[c] = 1
1321 1323 else:
1322 1324 cols.append(l.line)
1323 1325 ui.write(sep.join(cols), eol)
1324 1326 found = True
1325 1327 return found
1326 1328
1327 1329 skip = {}
1328 1330 revfiles = {}
1329 1331 matchfn = cmdutil.match(repo, pats, opts)
1330 1332 found = False
1331 1333 follow = opts.get('follow')
1332 1334
1333 1335 def prep(ctx, fns):
1334 1336 rev = ctx.rev()
1335 1337 pctx = ctx.parents()[0]
1336 1338 parent = pctx.rev()
1337 1339 matches.setdefault(rev, {})
1338 1340 matches.setdefault(parent, {})
1339 1341 files = revfiles.setdefault(rev, [])
1340 1342 for fn in fns:
1341 1343 flog = getfile(fn)
1342 1344 try:
1343 1345 fnode = ctx.filenode(fn)
1344 1346 except error.LookupError:
1345 1347 continue
1346 1348
1347 1349 copied = flog.renamed(fnode)
1348 1350 copy = follow and copied and copied[0]
1349 1351 if copy:
1350 1352 copies.setdefault(rev, {})[fn] = copy
1351 1353 if fn in skip:
1352 1354 if copy:
1353 1355 skip[copy] = True
1354 1356 continue
1355 1357 files.append(fn)
1356 1358
1357 1359 if fn not in matches[rev]:
1358 1360 grepbody(fn, rev, flog.read(fnode))
1359 1361
1360 1362 pfn = copy or fn
1361 1363 if pfn not in matches[parent]:
1362 1364 try:
1363 1365 fnode = pctx.filenode(pfn)
1364 1366 grepbody(pfn, parent, flog.read(fnode))
1365 1367 except error.LookupError:
1366 1368 pass
1367 1369
1368 1370 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1369 1371 rev = ctx.rev()
1370 1372 parent = ctx.parents()[0].rev()
1371 1373 for fn in sorted(revfiles.get(rev, [])):
1372 1374 states = matches[rev][fn]
1373 1375 copy = copies.get(rev, {}).get(fn)
1374 1376 if fn in skip:
1375 1377 if copy:
1376 1378 skip[copy] = True
1377 1379 continue
1378 1380 pstates = matches.get(parent, {}).get(copy or fn, [])
1379 1381 if pstates or states:
1380 1382 r = display(fn, ctx, pstates, states)
1381 1383 found = found or r
1382 1384 if r and not opts.get('all'):
1383 1385 skip[fn] = True
1384 1386 if copy:
1385 1387 skip[copy] = True
1386 1388 del matches[rev]
1387 1389 del revfiles[rev]
1388 1390
1389 1391 def heads(ui, repo, *branchrevs, **opts):
1390 1392 """show current repository heads or show branch heads
1391 1393
1392 1394 With no arguments, show all repository branch heads.
1393 1395
1394 1396 Repository "heads" are changesets with no child changesets. They are
1395 1397 where development generally takes place and are the usual targets
1396 1398 for update and merge operations. Branch heads are changesets that have
1397 1399 no child changeset on the same branch.
1398 1400
1399 1401 If one or more REVs are given, only branch heads on the branches
1400 1402 associated with the specified changesets are shown.
1401 1403
1402 1404 If -c/--closed is specified, also show branch heads marked closed
1403 1405 (see hg commit --close-branch).
1404 1406
1405 1407 If STARTREV is specified, only those heads that are descendants of
1406 1408 STARTREV will be displayed.
1407 1409
1408 1410 If -t/--topo is specified, named branch mechanics will be ignored and only
1409 1411 changesets without children will be shown.
1410 1412 """
1411 1413
1412 1414 if opts.get('rev'):
1413 1415 start = repo.lookup(opts['rev'])
1414 1416 else:
1415 1417 start = None
1416 1418
1417 1419 if opts.get('topo'):
1418 1420 heads = [repo[h] for h in repo.heads(start)]
1419 1421 else:
1420 1422 heads = []
1421 1423 for b, ls in repo.branchmap().iteritems():
1422 1424 if start is None:
1423 1425 heads += [repo[h] for h in ls]
1424 1426 continue
1425 1427 startrev = repo.changelog.rev(start)
1426 1428 descendants = set(repo.changelog.descendants(startrev))
1427 1429 descendants.add(startrev)
1428 1430 rev = repo.changelog.rev
1429 1431 heads += [repo[h] for h in ls if rev(h) in descendants]
1430 1432
1431 1433 if branchrevs:
1432 1434 decode, encode = encoding.fromlocal, encoding.tolocal
1433 1435 branches = set(repo[decode(br)].branch() for br in branchrevs)
1434 1436 heads = [h for h in heads if h.branch() in branches]
1435 1437
1436 1438 if not opts.get('closed'):
1437 1439 heads = [h for h in heads if not h.extra().get('close')]
1438 1440
1439 1441 if opts.get('active') and branchrevs:
1440 1442 dagheads = repo.heads(start)
1441 1443 heads = [h for h in heads if h.node() in dagheads]
1442 1444
1443 1445 if branchrevs:
1444 1446 haveheads = set(h.branch() for h in heads)
1445 1447 if branches - haveheads:
1446 1448 headless = ', '.join(encode(b) for b in branches - haveheads)
1447 1449 msg = _('no open branch heads found on branches %s')
1448 1450 if opts.get('rev'):
1449 1451 msg += _(' (started at %s)' % opts['rev'])
1450 1452 ui.warn((msg + '\n') % headless)
1451 1453
1452 1454 if not heads:
1453 1455 return 1
1454 1456
1455 1457 heads = sorted(heads, key=lambda x: -x.rev())
1456 1458 displayer = cmdutil.show_changeset(ui, repo, opts)
1457 1459 for ctx in heads:
1458 1460 displayer.show(ctx)
1459 1461 displayer.close()
1460 1462
1461 1463 def help_(ui, name=None, with_version=False, unknowncmd=False):
1462 1464 """show help for a given topic or a help overview
1463 1465
1464 1466 With no arguments, print a list of commands with short help messages.
1465 1467
1466 1468 Given a topic, extension, or command name, print help for that
1467 1469 topic."""
1468 1470 option_lists = []
1469 1471 textwidth = util.termwidth() - 2
1470 1472
1471 1473 def addglobalopts(aliases):
1472 1474 if ui.verbose:
1473 1475 option_lists.append((_("global options:"), globalopts))
1474 1476 if name == 'shortlist':
1475 1477 option_lists.append((_('use "hg help" for the full list '
1476 1478 'of commands'), ()))
1477 1479 else:
1478 1480 if name == 'shortlist':
1479 1481 msg = _('use "hg help" for the full list of commands '
1480 1482 'or "hg -v" for details')
1481 1483 elif aliases:
1482 1484 msg = _('use "hg -v help%s" to show aliases and '
1483 1485 'global options') % (name and " " + name or "")
1484 1486 else:
1485 1487 msg = _('use "hg -v help %s" to show global options') % name
1486 1488 option_lists.append((msg, ()))
1487 1489
1488 1490 def helpcmd(name):
1489 1491 if with_version:
1490 1492 version_(ui)
1491 1493 ui.write('\n')
1492 1494
1493 1495 try:
1494 1496 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1495 1497 except error.AmbiguousCommand, inst:
1496 1498 # py3k fix: except vars can't be used outside the scope of the
1497 1499 # except block, nor can be used inside a lambda. python issue4617
1498 1500 prefix = inst.args[0]
1499 1501 select = lambda c: c.lstrip('^').startswith(prefix)
1500 1502 helplist(_('list of commands:\n\n'), select)
1501 1503 return
1502 1504
1503 1505 # check if it's an invalid alias and display its error if it is
1504 1506 if getattr(entry[0], 'badalias', False):
1505 1507 if not unknowncmd:
1506 1508 entry[0](ui)
1507 1509 return
1508 1510
1509 1511 # synopsis
1510 1512 if len(entry) > 2:
1511 1513 if entry[2].startswith('hg'):
1512 1514 ui.write("%s\n" % entry[2])
1513 1515 else:
1514 1516 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1515 1517 else:
1516 1518 ui.write('hg %s\n' % aliases[0])
1517 1519
1518 1520 # aliases
1519 1521 if not ui.quiet and len(aliases) > 1:
1520 1522 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1521 1523
1522 1524 # description
1523 1525 doc = gettext(entry[0].__doc__)
1524 1526 if not doc:
1525 1527 doc = _("(no help text available)")
1526 1528 if ui.quiet:
1527 1529 doc = doc.splitlines()[0]
1528 1530 ui.write("\n%s\n" % minirst.format(doc, textwidth))
1529 1531
1530 1532 if not ui.quiet:
1531 1533 # options
1532 1534 if entry[1]:
1533 1535 option_lists.append((_("options:\n"), entry[1]))
1534 1536
1535 1537 addglobalopts(False)
1536 1538
1537 1539 def helplist(header, select=None):
1538 1540 h = {}
1539 1541 cmds = {}
1540 1542 for c, e in table.iteritems():
1541 1543 f = c.split("|", 1)[0]
1542 1544 if select and not select(f):
1543 1545 continue
1544 1546 if (not select and name != 'shortlist' and
1545 1547 e[0].__module__ != __name__):
1546 1548 continue
1547 1549 if name == "shortlist" and not f.startswith("^"):
1548 1550 continue
1549 1551 f = f.lstrip("^")
1550 1552 if not ui.debugflag and f.startswith("debug"):
1551 1553 continue
1552 1554 doc = e[0].__doc__
1553 1555 if doc and 'DEPRECATED' in doc and not ui.verbose:
1554 1556 continue
1555 1557 doc = gettext(doc)
1556 1558 if not doc:
1557 1559 doc = _("(no help text available)")
1558 1560 h[f] = doc.splitlines()[0].rstrip()
1559 1561 cmds[f] = c.lstrip("^")
1560 1562
1561 1563 if not h:
1562 1564 ui.status(_('no commands defined\n'))
1563 1565 return
1564 1566
1565 1567 ui.status(header)
1566 1568 fns = sorted(h)
1567 1569 m = max(map(len, fns))
1568 1570 for f in fns:
1569 1571 if ui.verbose:
1570 1572 commands = cmds[f].replace("|",", ")
1571 1573 ui.write(" %s:\n %s\n"%(commands, h[f]))
1572 1574 else:
1573 1575 ui.write(' %-*s %s\n' % (m, f, util.wrap(h[f], m + 4)))
1574 1576
1575 1577 if not ui.quiet:
1576 1578 addglobalopts(True)
1577 1579
1578 1580 def helptopic(name):
1579 1581 for names, header, doc in help.helptable:
1580 1582 if name in names:
1581 1583 break
1582 1584 else:
1583 1585 raise error.UnknownCommand(name)
1584 1586
1585 1587 # description
1586 1588 if not doc:
1587 1589 doc = _("(no help text available)")
1588 1590 if hasattr(doc, '__call__'):
1589 1591 doc = doc()
1590 1592
1591 1593 ui.write("%s\n\n" % header)
1592 1594 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1593 1595
1594 1596 def helpext(name):
1595 1597 try:
1596 1598 mod = extensions.find(name)
1597 1599 doc = gettext(mod.__doc__) or _('no help text available')
1598 1600 except KeyError:
1599 1601 mod = None
1600 1602 doc = extensions.disabledext(name)
1601 1603 if not doc:
1602 1604 raise error.UnknownCommand(name)
1603 1605
1604 1606 if '\n' not in doc:
1605 1607 head, tail = doc, ""
1606 1608 else:
1607 1609 head, tail = doc.split('\n', 1)
1608 1610 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1609 1611 if tail:
1610 1612 ui.write(minirst.format(tail, textwidth))
1611 1613 ui.status('\n\n')
1612 1614
1613 1615 if mod:
1614 1616 try:
1615 1617 ct = mod.cmdtable
1616 1618 except AttributeError:
1617 1619 ct = {}
1618 1620 modcmds = set([c.split('|', 1)[0] for c in ct])
1619 1621 helplist(_('list of commands:\n\n'), modcmds.__contains__)
1620 1622 else:
1621 1623 ui.write(_('use "hg help extensions" for information on enabling '
1622 1624 'extensions\n'))
1623 1625
1624 1626 def helpextcmd(name):
1625 1627 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
1626 1628 doc = gettext(mod.__doc__).splitlines()[0]
1627 1629
1628 1630 msg = help.listexts(_("'%s' is provided by the following "
1629 1631 "extension:") % cmd, {ext: doc}, len(ext),
1630 1632 indent=4)
1631 1633 ui.write(minirst.format(msg, textwidth))
1632 1634 ui.write('\n\n')
1633 1635 ui.write(_('use "hg help extensions" for information on enabling '
1634 1636 'extensions\n'))
1635 1637
1636 1638 if name and name != 'shortlist':
1637 1639 i = None
1638 1640 if unknowncmd:
1639 1641 queries = (helpextcmd,)
1640 1642 else:
1641 1643 queries = (helptopic, helpcmd, helpext, helpextcmd)
1642 1644 for f in queries:
1643 1645 try:
1644 1646 f(name)
1645 1647 i = None
1646 1648 break
1647 1649 except error.UnknownCommand, inst:
1648 1650 i = inst
1649 1651 if i:
1650 1652 raise i
1651 1653
1652 1654 else:
1653 1655 # program name
1654 1656 if ui.verbose or with_version:
1655 1657 version_(ui)
1656 1658 else:
1657 1659 ui.status(_("Mercurial Distributed SCM\n"))
1658 1660 ui.status('\n')
1659 1661
1660 1662 # list of commands
1661 1663 if name == "shortlist":
1662 1664 header = _('basic commands:\n\n')
1663 1665 else:
1664 1666 header = _('list of commands:\n\n')
1665 1667
1666 1668 helplist(header)
1667 1669 if name != 'shortlist':
1668 1670 exts, maxlength = extensions.enabled()
1669 1671 text = help.listexts(_('enabled extensions:'), exts, maxlength)
1670 1672 if text:
1671 1673 ui.write("\n%s\n" % minirst.format(text, textwidth))
1672 1674
1673 1675 # list all option lists
1674 1676 opt_output = []
1675 1677 for title, options in option_lists:
1676 1678 opt_output.append(("\n%s" % title, None))
1677 1679 for shortopt, longopt, default, desc in options:
1678 1680 if _("DEPRECATED") in desc and not ui.verbose:
1679 1681 continue
1680 1682 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1681 1683 longopt and " --%s" % longopt),
1682 1684 "%s%s" % (desc,
1683 1685 default
1684 1686 and _(" (default: %s)") % default
1685 1687 or "")))
1686 1688
1687 1689 if not name:
1688 1690 ui.write(_("\nadditional help topics:\n\n"))
1689 1691 topics = []
1690 1692 for names, header, doc in help.helptable:
1691 1693 topics.append((sorted(names, key=len, reverse=True)[0], header))
1692 1694 topics_len = max([len(s[0]) for s in topics])
1693 1695 for t, desc in topics:
1694 1696 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1695 1697
1696 1698 if opt_output:
1697 1699 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1698 1700 for first, second in opt_output:
1699 1701 if second:
1700 1702 second = util.wrap(second, opts_len + 3)
1701 1703 ui.write(" %-*s %s\n" % (opts_len, first, second))
1702 1704 else:
1703 1705 ui.write("%s\n" % first)
1704 1706
1705 1707 def identify(ui, repo, source=None,
1706 1708 rev=None, num=None, id=None, branch=None, tags=None):
1707 1709 """identify the working copy or specified revision
1708 1710
1709 1711 With no revision, print a summary of the current state of the
1710 1712 repository.
1711 1713
1712 1714 Specifying a path to a repository root or Mercurial bundle will
1713 1715 cause lookup to operate on that repository/bundle.
1714 1716
1715 1717 This summary identifies the repository state using one or two
1716 1718 parent hash identifiers, followed by a "+" if there are
1717 1719 uncommitted changes in the working directory, a list of tags for
1718 1720 this revision and a branch name for non-default branches.
1719 1721 """
1720 1722
1721 1723 if not repo and not source:
1722 1724 raise util.Abort(_("There is no Mercurial repository here "
1723 1725 "(.hg not found)"))
1724 1726
1725 1727 hexfunc = ui.debugflag and hex or short
1726 1728 default = not (num or id or branch or tags)
1727 1729 output = []
1728 1730
1729 1731 revs = []
1730 1732 if source:
1731 1733 source, branches = hg.parseurl(ui.expandpath(source))
1732 1734 repo = hg.repository(ui, source)
1733 1735 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
1734 1736
1735 1737 if not repo.local():
1736 1738 if not rev and revs:
1737 1739 rev = revs[0]
1738 1740 if not rev:
1739 1741 rev = "tip"
1740 1742 if num or branch or tags:
1741 1743 raise util.Abort(
1742 1744 "can't query remote revision number, branch, or tags")
1743 1745 output = [hexfunc(repo.lookup(rev))]
1744 1746 elif not rev:
1745 1747 ctx = repo[None]
1746 1748 parents = ctx.parents()
1747 1749 changed = False
1748 1750 if default or id or num:
1749 1751 changed = ctx.files() + ctx.deleted()
1750 1752 if default or id:
1751 1753 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1752 1754 (changed) and "+" or "")]
1753 1755 if num:
1754 1756 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1755 1757 (changed) and "+" or ""))
1756 1758 else:
1757 1759 ctx = repo[rev]
1758 1760 if default or id:
1759 1761 output = [hexfunc(ctx.node())]
1760 1762 if num:
1761 1763 output.append(str(ctx.rev()))
1762 1764
1763 1765 if repo.local() and default and not ui.quiet:
1764 1766 b = encoding.tolocal(ctx.branch())
1765 1767 if b != 'default':
1766 1768 output.append("(%s)" % b)
1767 1769
1768 1770 # multiple tags for a single parent separated by '/'
1769 1771 t = "/".join(ctx.tags())
1770 1772 if t:
1771 1773 output.append(t)
1772 1774
1773 1775 if branch:
1774 1776 output.append(encoding.tolocal(ctx.branch()))
1775 1777
1776 1778 if tags:
1777 1779 output.extend(ctx.tags())
1778 1780
1779 1781 ui.write("%s\n" % ' '.join(output))
1780 1782
1781 1783 def import_(ui, repo, patch1, *patches, **opts):
1782 1784 """import an ordered set of patches
1783 1785
1784 1786 Import a list of patches and commit them individually (unless
1785 1787 --no-commit is specified).
1786 1788
1787 1789 If there are outstanding changes in the working directory, import
1788 1790 will abort unless given the -f/--force flag.
1789 1791
1790 1792 You can import a patch straight from a mail message. Even patches
1791 1793 as attachments work (to use the body part, it must have type
1792 1794 text/plain or text/x-patch). From and Subject headers of email
1793 1795 message are used as default committer and commit message. All
1794 1796 text/plain body parts before first diff are added to commit
1795 1797 message.
1796 1798
1797 1799 If the imported patch was generated by hg export, user and
1798 1800 description from patch override values from message headers and
1799 1801 body. Values given on command line with -m/--message and -u/--user
1800 1802 override these.
1801 1803
1802 1804 If --exact is specified, import will set the working directory to
1803 1805 the parent of each patch before applying it, and will abort if the
1804 1806 resulting changeset has a different ID than the one recorded in
1805 1807 the patch. This may happen due to character set problems or other
1806 1808 deficiencies in the text patch format.
1807 1809
1808 1810 With -s/--similarity, hg will attempt to discover renames and
1809 1811 copies in the patch in the same way as 'addremove'.
1810 1812
1811 1813 To read a patch from standard input, use "-" as the patch name. If
1812 1814 a URL is specified, the patch will be downloaded from it.
1813 1815 See 'hg help dates' for a list of formats valid for -d/--date.
1814 1816 """
1815 1817 patches = (patch1,) + patches
1816 1818
1817 1819 date = opts.get('date')
1818 1820 if date:
1819 1821 opts['date'] = util.parsedate(date)
1820 1822
1821 1823 try:
1822 1824 sim = float(opts.get('similarity') or 0)
1823 1825 except ValueError:
1824 1826 raise util.Abort(_('similarity must be a number'))
1825 1827 if sim < 0 or sim > 100:
1826 1828 raise util.Abort(_('similarity must be between 0 and 100'))
1827 1829
1828 1830 if opts.get('exact') or not opts.get('force'):
1829 1831 cmdutil.bail_if_changed(repo)
1830 1832
1831 1833 d = opts["base"]
1832 1834 strip = opts["strip"]
1833 1835 wlock = lock = None
1834 1836 try:
1835 1837 wlock = repo.wlock()
1836 1838 lock = repo.lock()
1837 1839 for p in patches:
1838 1840 pf = os.path.join(d, p)
1839 1841
1840 1842 if pf == '-':
1841 1843 ui.status(_("applying patch from stdin\n"))
1842 1844 pf = sys.stdin
1843 1845 else:
1844 1846 ui.status(_("applying %s\n") % p)
1845 1847 pf = url.open(ui, pf)
1846 1848 data = patch.extract(ui, pf)
1847 1849 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1848 1850
1849 1851 if tmpname is None:
1850 1852 raise util.Abort(_('no diffs found'))
1851 1853
1852 1854 try:
1853 1855 cmdline_message = cmdutil.logmessage(opts)
1854 1856 if cmdline_message:
1855 1857 # pickup the cmdline msg
1856 1858 message = cmdline_message
1857 1859 elif message:
1858 1860 # pickup the patch msg
1859 1861 message = message.strip()
1860 1862 else:
1861 1863 # launch the editor
1862 1864 message = None
1863 1865 ui.debug('message:\n%s\n' % message)
1864 1866
1865 1867 wp = repo.parents()
1866 1868 if opts.get('exact'):
1867 1869 if not nodeid or not p1:
1868 1870 raise util.Abort(_('not a Mercurial patch'))
1869 1871 p1 = repo.lookup(p1)
1870 1872 p2 = repo.lookup(p2 or hex(nullid))
1871 1873
1872 1874 if p1 != wp[0].node():
1873 1875 hg.clean(repo, p1)
1874 1876 repo.dirstate.setparents(p1, p2)
1875 1877 elif p2:
1876 1878 try:
1877 1879 p1 = repo.lookup(p1)
1878 1880 p2 = repo.lookup(p2)
1879 1881 if p1 == wp[0].node():
1880 1882 repo.dirstate.setparents(p1, p2)
1881 1883 except error.RepoError:
1882 1884 pass
1883 1885 if opts.get('exact') or opts.get('import_branch'):
1884 1886 repo.dirstate.setbranch(branch or 'default')
1885 1887
1886 1888 files = {}
1887 1889 try:
1888 1890 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1889 1891 files=files, eolmode=None)
1890 1892 finally:
1891 1893 files = patch.updatedir(ui, repo, files,
1892 1894 similarity=sim / 100.0)
1893 1895 if not opts.get('no_commit'):
1894 1896 m = cmdutil.matchfiles(repo, files or [])
1895 1897 n = repo.commit(message, opts.get('user') or user,
1896 1898 opts.get('date') or date, match=m,
1897 1899 editor=cmdutil.commiteditor)
1898 1900 if opts.get('exact'):
1899 1901 if hex(n) != nodeid:
1900 1902 repo.rollback()
1901 1903 raise util.Abort(_('patch is damaged'
1902 1904 ' or loses information'))
1903 1905 # Force a dirstate write so that the next transaction
1904 1906 # backups an up-do-date file.
1905 1907 repo.dirstate.write()
1906 1908 finally:
1907 1909 os.unlink(tmpname)
1908 1910 finally:
1909 1911 release(lock, wlock)
1910 1912
1911 1913 def incoming(ui, repo, source="default", **opts):
1912 1914 """show new changesets found in source
1913 1915
1914 1916 Show new changesets found in the specified path/URL or the default
1915 1917 pull location. These are the changesets that would have been pulled
1916 1918 if a pull at the time you issued this command.
1917 1919
1918 1920 For remote repository, using --bundle avoids downloading the
1919 1921 changesets twice if the incoming is followed by a pull.
1920 1922
1921 1923 See pull for valid source format details.
1922 1924 """
1923 1925 limit = cmdutil.loglimit(opts)
1924 source, branches = hg.parseurl(ui.expandpath(source))
1926 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
1925 1927 other = hg.repository(cmdutil.remoteui(repo, opts), source)
1926 1928 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1927 1929 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
1928 1930 if revs:
1929 1931 revs = [other.lookup(rev) for rev in revs]
1930 1932 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1931 1933 force=opts["force"])
1932 1934 if not incoming:
1933 1935 try:
1934 1936 os.unlink(opts["bundle"])
1935 1937 except:
1936 1938 pass
1937 1939 ui.status(_("no changes found\n"))
1938 1940 return 1
1939 1941
1940 1942 cleanup = None
1941 1943 try:
1942 1944 fname = opts["bundle"]
1943 1945 if fname or not other.local():
1944 1946 # create a bundle (uncompressed if other repo is not local)
1945 1947
1946 1948 if revs is None and other.capable('changegroupsubset'):
1947 1949 revs = rheads
1948 1950
1949 1951 if revs is None:
1950 1952 cg = other.changegroup(incoming, "incoming")
1951 1953 else:
1952 1954 cg = other.changegroupsubset(incoming, revs, 'incoming')
1953 1955 bundletype = other.local() and "HG10BZ" or "HG10UN"
1954 1956 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1955 1957 # keep written bundle?
1956 1958 if opts["bundle"]:
1957 1959 cleanup = None
1958 1960 if not other.local():
1959 1961 # use the created uncompressed bundlerepo
1960 1962 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1961 1963
1962 1964 o = other.changelog.nodesbetween(incoming, revs)[0]
1963 1965 if opts.get('newest_first'):
1964 1966 o.reverse()
1965 1967 displayer = cmdutil.show_changeset(ui, other, opts)
1966 1968 count = 0
1967 1969 for n in o:
1968 1970 if limit is not None and count >= limit:
1969 1971 break
1970 1972 parents = [p for p in other.changelog.parents(n) if p != nullid]
1971 1973 if opts.get('no_merges') and len(parents) == 2:
1972 1974 continue
1973 1975 count += 1
1974 1976 displayer.show(other[n])
1975 1977 displayer.close()
1976 1978 finally:
1977 1979 if hasattr(other, 'close'):
1978 1980 other.close()
1979 1981 if cleanup:
1980 1982 os.unlink(cleanup)
1981 1983
1982 1984 def init(ui, dest=".", **opts):
1983 1985 """create a new repository in the given directory
1984 1986
1985 1987 Initialize a new repository in the given directory. If the given
1986 1988 directory does not exist, it will be created.
1987 1989
1988 1990 If no directory is given, the current directory is used.
1989 1991
1990 1992 It is possible to specify an ``ssh://`` URL as the destination.
1991 1993 See 'hg help urls' for more information.
1992 1994 """
1993 1995 hg.repository(cmdutil.remoteui(ui, opts), dest, create=1)
1994 1996
1995 1997 def locate(ui, repo, *pats, **opts):
1996 1998 """locate files matching specific patterns
1997 1999
1998 2000 Print files under Mercurial control in the working directory whose
1999 2001 names match the given patterns.
2000 2002
2001 2003 By default, this command searches all directories in the working
2002 2004 directory. To search just the current directory and its
2003 2005 subdirectories, use "--include .".
2004 2006
2005 2007 If no patterns are given to match, this command prints the names
2006 2008 of all files under Mercurial control in the working directory.
2007 2009
2008 2010 If you want to feed the output of this command into the "xargs"
2009 2011 command, use the -0 option to both this command and "xargs". This
2010 2012 will avoid the problem of "xargs" treating single filenames that
2011 2013 contain whitespace as multiple filenames.
2012 2014 """
2013 2015 end = opts.get('print0') and '\0' or '\n'
2014 2016 rev = opts.get('rev') or None
2015 2017
2016 2018 ret = 1
2017 2019 m = cmdutil.match(repo, pats, opts, default='relglob')
2018 2020 m.bad = lambda x, y: False
2019 2021 for abs in repo[rev].walk(m):
2020 2022 if not rev and abs not in repo.dirstate:
2021 2023 continue
2022 2024 if opts.get('fullpath'):
2023 2025 ui.write(repo.wjoin(abs), end)
2024 2026 else:
2025 2027 ui.write(((pats and m.rel(abs)) or abs), end)
2026 2028 ret = 0
2027 2029
2028 2030 return ret
2029 2031
2030 2032 def log(ui, repo, *pats, **opts):
2031 2033 """show revision history of entire repository or files
2032 2034
2033 2035 Print the revision history of the specified files or the entire
2034 2036 project.
2035 2037
2036 2038 File history is shown without following rename or copy history of
2037 2039 files. Use -f/--follow with a filename to follow history across
2038 2040 renames and copies. --follow without a filename will only show
2039 2041 ancestors or descendants of the starting revision. --follow-first
2040 2042 only follows the first parent of merge revisions.
2041 2043
2042 2044 If no revision range is specified, the default is tip:0 unless
2043 2045 --follow is set, in which case the working directory parent is
2044 2046 used as the starting revision.
2045 2047
2046 2048 See 'hg help dates' for a list of formats valid for -d/--date.
2047 2049
2048 2050 By default this command prints revision number and changeset id,
2049 2051 tags, non-trivial parents, user, date and time, and a summary for
2050 2052 each commit. When the -v/--verbose switch is used, the list of
2051 2053 changed files and full commit message are shown.
2052 2054
2053 2055 NOTE: log -p/--patch may generate unexpected diff output for merge
2054 2056 changesets, as it will only compare the merge changeset against
2055 2057 its first parent. Also, only files different from BOTH parents
2056 2058 will appear in files:.
2057 2059 """
2058 2060
2059 2061 matchfn = cmdutil.match(repo, pats, opts)
2060 2062 limit = cmdutil.loglimit(opts)
2061 2063 count = 0
2062 2064
2063 2065 endrev = None
2064 2066 if opts.get('copies') and opts.get('rev'):
2065 2067 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2066 2068
2067 2069 df = False
2068 2070 if opts["date"]:
2069 2071 df = util.matchdate(opts["date"])
2070 2072
2071 2073 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
2072 2074 def prep(ctx, fns):
2073 2075 rev = ctx.rev()
2074 2076 parents = [p for p in repo.changelog.parentrevs(rev)
2075 2077 if p != nullrev]
2076 2078 if opts.get('no_merges') and len(parents) == 2:
2077 2079 return
2078 2080 if opts.get('only_merges') and len(parents) != 2:
2079 2081 return
2080 2082 if opts.get('only_branch') and ctx.branch() not in opts['only_branch']:
2081 2083 return
2082 2084 if df and not df(ctx.date()[0]):
2083 2085 return
2084 2086 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2085 2087 return
2086 2088 if opts.get('keyword'):
2087 2089 for k in [kw.lower() for kw in opts['keyword']]:
2088 2090 if (k in ctx.user().lower() or
2089 2091 k in ctx.description().lower() or
2090 2092 k in " ".join(ctx.files()).lower()):
2091 2093 break
2092 2094 else:
2093 2095 return
2094 2096
2095 2097 copies = None
2096 2098 if opts.get('copies') and rev:
2097 2099 copies = []
2098 2100 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2099 2101 for fn in ctx.files():
2100 2102 rename = getrenamed(fn, rev)
2101 2103 if rename:
2102 2104 copies.append((fn, rename[0]))
2103 2105
2104 2106 displayer.show(ctx, copies=copies)
2105 2107
2106 2108 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2107 2109 if count == limit:
2108 2110 break
2109 2111 if displayer.flush(ctx.rev()):
2110 2112 count += 1
2111 2113 displayer.close()
2112 2114
2113 2115 def manifest(ui, repo, node=None, rev=None):
2114 2116 """output the current or given revision of the project manifest
2115 2117
2116 2118 Print a list of version controlled files for the given revision.
2117 2119 If no revision is given, the first parent of the working directory
2118 2120 is used, or the null revision if no revision is checked out.
2119 2121
2120 2122 With -v, print file permissions, symlink and executable bits.
2121 2123 With --debug, print file revision hashes.
2122 2124 """
2123 2125
2124 2126 if rev and node:
2125 2127 raise util.Abort(_("please specify just one revision"))
2126 2128
2127 2129 if not node:
2128 2130 node = rev
2129 2131
2130 2132 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2131 2133 ctx = repo[node]
2132 2134 for f in ctx:
2133 2135 if ui.debugflag:
2134 2136 ui.write("%40s " % hex(ctx.manifest()[f]))
2135 2137 if ui.verbose:
2136 2138 ui.write(decor[ctx.flags(f)])
2137 2139 ui.write("%s\n" % f)
2138 2140
2139 2141 def merge(ui, repo, node=None, **opts):
2140 2142 """merge working directory with another revision
2141 2143
2142 2144 The current working directory is updated with all changes made in
2143 2145 the requested revision since the last common predecessor revision.
2144 2146
2145 2147 Files that changed between either parent are marked as changed for
2146 2148 the next commit and a commit must be performed before any further
2147 2149 updates to the repository are allowed. The next commit will have
2148 2150 two parents.
2149 2151
2150 2152 If no revision is specified, the working directory's parent is a
2151 2153 head revision, and the current branch contains exactly one other
2152 2154 head, the other head is merged with by default. Otherwise, an
2153 2155 explicit revision with which to merge with must be provided.
2154 2156 """
2155 2157
2156 2158 if opts.get('rev') and node:
2157 2159 raise util.Abort(_("please specify just one revision"))
2158 2160 if not node:
2159 2161 node = opts.get('rev')
2160 2162
2161 2163 if not node:
2162 2164 branch = repo.changectx(None).branch()
2163 2165 bheads = repo.branchheads(branch)
2164 2166 if len(bheads) > 2:
2165 2167 ui.warn(_("abort: branch '%s' has %d heads - "
2166 2168 "please merge with an explicit rev\n")
2167 2169 % (branch, len(bheads)))
2168 2170 ui.status(_("(run 'hg heads .' to see heads)\n"))
2169 2171 return False
2170 2172
2171 2173 parent = repo.dirstate.parents()[0]
2172 2174 if len(bheads) == 1:
2173 2175 if len(repo.heads()) > 1:
2174 2176 ui.warn(_("abort: branch '%s' has one head - "
2175 2177 "please merge with an explicit rev\n" % branch))
2176 2178 ui.status(_("(run 'hg heads' to see all heads)\n"))
2177 2179 return False
2178 2180 msg = _('there is nothing to merge')
2179 2181 if parent != repo.lookup(repo[None].branch()):
2180 2182 msg = _('%s - use "hg update" instead') % msg
2181 2183 raise util.Abort(msg)
2182 2184
2183 2185 if parent not in bheads:
2184 2186 raise util.Abort(_('working dir not at a head rev - '
2185 2187 'use "hg update" or merge with an explicit rev'))
2186 2188 node = parent == bheads[0] and bheads[-1] or bheads[0]
2187 2189
2188 2190 if opts.get('preview'):
2189 2191 p1 = repo['.']
2190 2192 p2 = repo[node]
2191 2193 common = p1.ancestor(p2)
2192 2194 roots, heads = [common.node()], [p2.node()]
2193 2195 displayer = cmdutil.show_changeset(ui, repo, opts)
2194 2196 for node in repo.changelog.nodesbetween(roots=roots, heads=heads)[0]:
2195 2197 if node not in roots:
2196 2198 displayer.show(repo[node])
2197 2199 displayer.close()
2198 2200 return 0
2199 2201
2200 2202 return hg.merge(repo, node, force=opts.get('force'))
2201 2203
2202 2204 def outgoing(ui, repo, dest=None, **opts):
2203 2205 """show changesets not found in the destination
2204 2206
2205 2207 Show changesets not found in the specified destination repository
2206 2208 or the default push location. These are the changesets that would
2207 2209 be pushed if a push was requested.
2208 2210
2209 2211 See pull for details of valid destination formats.
2210 2212 """
2211 2213 limit = cmdutil.loglimit(opts)
2212 2214 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2213 dest, branches = hg.parseurl(dest)
2215 dest, branches = hg.parseurl(dest, opts.get('branch'))
2214 2216 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2215 2217 if revs:
2216 2218 revs = [repo.lookup(rev) for rev in revs]
2217 2219
2218 2220 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2219 2221 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2220 2222 o = repo.findoutgoing(other, force=opts.get('force'))
2221 2223 if not o:
2222 2224 ui.status(_("no changes found\n"))
2223 2225 return 1
2224 2226 o = repo.changelog.nodesbetween(o, revs)[0]
2225 2227 if opts.get('newest_first'):
2226 2228 o.reverse()
2227 2229 displayer = cmdutil.show_changeset(ui, repo, opts)
2228 2230 count = 0
2229 2231 for n in o:
2230 2232 if limit is not None and count >= limit:
2231 2233 break
2232 2234 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2233 2235 if opts.get('no_merges') and len(parents) == 2:
2234 2236 continue
2235 2237 count += 1
2236 2238 displayer.show(repo[n])
2237 2239 displayer.close()
2238 2240
2239 2241 def parents(ui, repo, file_=None, **opts):
2240 2242 """show the parents of the working directory or revision
2241 2243
2242 2244 Print the working directory's parent revisions. If a revision is
2243 2245 given via -r/--rev, the parent of that revision will be printed.
2244 2246 If a file argument is given, the revision in which the file was
2245 2247 last changed (before the working directory revision or the
2246 2248 argument to --rev if given) is printed.
2247 2249 """
2248 2250 rev = opts.get('rev')
2249 2251 if rev:
2250 2252 ctx = repo[rev]
2251 2253 else:
2252 2254 ctx = repo[None]
2253 2255
2254 2256 if file_:
2255 2257 m = cmdutil.match(repo, (file_,), opts)
2256 2258 if m.anypats() or len(m.files()) != 1:
2257 2259 raise util.Abort(_('can only specify an explicit filename'))
2258 2260 file_ = m.files()[0]
2259 2261 filenodes = []
2260 2262 for cp in ctx.parents():
2261 2263 if not cp:
2262 2264 continue
2263 2265 try:
2264 2266 filenodes.append(cp.filenode(file_))
2265 2267 except error.LookupError:
2266 2268 pass
2267 2269 if not filenodes:
2268 2270 raise util.Abort(_("'%s' not found in manifest!") % file_)
2269 2271 fl = repo.file(file_)
2270 2272 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2271 2273 else:
2272 2274 p = [cp.node() for cp in ctx.parents()]
2273 2275
2274 2276 displayer = cmdutil.show_changeset(ui, repo, opts)
2275 2277 for n in p:
2276 2278 if n != nullid:
2277 2279 displayer.show(repo[n])
2278 2280 displayer.close()
2279 2281
2280 2282 def paths(ui, repo, search=None):
2281 2283 """show aliases for remote repositories
2282 2284
2283 2285 Show definition of symbolic path name NAME. If no name is given,
2284 2286 show definition of all available names.
2285 2287
2286 2288 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2287 2289 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2288 2290
2289 2291 See 'hg help urls' for more information.
2290 2292 """
2291 2293 if search:
2292 2294 for name, path in ui.configitems("paths"):
2293 2295 if name == search:
2294 2296 ui.write("%s\n" % url.hidepassword(path))
2295 2297 return
2296 2298 ui.warn(_("not found!\n"))
2297 2299 return 1
2298 2300 else:
2299 2301 for name, path in ui.configitems("paths"):
2300 2302 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2301 2303
2302 2304 def postincoming(ui, repo, modheads, optupdate, checkout):
2303 2305 if modheads == 0:
2304 2306 return
2305 2307 if optupdate:
2306 2308 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2307 2309 return hg.update(repo, checkout)
2308 2310 else:
2309 2311 ui.status(_("not updating, since new heads added\n"))
2310 2312 if modheads > 1:
2311 2313 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2312 2314 else:
2313 2315 ui.status(_("(run 'hg update' to get a working copy)\n"))
2314 2316
2315 2317 def pull(ui, repo, source="default", **opts):
2316 2318 """pull changes from the specified source
2317 2319
2318 2320 Pull changes from a remote repository to a local one.
2319 2321
2320 2322 This finds all changes from the repository at the specified path
2321 2323 or URL and adds them to a local repository (the current one unless
2322 2324 -R is specified). By default, this does not update the copy of the
2323 2325 project in the working directory.
2324 2326
2325 2327 Use hg incoming if you want to see what would have been added by a
2326 2328 pull at the time you issued this command. If you then decide to
2327 2329 added those changes to the repository, you should use pull -r X
2328 2330 where X is the last changeset listed by hg incoming.
2329 2331
2330 2332 If SOURCE is omitted, the 'default' path will be used.
2331 2333 See 'hg help urls' for more information.
2332 2334 """
2333 source, branches = hg.parseurl(ui.expandpath(source))
2335 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2334 2336 other = hg.repository(cmdutil.remoteui(repo, opts), source)
2335 2337 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2336 2338 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2337 2339 if revs:
2338 2340 try:
2339 2341 revs = [other.lookup(rev) for rev in revs]
2340 2342 except error.CapabilityError:
2341 2343 err = _("Other repository doesn't support revision lookup, "
2342 2344 "so a rev cannot be specified.")
2343 2345 raise util.Abort(err)
2344 2346
2345 2347 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2346 2348 if checkout:
2347 2349 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2348 2350 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2349 2351
2350 2352 def push(ui, repo, dest=None, **opts):
2351 2353 """push changes to the specified destination
2352 2354
2353 2355 Push changes from the local repository to the specified destination.
2354 2356
2355 2357 This is the symmetrical operation for pull. It moves changes from
2356 2358 the current repository to a different one. If the destination is
2357 2359 local this is identical to a pull in that directory from the
2358 2360 current one.
2359 2361
2360 2362 By default, push will refuse to run if it detects the result would
2361 2363 increase the number of remote heads. This generally indicates the
2362 2364 user forgot to pull and merge before pushing.
2363 2365
2364 2366 If -r/--rev is used, the named revision and all its ancestors will
2365 2367 be pushed to the remote repository.
2366 2368
2367 2369 Please see 'hg help urls' for important details about ``ssh://``
2368 2370 URLs. If DESTINATION is omitted, a default path will be used.
2369 2371 """
2370 2372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2371 dest, branches = hg.parseurl(dest)
2373 dest, branches = hg.parseurl(dest, opts.get('branch'))
2372 2374 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2373 2375 other = hg.repository(cmdutil.remoteui(repo, opts), dest)
2374 2376 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2375 2377 if revs:
2376 2378 revs = [repo.lookup(rev) for rev in revs]
2377 2379
2378 2380 # push subrepos depth-first for coherent ordering
2379 2381 c = repo['']
2380 2382 subs = c.substate # only repos that are committed
2381 2383 for s in sorted(subs):
2382 2384 c.sub(s).push(opts.get('force'))
2383 2385
2384 2386 r = repo.push(other, opts.get('force'), revs=revs)
2385 2387 return r == 0
2386 2388
2387 2389 def recover(ui, repo):
2388 2390 """roll back an interrupted transaction
2389 2391
2390 2392 Recover from an interrupted commit or pull.
2391 2393
2392 2394 This command tries to fix the repository status after an
2393 2395 interrupted operation. It should only be necessary when Mercurial
2394 2396 suggests it.
2395 2397 """
2396 2398 if repo.recover():
2397 2399 return hg.verify(repo)
2398 2400 return 1
2399 2401
2400 2402 def remove(ui, repo, *pats, **opts):
2401 2403 """remove the specified files on the next commit
2402 2404
2403 2405 Schedule the indicated files for removal from the repository.
2404 2406
2405 2407 This only removes files from the current branch, not from the
2406 2408 entire project history. -A/--after can be used to remove only
2407 2409 files that have already been deleted, -f/--force can be used to
2408 2410 force deletion, and -Af can be used to remove files from the next
2409 2411 revision without deleting them from the working directory.
2410 2412
2411 2413 The following table details the behavior of remove for different
2412 2414 file states (columns) and option combinations (rows). The file
2413 2415 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2414 2416 reported by hg status). The actions are Warn, Remove (from branch)
2415 2417 and Delete (from disk)::
2416 2418
2417 2419 A C M !
2418 2420 none W RD W R
2419 2421 -f R RD RD R
2420 2422 -A W W W R
2421 2423 -Af R R R R
2422 2424
2423 2425 This command schedules the files to be removed at the next commit.
2424 2426 To undo a remove before that, see hg revert.
2425 2427 """
2426 2428
2427 2429 after, force = opts.get('after'), opts.get('force')
2428 2430 if not pats and not after:
2429 2431 raise util.Abort(_('no files specified'))
2430 2432
2431 2433 m = cmdutil.match(repo, pats, opts)
2432 2434 s = repo.status(match=m, clean=True)
2433 2435 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2434 2436
2435 2437 for f in m.files():
2436 2438 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2437 2439 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2438 2440
2439 2441 def warn(files, reason):
2440 2442 for f in files:
2441 2443 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2442 2444 % (m.rel(f), reason))
2443 2445
2444 2446 if force:
2445 2447 remove, forget = modified + deleted + clean, added
2446 2448 elif after:
2447 2449 remove, forget = deleted, []
2448 2450 warn(modified + added + clean, _('still exists'))
2449 2451 else:
2450 2452 remove, forget = deleted + clean, []
2451 2453 warn(modified, _('is modified'))
2452 2454 warn(added, _('has been marked for add'))
2453 2455
2454 2456 for f in sorted(remove + forget):
2455 2457 if ui.verbose or not m.exact(f):
2456 2458 ui.status(_('removing %s\n') % m.rel(f))
2457 2459
2458 2460 repo.forget(forget)
2459 2461 repo.remove(remove, unlink=not after)
2460 2462
2461 2463 def rename(ui, repo, *pats, **opts):
2462 2464 """rename files; equivalent of copy + remove
2463 2465
2464 2466 Mark dest as copies of sources; mark sources for deletion. If dest
2465 2467 is a directory, copies are put in that directory. If dest is a
2466 2468 file, there can only be one source.
2467 2469
2468 2470 By default, this command copies the contents of files as they
2469 2471 exist in the working directory. If invoked with -A/--after, the
2470 2472 operation is recorded, but no copying is performed.
2471 2473
2472 2474 This command takes effect at the next commit. To undo a rename
2473 2475 before that, see hg revert.
2474 2476 """
2475 2477 wlock = repo.wlock(False)
2476 2478 try:
2477 2479 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2478 2480 finally:
2479 2481 wlock.release()
2480 2482
2481 2483 def resolve(ui, repo, *pats, **opts):
2482 2484 """retry file merges from a merge or update
2483 2485
2484 2486 This command can cleanly retry unresolved file merges using file
2485 2487 revisions preserved from the last update or merge.
2486 2488
2487 2489 If a conflict is resolved manually, please note that the changes
2488 2490 will be overwritten if the merge is retried with resolve. The
2489 2491 -m/--mark switch should be used to mark the file as resolved.
2490 2492
2491 2493 You can specify a set of files to operate on, or use the -a/--all
2492 2494 switch to select all unresolved files.
2493 2495
2494 2496 This command also allows listing resolved files and manually
2495 2497 indicating whether or not files are resolved. All files must be
2496 2498 marked as resolved before a commit is permitted.
2497 2499
2498 2500 The codes used to show the status of files are::
2499 2501
2500 2502 U = unresolved
2501 2503 R = resolved
2502 2504 """
2503 2505
2504 2506 all, mark, unmark, show, nostatus = \
2505 2507 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2506 2508
2507 2509 if (show and (mark or unmark)) or (mark and unmark):
2508 2510 raise util.Abort(_("too many options specified"))
2509 2511 if pats and all:
2510 2512 raise util.Abort(_("can't specify --all and patterns"))
2511 2513 if not (all or pats or show or mark or unmark):
2512 2514 raise util.Abort(_('no files or directories specified; '
2513 2515 'use --all to remerge all files'))
2514 2516
2515 2517 ms = merge_.mergestate(repo)
2516 2518 m = cmdutil.match(repo, pats, opts)
2517 2519
2518 2520 for f in ms:
2519 2521 if m(f):
2520 2522 if show:
2521 2523 if nostatus:
2522 2524 ui.write("%s\n" % f)
2523 2525 else:
2524 2526 ui.write("%s %s\n" % (ms[f].upper(), f))
2525 2527 elif mark:
2526 2528 ms.mark(f, "r")
2527 2529 elif unmark:
2528 2530 ms.mark(f, "u")
2529 2531 else:
2530 2532 wctx = repo[None]
2531 2533 mctx = wctx.parents()[-1]
2532 2534
2533 2535 # backup pre-resolve (merge uses .orig for its own purposes)
2534 2536 a = repo.wjoin(f)
2535 2537 util.copyfile(a, a + ".resolve")
2536 2538
2537 2539 # resolve file
2538 2540 ms.resolve(f, wctx, mctx)
2539 2541
2540 2542 # replace filemerge's .orig file with our resolve file
2541 2543 util.rename(a + ".resolve", a + ".orig")
2542 2544
2543 2545 def revert(ui, repo, *pats, **opts):
2544 2546 """restore individual files or directories to an earlier state
2545 2547
2546 2548 (Use update -r to check out earlier revisions, revert does not
2547 2549 change the working directory parents.)
2548 2550
2549 2551 With no revision specified, revert the named files or directories
2550 2552 to the contents they had in the parent of the working directory.
2551 2553 This restores the contents of the affected files to an unmodified
2552 2554 state and unschedules adds, removes, copies, and renames. If the
2553 2555 working directory has two parents, you must explicitly specify a
2554 2556 revision.
2555 2557
2556 2558 Using the -r/--rev option, revert the given files or directories
2557 2559 to their contents as of a specific revision. This can be helpful
2558 2560 to "roll back" some or all of an earlier change. See 'hg help
2559 2561 dates' for a list of formats valid for -d/--date.
2560 2562
2561 2563 Revert modifies the working directory. It does not commit any
2562 2564 changes, or change the parent of the working directory. If you
2563 2565 revert to a revision other than the parent of the working
2564 2566 directory, the reverted files will thus appear modified
2565 2567 afterwards.
2566 2568
2567 2569 If a file has been deleted, it is restored. If the executable mode
2568 2570 of a file was changed, it is reset.
2569 2571
2570 2572 If names are given, all files matching the names are reverted.
2571 2573 If no arguments are given, no files are reverted.
2572 2574
2573 2575 Modified files are saved with a .orig suffix before reverting.
2574 2576 To disable these backups, use --no-backup.
2575 2577 """
2576 2578
2577 2579 if opts["date"]:
2578 2580 if opts["rev"]:
2579 2581 raise util.Abort(_("you can't specify a revision and a date"))
2580 2582 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2581 2583
2582 2584 if not pats and not opts.get('all'):
2583 2585 raise util.Abort(_('no files or directories specified; '
2584 2586 'use --all to revert the whole repo'))
2585 2587
2586 2588 parent, p2 = repo.dirstate.parents()
2587 2589 if not opts.get('rev') and p2 != nullid:
2588 2590 raise util.Abort(_('uncommitted merge - please provide a '
2589 2591 'specific revision'))
2590 2592 ctx = repo[opts.get('rev')]
2591 2593 node = ctx.node()
2592 2594 mf = ctx.manifest()
2593 2595 if node == parent:
2594 2596 pmf = mf
2595 2597 else:
2596 2598 pmf = None
2597 2599
2598 2600 # need all matching names in dirstate and manifest of target rev,
2599 2601 # so have to walk both. do not print errors if files exist in one
2600 2602 # but not other.
2601 2603
2602 2604 names = {}
2603 2605
2604 2606 wlock = repo.wlock()
2605 2607 try:
2606 2608 # walk dirstate.
2607 2609
2608 2610 m = cmdutil.match(repo, pats, opts)
2609 2611 m.bad = lambda x, y: False
2610 2612 for abs in repo.walk(m):
2611 2613 names[abs] = m.rel(abs), m.exact(abs)
2612 2614
2613 2615 # walk target manifest.
2614 2616
2615 2617 def badfn(path, msg):
2616 2618 if path in names:
2617 2619 return
2618 2620 path_ = path + '/'
2619 2621 for f in names:
2620 2622 if f.startswith(path_):
2621 2623 return
2622 2624 ui.warn("%s: %s\n" % (m.rel(path), msg))
2623 2625
2624 2626 m = cmdutil.match(repo, pats, opts)
2625 2627 m.bad = badfn
2626 2628 for abs in repo[node].walk(m):
2627 2629 if abs not in names:
2628 2630 names[abs] = m.rel(abs), m.exact(abs)
2629 2631
2630 2632 m = cmdutil.matchfiles(repo, names)
2631 2633 changes = repo.status(match=m)[:4]
2632 2634 modified, added, removed, deleted = map(set, changes)
2633 2635
2634 2636 # if f is a rename, also revert the source
2635 2637 cwd = repo.getcwd()
2636 2638 for f in added:
2637 2639 src = repo.dirstate.copied(f)
2638 2640 if src and src not in names and repo.dirstate[src] == 'r':
2639 2641 removed.add(src)
2640 2642 names[src] = (repo.pathto(src, cwd), True)
2641 2643
2642 2644 def removeforget(abs):
2643 2645 if repo.dirstate[abs] == 'a':
2644 2646 return _('forgetting %s\n')
2645 2647 return _('removing %s\n')
2646 2648
2647 2649 revert = ([], _('reverting %s\n'))
2648 2650 add = ([], _('adding %s\n'))
2649 2651 remove = ([], removeforget)
2650 2652 undelete = ([], _('undeleting %s\n'))
2651 2653
2652 2654 disptable = (
2653 2655 # dispatch table:
2654 2656 # file state
2655 2657 # action if in target manifest
2656 2658 # action if not in target manifest
2657 2659 # make backup if in target manifest
2658 2660 # make backup if not in target manifest
2659 2661 (modified, revert, remove, True, True),
2660 2662 (added, revert, remove, True, False),
2661 2663 (removed, undelete, None, False, False),
2662 2664 (deleted, revert, remove, False, False),
2663 2665 )
2664 2666
2665 2667 for abs, (rel, exact) in sorted(names.items()):
2666 2668 mfentry = mf.get(abs)
2667 2669 target = repo.wjoin(abs)
2668 2670 def handle(xlist, dobackup):
2669 2671 xlist[0].append(abs)
2670 2672 if dobackup and not opts.get('no_backup') and util.lexists(target):
2671 2673 bakname = "%s.orig" % rel
2672 2674 ui.note(_('saving current version of %s as %s\n') %
2673 2675 (rel, bakname))
2674 2676 if not opts.get('dry_run'):
2675 2677 util.copyfile(target, bakname)
2676 2678 if ui.verbose or not exact:
2677 2679 msg = xlist[1]
2678 2680 if not isinstance(msg, basestring):
2679 2681 msg = msg(abs)
2680 2682 ui.status(msg % rel)
2681 2683 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2682 2684 if abs not in table:
2683 2685 continue
2684 2686 # file has changed in dirstate
2685 2687 if mfentry:
2686 2688 handle(hitlist, backuphit)
2687 2689 elif misslist is not None:
2688 2690 handle(misslist, backupmiss)
2689 2691 break
2690 2692 else:
2691 2693 if abs not in repo.dirstate:
2692 2694 if mfentry:
2693 2695 handle(add, True)
2694 2696 elif exact:
2695 2697 ui.warn(_('file not managed: %s\n') % rel)
2696 2698 continue
2697 2699 # file has not changed in dirstate
2698 2700 if node == parent:
2699 2701 if exact:
2700 2702 ui.warn(_('no changes needed to %s\n') % rel)
2701 2703 continue
2702 2704 if pmf is None:
2703 2705 # only need parent manifest in this unlikely case,
2704 2706 # so do not read by default
2705 2707 pmf = repo[parent].manifest()
2706 2708 if abs in pmf:
2707 2709 if mfentry:
2708 2710 # if version of file is same in parent and target
2709 2711 # manifests, do nothing
2710 2712 if (pmf[abs] != mfentry or
2711 2713 pmf.flags(abs) != mf.flags(abs)):
2712 2714 handle(revert, False)
2713 2715 else:
2714 2716 handle(remove, False)
2715 2717
2716 2718 if not opts.get('dry_run'):
2717 2719 def checkout(f):
2718 2720 fc = ctx[f]
2719 2721 repo.wwrite(f, fc.data(), fc.flags())
2720 2722
2721 2723 audit_path = util.path_auditor(repo.root)
2722 2724 for f in remove[0]:
2723 2725 if repo.dirstate[f] == 'a':
2724 2726 repo.dirstate.forget(f)
2725 2727 continue
2726 2728 audit_path(f)
2727 2729 try:
2728 2730 util.unlink(repo.wjoin(f))
2729 2731 except OSError:
2730 2732 pass
2731 2733 repo.dirstate.remove(f)
2732 2734
2733 2735 normal = None
2734 2736 if node == parent:
2735 2737 # We're reverting to our parent. If possible, we'd like status
2736 2738 # to report the file as clean. We have to use normallookup for
2737 2739 # merges to avoid losing information about merged/dirty files.
2738 2740 if p2 != nullid:
2739 2741 normal = repo.dirstate.normallookup
2740 2742 else:
2741 2743 normal = repo.dirstate.normal
2742 2744 for f in revert[0]:
2743 2745 checkout(f)
2744 2746 if normal:
2745 2747 normal(f)
2746 2748
2747 2749 for f in add[0]:
2748 2750 checkout(f)
2749 2751 repo.dirstate.add(f)
2750 2752
2751 2753 normal = repo.dirstate.normallookup
2752 2754 if node == parent and p2 == nullid:
2753 2755 normal = repo.dirstate.normal
2754 2756 for f in undelete[0]:
2755 2757 checkout(f)
2756 2758 normal(f)
2757 2759
2758 2760 finally:
2759 2761 wlock.release()
2760 2762
2761 2763 def rollback(ui, repo):
2762 2764 """roll back the last transaction
2763 2765
2764 2766 This command should be used with care. There is only one level of
2765 2767 rollback, and there is no way to undo a rollback. It will also
2766 2768 restore the dirstate at the time of the last transaction, losing
2767 2769 any dirstate changes since that time. This command does not alter
2768 2770 the working directory.
2769 2771
2770 2772 Transactions are used to encapsulate the effects of all commands
2771 2773 that create new changesets or propagate existing changesets into a
2772 2774 repository. For example, the following commands are transactional,
2773 2775 and their effects can be rolled back:
2774 2776
2775 2777 - commit
2776 2778 - import
2777 2779 - pull
2778 2780 - push (with this repository as the destination)
2779 2781 - unbundle
2780 2782
2781 2783 This command is not intended for use on public repositories. Once
2782 2784 changes are visible for pull by other users, rolling a transaction
2783 2785 back locally is ineffective (someone else may already have pulled
2784 2786 the changes). Furthermore, a race is possible with readers of the
2785 2787 repository; for example an in-progress pull from the repository
2786 2788 may fail if a rollback is performed.
2787 2789 """
2788 2790 repo.rollback()
2789 2791
2790 2792 def root(ui, repo):
2791 2793 """print the root (top) of the current working directory
2792 2794
2793 2795 Print the root directory of the current repository.
2794 2796 """
2795 2797 ui.write(repo.root + "\n")
2796 2798
2797 2799 def serve(ui, repo, **opts):
2798 2800 """export the repository via HTTP
2799 2801
2800 2802 Start a local HTTP repository browser and pull server.
2801 2803
2802 2804 By default, the server logs accesses to stdout and errors to
2803 2805 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
2804 2806 files.
2805 2807 """
2806 2808
2807 2809 if opts["stdio"]:
2808 2810 if repo is None:
2809 2811 raise error.RepoError(_("There is no Mercurial repository here"
2810 2812 " (.hg not found)"))
2811 2813 s = sshserver.sshserver(ui, repo)
2812 2814 s.serve_forever()
2813 2815
2814 2816 baseui = repo and repo.baseui or ui
2815 2817 optlist = ("name templates style address port prefix ipv6"
2816 2818 " accesslog errorlog webdir_conf certificate encoding")
2817 2819 for o in optlist.split():
2818 2820 if opts.get(o, None):
2819 2821 baseui.setconfig("web", o, str(opts[o]))
2820 2822 if (repo is not None) and (repo.ui != baseui):
2821 2823 repo.ui.setconfig("web", o, str(opts[o]))
2822 2824
2823 2825 if repo is None and not ui.config("web", "webdir_conf"):
2824 2826 raise error.RepoError(_("There is no Mercurial repository here"
2825 2827 " (.hg not found)"))
2826 2828
2827 2829 class service(object):
2828 2830 def init(self):
2829 2831 util.set_signal_handler()
2830 2832 self.httpd = server.create_server(baseui, repo)
2831 2833
2832 2834 if not ui.verbose:
2833 2835 return
2834 2836
2835 2837 if self.httpd.prefix:
2836 2838 prefix = self.httpd.prefix.strip('/') + '/'
2837 2839 else:
2838 2840 prefix = ''
2839 2841
2840 2842 port = ':%d' % self.httpd.port
2841 2843 if port == ':80':
2842 2844 port = ''
2843 2845
2844 2846 bindaddr = self.httpd.addr
2845 2847 if bindaddr == '0.0.0.0':
2846 2848 bindaddr = '*'
2847 2849 elif ':' in bindaddr: # IPv6
2848 2850 bindaddr = '[%s]' % bindaddr
2849 2851
2850 2852 fqaddr = self.httpd.fqaddr
2851 2853 if ':' in fqaddr:
2852 2854 fqaddr = '[%s]' % fqaddr
2853 2855 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2854 2856 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2855 2857
2856 2858 def run(self):
2857 2859 self.httpd.serve_forever()
2858 2860
2859 2861 service = service()
2860 2862
2861 2863 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2862 2864
2863 2865 def status(ui, repo, *pats, **opts):
2864 2866 """show changed files in the working directory
2865 2867
2866 2868 Show status of files in the repository. If names are given, only
2867 2869 files that match are shown. Files that are clean or ignored or
2868 2870 the source of a copy/move operation, are not listed unless
2869 2871 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
2870 2872 Unless options described with "show only ..." are given, the
2871 2873 options -mardu are used.
2872 2874
2873 2875 Option -q/--quiet hides untracked (unknown and ignored) files
2874 2876 unless explicitly requested with -u/--unknown or -i/--ignored.
2875 2877
2876 2878 NOTE: status may appear to disagree with diff if permissions have
2877 2879 changed or a merge has occurred. The standard diff format does not
2878 2880 report permission changes and diff only reports changes relative
2879 2881 to one merge parent.
2880 2882
2881 2883 If one revision is given, it is used as the base revision.
2882 2884 If two revisions are given, the differences between them are
2883 2885 shown. The --change option can also be used as a shortcut to list
2884 2886 the changed files of a revision from its first parent.
2885 2887
2886 2888 The codes used to show the status of files are::
2887 2889
2888 2890 M = modified
2889 2891 A = added
2890 2892 R = removed
2891 2893 C = clean
2892 2894 ! = missing (deleted by non-hg command, but still tracked)
2893 2895 ? = not tracked
2894 2896 I = ignored
2895 2897 = origin of the previous file listed as A (added)
2896 2898 """
2897 2899
2898 2900 revs = opts.get('rev')
2899 2901 change = opts.get('change')
2900 2902
2901 2903 if revs and change:
2902 2904 msg = _('cannot specify --rev and --change at the same time')
2903 2905 raise util.Abort(msg)
2904 2906 elif change:
2905 2907 node2 = repo.lookup(change)
2906 2908 node1 = repo[node2].parents()[0].node()
2907 2909 else:
2908 2910 node1, node2 = cmdutil.revpair(repo, revs)
2909 2911
2910 2912 cwd = (pats and repo.getcwd()) or ''
2911 2913 end = opts.get('print0') and '\0' or '\n'
2912 2914 copy = {}
2913 2915 states = 'modified added removed deleted unknown ignored clean'.split()
2914 2916 show = [k for k in states if opts.get(k)]
2915 2917 if opts.get('all'):
2916 2918 show += ui.quiet and (states[:4] + ['clean']) or states
2917 2919 if not show:
2918 2920 show = ui.quiet and states[:4] or states[:5]
2919 2921
2920 2922 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2921 2923 'ignored' in show, 'clean' in show, 'unknown' in show)
2922 2924 changestates = zip(states, 'MAR!?IC', stat)
2923 2925
2924 2926 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2925 2927 ctxn = repo[nullid]
2926 2928 ctx1 = repo[node1]
2927 2929 ctx2 = repo[node2]
2928 2930 added = stat[1]
2929 2931 if node2 is None:
2930 2932 added = stat[0] + stat[1] # merged?
2931 2933
2932 2934 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
2933 2935 if k in added:
2934 2936 copy[k] = v
2935 2937 elif v in added:
2936 2938 copy[v] = k
2937 2939
2938 2940 for state, char, files in changestates:
2939 2941 if state in show:
2940 2942 format = "%s %%s%s" % (char, end)
2941 2943 if opts.get('no_status'):
2942 2944 format = "%%s%s" % end
2943 2945
2944 2946 for f in files:
2945 2947 ui.write(format % repo.pathto(f, cwd))
2946 2948 if f in copy:
2947 2949 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2948 2950
2949 2951 def summary(ui, repo, **opts):
2950 2952 """summarize working directory state
2951 2953
2952 2954 This generates a brief summary of the working directory state,
2953 2955 including parents, branch, commit status, and available updates.
2954 2956
2955 2957 With the --remote option, this will check the default paths for
2956 2958 incoming and outgoing changes. This can be time-consuming.
2957 2959 """
2958 2960
2959 2961 ctx = repo[None]
2960 2962 parents = ctx.parents()
2961 2963 pnode = parents[0].node()
2962 2964 tags = repo.tags()
2963 2965
2964 2966 for p in parents:
2965 2967 t = ' '.join([t for t in tags if tags[t] == p.node()])
2966 2968 if p.rev() == -1:
2967 2969 if not len(repo):
2968 2970 t += _(' (empty repository)')
2969 2971 else:
2970 2972 t += _(' (no revision checked out)')
2971 2973 ui.write(_('parent: %d:%s %s\n') % (p.rev(), str(p), t))
2972 2974 if p.description():
2973 2975 ui.status(' ' + p.description().splitlines()[0].strip() + '\n')
2974 2976
2975 2977 branch = ctx.branch()
2976 2978 bheads = repo.branchheads(branch)
2977 2979 m = _('branch: %s\n') % branch
2978 2980 if branch != 'default':
2979 2981 ui.write(m)
2980 2982 else:
2981 2983 ui.status(m)
2982 2984
2983 2985 st = list(repo.status(unknown=True))[:7]
2984 2986 ms = merge_.mergestate(repo)
2985 2987 st.append([f for f in ms if f == 'u'])
2986 2988 labels = [_('%d modified'), _('%d added'), _('%d removed'),
2987 2989 _('%d deleted'), _('%d unknown'), _('%d ignored'),
2988 2990 _('%d unresolved')]
2989 2991 t = []
2990 2992 for s, l in zip(st, labels):
2991 2993 if s:
2992 2994 t.append(l % len(s))
2993 2995
2994 2996 t = ', '.join(t)
2995 2997 cleanworkdir = False
2996 2998
2997 2999 if len(parents) > 1:
2998 3000 t += _(' (merge)')
2999 3001 elif branch != parents[0].branch():
3000 3002 t += _(' (new branch)')
3001 3003 elif (not st[0] and not st[1] and not st[2]):
3002 3004 t += _(' (clean)')
3003 3005 cleanworkdir = True
3004 3006 elif pnode not in bheads:
3005 3007 t += _(' (new branch head)')
3006 3008
3007 3009 if cleanworkdir:
3008 3010 ui.status(_('commit: %s\n') % t.strip())
3009 3011 else:
3010 3012 ui.write(_('commit: %s\n') % t.strip())
3011 3013
3012 3014 # all ancestors of branch heads - all ancestors of parent = new csets
3013 3015 new = [0] * len(repo)
3014 3016 cl = repo.changelog
3015 3017 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3016 3018 new[a] = 1
3017 3019 for a in cl.ancestors(*[p.rev() for p in parents]):
3018 3020 new[a] = 0
3019 3021 new = sum(new)
3020 3022
3021 3023 if new == 0:
3022 3024 ui.status(_('update: (current)\n'))
3023 3025 elif pnode not in bheads:
3024 3026 ui.write(_('update: %d new changesets (update)\n') % new)
3025 3027 else:
3026 3028 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3027 3029 (new, len(bheads)))
3028 3030
3029 3031 if opts.get('remote'):
3030 3032 t = []
3031 3033 source, revs, checkout = hg.parseurl(ui.expandpath('default'),
3032 3034 opts.get('rev'))
3033 3035 other = hg.repository(cmdutil.remoteui(repo, {}), source)
3034 3036 ui.debug('comparing with %s\n' % url.hidepassword(source))
3035 3037 repo.ui.pushbuffer()
3036 3038 common, incoming, rheads = repo.findcommonincoming(other)
3037 3039 repo.ui.popbuffer()
3038 3040 if incoming:
3039 3041 t.append(_('1 or more incoming'))
3040 3042
3041 3043 dest, revs, checkout = hg.parseurl(
3042 3044 ui.expandpath('default-push', 'default'))
3043 3045 other = hg.repository(cmdutil.remoteui(repo, {}), dest)
3044 3046 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3045 3047 repo.ui.pushbuffer()
3046 3048 o = repo.findoutgoing(other)
3047 3049 repo.ui.popbuffer()
3048 3050 o = repo.changelog.nodesbetween(o, revs)[0]
3049 3051 if o:
3050 3052 t.append(_('%d outgoing') % len(o))
3051 3053
3052 3054 if t:
3053 3055 ui.write(_('remote: %s\n') % (', '.join(t)))
3054 3056 else:
3055 3057 ui.status(_('remote: (synced)\n'))
3056 3058
3057 3059 def tag(ui, repo, name1, *names, **opts):
3058 3060 """add one or more tags for the current or given revision
3059 3061
3060 3062 Name a particular revision using <name>.
3061 3063
3062 3064 Tags are used to name particular revisions of the repository and are
3063 3065 very useful to compare different revisions, to go back to significant
3064 3066 earlier versions or to mark branch points as releases, etc.
3065 3067
3066 3068 If no revision is given, the parent of the working directory is
3067 3069 used, or tip if no revision is checked out.
3068 3070
3069 3071 To facilitate version control, distribution, and merging of tags,
3070 3072 they are stored as a file named ".hgtags" which is managed
3071 3073 similarly to other project files and can be hand-edited if
3072 3074 necessary. The file '.hg/localtags' is used for local tags (not
3073 3075 shared among repositories).
3074 3076
3075 3077 See 'hg help dates' for a list of formats valid for -d/--date.
3076 3078 """
3077 3079
3078 3080 rev_ = "."
3079 3081 names = (name1,) + names
3080 3082 if len(names) != len(set(names)):
3081 3083 raise util.Abort(_('tag names must be unique'))
3082 3084 for n in names:
3083 3085 if n in ['tip', '.', 'null']:
3084 3086 raise util.Abort(_('the name \'%s\' is reserved') % n)
3085 3087 if opts.get('rev') and opts.get('remove'):
3086 3088 raise util.Abort(_("--rev and --remove are incompatible"))
3087 3089 if opts.get('rev'):
3088 3090 rev_ = opts['rev']
3089 3091 message = opts.get('message')
3090 3092 if opts.get('remove'):
3091 3093 expectedtype = opts.get('local') and 'local' or 'global'
3092 3094 for n in names:
3093 3095 if not repo.tagtype(n):
3094 3096 raise util.Abort(_('tag \'%s\' does not exist') % n)
3095 3097 if repo.tagtype(n) != expectedtype:
3096 3098 if expectedtype == 'global':
3097 3099 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3098 3100 else:
3099 3101 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3100 3102 rev_ = nullid
3101 3103 if not message:
3102 3104 # we don't translate commit messages
3103 3105 message = 'Removed tag %s' % ', '.join(names)
3104 3106 elif not opts.get('force'):
3105 3107 for n in names:
3106 3108 if n in repo.tags():
3107 3109 raise util.Abort(_('tag \'%s\' already exists '
3108 3110 '(use -f to force)') % n)
3109 3111 if not rev_ and repo.dirstate.parents()[1] != nullid:
3110 3112 raise util.Abort(_('uncommitted merge - please provide a '
3111 3113 'specific revision'))
3112 3114 r = repo[rev_].node()
3113 3115
3114 3116 if not message:
3115 3117 # we don't translate commit messages
3116 3118 message = ('Added tag %s for changeset %s' %
3117 3119 (', '.join(names), short(r)))
3118 3120
3119 3121 date = opts.get('date')
3120 3122 if date:
3121 3123 date = util.parsedate(date)
3122 3124
3123 3125 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3124 3126
3125 3127 def tags(ui, repo):
3126 3128 """list repository tags
3127 3129
3128 3130 This lists both regular and local tags. When the -v/--verbose
3129 3131 switch is used, a third column "local" is printed for local tags.
3130 3132 """
3131 3133
3132 3134 hexfunc = ui.debugflag and hex or short
3133 3135 tagtype = ""
3134 3136
3135 3137 for t, n in reversed(repo.tagslist()):
3136 3138 if ui.quiet:
3137 3139 ui.write("%s\n" % t)
3138 3140 continue
3139 3141
3140 3142 try:
3141 3143 hn = hexfunc(n)
3142 3144 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3143 3145 except error.LookupError:
3144 3146 r = " ?:%s" % hn
3145 3147 else:
3146 3148 spaces = " " * (30 - encoding.colwidth(t))
3147 3149 if ui.verbose:
3148 3150 if repo.tagtype(t) == 'local':
3149 3151 tagtype = " local"
3150 3152 else:
3151 3153 tagtype = ""
3152 3154 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3153 3155
3154 3156 def tip(ui, repo, **opts):
3155 3157 """show the tip revision
3156 3158
3157 3159 The tip revision (usually just called the tip) is the changeset
3158 3160 most recently added to the repository (and therefore the most
3159 3161 recently changed head).
3160 3162
3161 3163 If you have just made a commit, that commit will be the tip. If
3162 3164 you have just pulled changes from another repository, the tip of
3163 3165 that repository becomes the current tip. The "tip" tag is special
3164 3166 and cannot be renamed or assigned to a different changeset.
3165 3167 """
3166 3168 displayer = cmdutil.show_changeset(ui, repo, opts)
3167 3169 displayer.show(repo[len(repo) - 1])
3168 3170 displayer.close()
3169 3171
3170 3172 def unbundle(ui, repo, fname1, *fnames, **opts):
3171 3173 """apply one or more changegroup files
3172 3174
3173 3175 Apply one or more compressed changegroup files generated by the
3174 3176 bundle command.
3175 3177 """
3176 3178 fnames = (fname1,) + fnames
3177 3179
3178 3180 lock = repo.lock()
3179 3181 try:
3180 3182 for fname in fnames:
3181 3183 f = url.open(ui, fname)
3182 3184 gen = changegroup.readbundle(f, fname)
3183 3185 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
3184 3186 finally:
3185 3187 lock.release()
3186 3188
3187 3189 return postincoming(ui, repo, modheads, opts.get('update'), None)
3188 3190
3189 3191 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3190 3192 """update working directory
3191 3193
3192 3194 Update the repository's working directory to the specified
3193 3195 changeset.
3194 3196
3195 3197 If no changeset is specified, attempt to update to the head of the
3196 3198 current branch. If this head is a descendant of the working
3197 3199 directory's parent, update to it, otherwise abort.
3198 3200
3199 3201 The following rules apply when the working directory contains
3200 3202 uncommitted changes:
3201 3203
3202 3204 1. If neither -c/--check nor -C/--clean is specified, and if
3203 3205 the requested changeset is an ancestor or descendant of
3204 3206 the working directory's parent, the uncommitted changes
3205 3207 are merged into the requested changeset and the merged
3206 3208 result is left uncommitted. If the requested changeset is
3207 3209 not an ancestor or descendant (that is, it is on another
3208 3210 branch), the update is aborted and the uncommitted changes
3209 3211 are preserved.
3210 3212
3211 3213 2. With the -c/--check option, the update is aborted and the
3212 3214 uncommitted changes are preserved.
3213 3215
3214 3216 3. With the -C/--clean option, uncommitted changes are discarded and
3215 3217 the working directory is updated to the requested changeset.
3216 3218
3217 3219 Use null as the changeset to remove the working directory (like 'hg
3218 3220 clone -U').
3219 3221
3220 3222 If you want to update just one file to an older changeset, use 'hg revert'.
3221 3223
3222 3224 See 'hg help dates' for a list of formats valid for -d/--date.
3223 3225 """
3224 3226 if rev and node:
3225 3227 raise util.Abort(_("please specify just one revision"))
3226 3228
3227 3229 if not rev:
3228 3230 rev = node
3229 3231
3230 3232 if check and clean:
3231 3233 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3232 3234
3233 3235 if check:
3234 3236 # we could use dirty() but we can ignore merge and branch trivia
3235 3237 c = repo[None]
3236 3238 if c.modified() or c.added() or c.removed():
3237 3239 raise util.Abort(_("uncommitted local changes"))
3238 3240
3239 3241 if date:
3240 3242 if rev:
3241 3243 raise util.Abort(_("you can't specify a revision and a date"))
3242 3244 rev = cmdutil.finddate(ui, repo, date)
3243 3245
3244 3246 if clean or check:
3245 3247 return hg.clean(repo, rev)
3246 3248 else:
3247 3249 return hg.update(repo, rev)
3248 3250
3249 3251 def verify(ui, repo):
3250 3252 """verify the integrity of the repository
3251 3253
3252 3254 Verify the integrity of the current repository.
3253 3255
3254 3256 This will perform an extensive check of the repository's
3255 3257 integrity, validating the hashes and checksums of each entry in
3256 3258 the changelog, manifest, and tracked files, as well as the
3257 3259 integrity of their crosslinks and indices.
3258 3260 """
3259 3261 return hg.verify(repo)
3260 3262
3261 3263 def version_(ui):
3262 3264 """output version and copyright information"""
3263 3265 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3264 3266 % util.version())
3265 3267 ui.status(_(
3266 3268 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3267 3269 "This is free software; see the source for copying conditions. "
3268 3270 "There is NO\nwarranty; "
3269 3271 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3270 3272 ))
3271 3273
3272 3274 # Command options and aliases are listed here, alphabetically
3273 3275
3274 3276 globalopts = [
3275 3277 ('R', 'repository', '',
3276 3278 _('repository root directory or name of overlay bundle file')),
3277 3279 ('', 'cwd', '', _('change working directory')),
3278 3280 ('y', 'noninteractive', None,
3279 3281 _('do not prompt, assume \'yes\' for any required answers')),
3280 3282 ('q', 'quiet', None, _('suppress output')),
3281 3283 ('v', 'verbose', None, _('enable additional output')),
3282 3284 ('', 'config', [], _('set/override config option')),
3283 3285 ('', 'debug', None, _('enable debugging output')),
3284 3286 ('', 'debugger', None, _('start debugger')),
3285 3287 ('', 'encoding', encoding.encoding, _('set the charset encoding')),
3286 3288 ('', 'encodingmode', encoding.encodingmode,
3287 3289 _('set the charset encoding mode')),
3288 3290 ('', 'traceback', None, _('always print a traceback on exception')),
3289 3291 ('', 'time', None, _('time how long the command takes')),
3290 3292 ('', 'profile', None, _('print command execution profile')),
3291 3293 ('', 'version', None, _('output version information and exit')),
3292 3294 ('h', 'help', None, _('display help and exit')),
3293 3295 ]
3294 3296
3295 3297 dryrunopts = [('n', 'dry-run', None,
3296 3298 _('do not perform actions, just print output'))]
3297 3299
3298 3300 remoteopts = [
3299 3301 ('e', 'ssh', '', _('specify ssh command to use')),
3300 3302 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
3301 3303 ]
3302 3304
3303 3305 walkopts = [
3304 3306 ('I', 'include', [], _('include names matching the given patterns')),
3305 3307 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3306 3308 ]
3307 3309
3308 3310 commitopts = [
3309 3311 ('m', 'message', '', _('use <text> as commit message')),
3310 3312 ('l', 'logfile', '', _('read commit message from <file>')),
3311 3313 ]
3312 3314
3313 3315 commitopts2 = [
3314 3316 ('d', 'date', '', _('record datecode as commit date')),
3315 3317 ('u', 'user', '', _('record the specified user as committer')),
3316 3318 ]
3317 3319
3318 3320 templateopts = [
3319 3321 ('', 'style', '', _('display using template map file')),
3320 3322 ('', 'template', '', _('display with template')),
3321 3323 ]
3322 3324
3323 3325 logopts = [
3324 3326 ('p', 'patch', None, _('show patch')),
3325 3327 ('g', 'git', None, _('use git extended diff format')),
3326 3328 ('l', 'limit', '', _('limit number of changes displayed')),
3327 3329 ('M', 'no-merges', None, _('do not show merges')),
3328 3330 ] + templateopts
3329 3331
3330 3332 diffopts = [
3331 3333 ('a', 'text', None, _('treat all files as text')),
3332 3334 ('g', 'git', None, _('use git extended diff format')),
3333 3335 ('', 'nodates', None, _('omit dates from diff headers'))
3334 3336 ]
3335 3337
3336 3338 diffopts2 = [
3337 3339 ('p', 'show-function', None, _('show which function each change is in')),
3338 3340 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3339 3341 ('w', 'ignore-all-space', None,
3340 3342 _('ignore white space when comparing lines')),
3341 3343 ('b', 'ignore-space-change', None,
3342 3344 _('ignore changes in the amount of white space')),
3343 3345 ('B', 'ignore-blank-lines', None,
3344 3346 _('ignore changes whose lines are all blank')),
3345 3347 ('U', 'unified', '', _('number of lines of context to show')),
3346 3348 ('', 'stat', None, _('output diffstat-style summary of changes')),
3347 3349 ]
3348 3350
3349 3351 similarityopts = [
3350 3352 ('s', 'similarity', '',
3351 3353 _('guess renamed files by similarity (0<=s<=100)'))
3352 3354 ]
3353 3355
3354 3356 table = {
3355 3357 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3356 3358 "addremove":
3357 3359 (addremove, similarityopts + walkopts + dryrunopts,
3358 3360 _('[OPTION]... [FILE]...')),
3359 3361 "^annotate|blame":
3360 3362 (annotate,
3361 3363 [('r', 'rev', '', _('annotate the specified revision')),
3362 3364 ('', 'follow', None, _('follow copies and renames (DEPRECATED)')),
3363 3365 ('', 'no-follow', None, _("don't follow copies and renames")),
3364 3366 ('a', 'text', None, _('treat all files as text')),
3365 3367 ('u', 'user', None, _('list the author (long with -v)')),
3366 3368 ('f', 'file', None, _('list the filename')),
3367 3369 ('d', 'date', None, _('list the date (short with -q)')),
3368 3370 ('n', 'number', None, _('list the revision number (default)')),
3369 3371 ('c', 'changeset', None, _('list the changeset')),
3370 3372 ('l', 'line-number', None,
3371 3373 _('show line number at the first appearance'))
3372 3374 ] + walkopts,
3373 3375 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3374 3376 "archive":
3375 3377 (archive,
3376 3378 [('', 'no-decode', None, _('do not pass files through decoders')),
3377 3379 ('p', 'prefix', '', _('directory prefix for files in archive')),
3378 3380 ('r', 'rev', '', _('revision to distribute')),
3379 3381 ('t', 'type', '', _('type of distribution to create')),
3380 3382 ] + walkopts,
3381 3383 _('[OPTION]... DEST')),
3382 3384 "backout":
3383 3385 (backout,
3384 3386 [('', 'merge', None,
3385 3387 _('merge with old dirstate parent after backout')),
3386 3388 ('', 'parent', '', _('parent to choose when backing out merge')),
3387 3389 ('r', 'rev', '', _('revision to backout')),
3388 3390 ] + walkopts + commitopts + commitopts2,
3389 3391 _('[OPTION]... [-r] REV')),
3390 3392 "bisect":
3391 3393 (bisect,
3392 3394 [('r', 'reset', False, _('reset bisect state')),
3393 3395 ('g', 'good', False, _('mark changeset good')),
3394 3396 ('b', 'bad', False, _('mark changeset bad')),
3395 3397 ('s', 'skip', False, _('skip testing changeset')),
3396 3398 ('c', 'command', '', _('use command to check changeset state')),
3397 3399 ('U', 'noupdate', False, _('do not update to target'))],
3398 3400 _("[-gbsr] [-U] [-c CMD] [REV]")),
3399 3401 "branch":
3400 3402 (branch,
3401 3403 [('f', 'force', None,
3402 3404 _('set branch name even if it shadows an existing branch')),
3403 3405 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3404 3406 _('[-fC] [NAME]')),
3405 3407 "branches":
3406 3408 (branches,
3407 3409 [('a', 'active', False,
3408 3410 _('show only branches that have unmerged heads')),
3409 3411 ('c', 'closed', False,
3410 3412 _('show normal and closed branches'))],
3411 3413 _('[-ac]')),
3412 3414 "bundle":
3413 3415 (bundle,
3414 3416 [('f', 'force', None,
3415 3417 _('run even when the destination is unrelated')),
3416 3418 ('r', 'rev', [],
3417 3419 _('a changeset intended to be added to the destination')),
3420 ('b', 'branch', [],
3421 _('a specific branch you would like to bundle')),
3418 3422 ('', 'base', [],
3419 3423 _('a base changeset assumed to be available at the destination')),
3420 3424 ('a', 'all', None, _('bundle all changesets in the repository')),
3421 3425 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3422 3426 ] + remoteopts,
3423 3427 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3424 3428 "cat":
3425 3429 (cat,
3426 3430 [('o', 'output', '', _('print output to file with formatted name')),
3427 3431 ('r', 'rev', '', _('print the given revision')),
3428 3432 ('', 'decode', None, _('apply any matching decode filter')),
3429 3433 ] + walkopts,
3430 3434 _('[OPTION]... FILE...')),
3431 3435 "^clone":
3432 3436 (clone,
3433 3437 [('U', 'noupdate', None,
3434 3438 _('the clone will include an empty working copy (only a repository)')),
3435 3439 ('u', 'updaterev', '',
3436 3440 _('revision, tag or branch to check out')),
3437 3441 ('r', 'rev', [],
3438 3442 _('include the specified changeset')),
3443 ('b', 'branch', [],
3444 _('clone only the specified branch')),
3439 3445 ('', 'pull', None, _('use pull protocol to copy metadata')),
3440 3446 ('', 'uncompressed', None,
3441 3447 _('use uncompressed transfer (fast over LAN)')),
3442 3448 ] + remoteopts,
3443 3449 _('[OPTION]... SOURCE [DEST]')),
3444 3450 "^commit|ci":
3445 3451 (commit,
3446 3452 [('A', 'addremove', None,
3447 3453 _('mark new/missing files as added/removed before committing')),
3448 3454 ('', 'close-branch', None,
3449 3455 _('mark a branch as closed, hiding it from the branch list')),
3450 3456 ] + walkopts + commitopts + commitopts2,
3451 3457 _('[OPTION]... [FILE]...')),
3452 3458 "copy|cp":
3453 3459 (copy,
3454 3460 [('A', 'after', None, _('record a copy that has already occurred')),
3455 3461 ('f', 'force', None,
3456 3462 _('forcibly copy over an existing managed file')),
3457 3463 ] + walkopts + dryrunopts,
3458 3464 _('[OPTION]... [SOURCE]... DEST')),
3459 3465 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3460 3466 "debugcheckstate": (debugcheckstate, [], ''),
3461 3467 "debugcommands": (debugcommands, [], _('[COMMAND]')),
3462 3468 "debugcomplete":
3463 3469 (debugcomplete,
3464 3470 [('o', 'options', None, _('show the command options'))],
3465 3471 _('[-o] CMD')),
3466 3472 "debugdate":
3467 3473 (debugdate,
3468 3474 [('e', 'extended', None, _('try extended date formats'))],
3469 3475 _('[-e] DATE [RANGE]')),
3470 3476 "debugdata": (debugdata, [], _('FILE REV')),
3471 3477 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3472 3478 "debugindex": (debugindex, [], _('FILE')),
3473 3479 "debugindexdot": (debugindexdot, [], _('FILE')),
3474 3480 "debuginstall": (debuginstall, [], ''),
3475 3481 "debugrebuildstate":
3476 3482 (debugrebuildstate,
3477 3483 [('r', 'rev', '', _('revision to rebuild to'))],
3478 3484 _('[-r REV] [REV]')),
3479 3485 "debugrename":
3480 3486 (debugrename,
3481 3487 [('r', 'rev', '', _('revision to debug'))],
3482 3488 _('[-r REV] FILE')),
3483 3489 "debugsetparents":
3484 3490 (debugsetparents, [], _('REV1 [REV2]')),
3485 3491 "debugstate":
3486 3492 (debugstate,
3487 3493 [('', 'nodates', None, _('do not display the saved mtime'))],
3488 3494 _('[OPTION]...')),
3489 3495 "debugsub":
3490 3496 (debugsub,
3491 3497 [('r', 'rev', '', _('revision to check'))],
3492 3498 _('[-r REV] [REV]')),
3493 3499 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3494 3500 "^diff":
3495 3501 (diff,
3496 3502 [('r', 'rev', [], _('revision')),
3497 3503 ('c', 'change', '', _('change made by revision'))
3498 3504 ] + diffopts + diffopts2 + walkopts,
3499 3505 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3500 3506 "^export":
3501 3507 (export,
3502 3508 [('o', 'output', '', _('print output to file with formatted name')),
3503 3509 ('', 'switch-parent', None, _('diff against the second parent')),
3504 3510 ('r', 'rev', [], _('revisions to export')),
3505 3511 ] + diffopts,
3506 3512 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3507 3513 "^forget":
3508 3514 (forget,
3509 3515 [] + walkopts,
3510 3516 _('[OPTION]... FILE...')),
3511 3517 "grep":
3512 3518 (grep,
3513 3519 [('0', 'print0', None, _('end fields with NUL')),
3514 3520 ('', 'all', None, _('print all revisions that match')),
3515 3521 ('f', 'follow', None,
3516 3522 _('follow changeset history,'
3517 3523 ' or file history across copies and renames')),
3518 3524 ('i', 'ignore-case', None, _('ignore case when matching')),
3519 3525 ('l', 'files-with-matches', None,
3520 3526 _('print only filenames and revisions that match')),
3521 3527 ('n', 'line-number', None, _('print matching line numbers')),
3522 3528 ('r', 'rev', [], _('search in given revision range')),
3523 3529 ('u', 'user', None, _('list the author (long with -v)')),
3524 3530 ('d', 'date', None, _('list the date (short with -q)')),
3525 3531 ] + walkopts,
3526 3532 _('[OPTION]... PATTERN [FILE]...')),
3527 3533 "heads":
3528 3534 (heads,
3529 3535 [('r', 'rev', '', _('show only heads which are descendants of REV')),
3530 3536 ('t', 'topo', False, _('show topological heads only')),
3531 3537 ('a', 'active', False,
3532 3538 _('show active branchheads only [DEPRECATED]')),
3533 3539 ('c', 'closed', False,
3534 3540 _('show normal and closed branch heads')),
3535 3541 ] + templateopts,
3536 3542 _('[-ac] [-r STARTREV] [REV]...')),
3537 3543 "help": (help_, [], _('[TOPIC]')),
3538 3544 "identify|id":
3539 3545 (identify,
3540 3546 [('r', 'rev', '', _('identify the specified revision')),
3541 3547 ('n', 'num', None, _('show local revision number')),
3542 3548 ('i', 'id', None, _('show global revision id')),
3543 3549 ('b', 'branch', None, _('show branch')),
3544 3550 ('t', 'tags', None, _('show tags'))],
3545 3551 _('[-nibt] [-r REV] [SOURCE]')),
3546 3552 "import|patch":
3547 3553 (import_,
3548 3554 [('p', 'strip', 1,
3549 3555 _('directory strip option for patch. This has the same '
3550 3556 'meaning as the corresponding patch option')),
3551 3557 ('b', 'base', '', _('base path')),
3552 3558 ('f', 'force', None,
3553 3559 _('skip check for outstanding uncommitted changes')),
3554 3560 ('', 'no-commit', None,
3555 3561 _("don't commit, just update the working directory")),
3556 3562 ('', 'exact', None,
3557 3563 _('apply patch to the nodes from which it was generated')),
3558 3564 ('', 'import-branch', None,
3559 3565 _('use any branch information in patch (implied by --exact)'))] +
3560 3566 commitopts + commitopts2 + similarityopts,
3561 3567 _('[OPTION]... PATCH...')),
3562 3568 "incoming|in":
3563 3569 (incoming,
3564 3570 [('f', 'force', None,
3565 3571 _('run even if remote repository is unrelated')),
3566 3572 ('n', 'newest-first', None, _('show newest record first')),
3567 3573 ('', 'bundle', '', _('file to store the bundles into')),
3568 3574 ('r', 'rev', [],
3569 3575 _('a remote changeset intended to be added')),
3576 ('b', 'branch', [],
3577 _('a specific branch you would like to pull')),
3570 3578 ] + logopts + remoteopts,
3571 3579 _('[-p] [-n] [-M] [-f] [-r REV]...'
3572 3580 ' [--bundle FILENAME] [SOURCE]')),
3573 3581 "^init":
3574 3582 (init,
3575 3583 remoteopts,
3576 3584 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3577 3585 "locate":
3578 3586 (locate,
3579 3587 [('r', 'rev', '', _('search the repository as it is in REV')),
3580 3588 ('0', 'print0', None,
3581 3589 _('end filenames with NUL, for use with xargs')),
3582 3590 ('f', 'fullpath', None,
3583 3591 _('print complete paths from the filesystem root')),
3584 3592 ] + walkopts,
3585 3593 _('[OPTION]... [PATTERN]...')),
3586 3594 "^log|history":
3587 3595 (log,
3588 3596 [('f', 'follow', None,
3589 3597 _('follow changeset history,'
3590 3598 ' or file history across copies and renames')),
3591 3599 ('', 'follow-first', None,
3592 3600 _('only follow the first parent of merge changesets')),
3593 3601 ('d', 'date', '', _('show revisions matching date spec')),
3594 3602 ('C', 'copies', None, _('show copied files')),
3595 3603 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3596 3604 ('r', 'rev', [], _('show the specified revision or range')),
3597 3605 ('', 'removed', None, _('include revisions where files were removed')),
3598 3606 ('m', 'only-merges', None, _('show only merges')),
3599 3607 ('u', 'user', [], _('revisions committed by user')),
3600 3608 ('b', 'only-branch', [],
3601 3609 _('show only changesets within the given named branch')),
3602 3610 ('P', 'prune', [],
3603 3611 _('do not display revision or any of its ancestors')),
3604 3612 ] + logopts + walkopts,
3605 3613 _('[OPTION]... [FILE]')),
3606 3614 "manifest":
3607 3615 (manifest,
3608 3616 [('r', 'rev', '', _('revision to display'))],
3609 3617 _('[-r REV]')),
3610 3618 "^merge":
3611 3619 (merge,
3612 3620 [('f', 'force', None, _('force a merge with outstanding changes')),
3613 3621 ('r', 'rev', '', _('revision to merge')),
3614 3622 ('P', 'preview', None,
3615 3623 _('review revisions to merge (no merge is performed)'))],
3616 3624 _('[-P] [-f] [[-r] REV]')),
3617 3625 "outgoing|out":
3618 3626 (outgoing,
3619 3627 [('f', 'force', None,
3620 3628 _('run even when the destination is unrelated')),
3621 3629 ('r', 'rev', [],
3622 3630 _('a changeset intended to be included in the destination')),
3623 3631 ('n', 'newest-first', None, _('show newest record first')),
3632 ('b', 'branch', [],
3633 _('a specific branch you would like to push')),
3624 3634 ] + logopts + remoteopts,
3625 3635 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3626 3636 "parents":
3627 3637 (parents,
3628 3638 [('r', 'rev', '', _('show parents of the specified revision')),
3629 3639 ] + templateopts,
3630 3640 _('[-r REV] [FILE]')),
3631 3641 "paths": (paths, [], _('[NAME]')),
3632 3642 "^pull":
3633 3643 (pull,
3634 3644 [('u', 'update', None,
3635 3645 _('update to new branch head if changesets were pulled')),
3636 3646 ('f', 'force', None,
3637 3647 _('run even when remote repository is unrelated')),
3638 3648 ('r', 'rev', [],
3639 3649 _('a remote changeset intended to be added')),
3650 ('b', 'branch', [],
3651 _('a specific branch you would like to pull')),
3640 3652 ] + remoteopts,
3641 3653 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3642 3654 "^push":
3643 3655 (push,
3644 3656 [('f', 'force', None, _('force push')),
3645 3657 ('r', 'rev', [],
3646 3658 _('a changeset intended to be included in the destination')),
3659 ('b', 'branch', [],
3660 _('a specific branch you would like to push')),
3647 3661 ] + remoteopts,
3648 3662 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3649 3663 "recover": (recover, []),
3650 3664 "^remove|rm":
3651 3665 (remove,
3652 3666 [('A', 'after', None, _('record delete for missing files')),
3653 3667 ('f', 'force', None,
3654 3668 _('remove (and delete) file even if added or modified')),
3655 3669 ] + walkopts,
3656 3670 _('[OPTION]... FILE...')),
3657 3671 "rename|mv":
3658 3672 (rename,
3659 3673 [('A', 'after', None, _('record a rename that has already occurred')),
3660 3674 ('f', 'force', None,
3661 3675 _('forcibly copy over an existing managed file')),
3662 3676 ] + walkopts + dryrunopts,
3663 3677 _('[OPTION]... SOURCE... DEST')),
3664 3678 "resolve":
3665 3679 (resolve,
3666 3680 [('a', 'all', None, _('select all unresolved files')),
3667 3681 ('l', 'list', None, _('list state of files needing merge')),
3668 3682 ('m', 'mark', None, _('mark files as resolved')),
3669 3683 ('u', 'unmark', None, _('unmark files as resolved')),
3670 3684 ('n', 'no-status', None, _('hide status prefix'))]
3671 3685 + walkopts,
3672 3686 _('[OPTION]... [FILE]...')),
3673 3687 "revert":
3674 3688 (revert,
3675 3689 [('a', 'all', None, _('revert all changes when no arguments given')),
3676 3690 ('d', 'date', '', _('tipmost revision matching date')),
3677 3691 ('r', 'rev', '', _('revert to the specified revision')),
3678 3692 ('', 'no-backup', None, _('do not save backup copies of files')),
3679 3693 ] + walkopts + dryrunopts,
3680 3694 _('[OPTION]... [-r REV] [NAME]...')),
3681 3695 "rollback": (rollback, []),
3682 3696 "root": (root, []),
3683 3697 "^serve":
3684 3698 (serve,
3685 3699 [('A', 'accesslog', '', _('name of access log file to write to')),
3686 3700 ('d', 'daemon', None, _('run server in background')),
3687 3701 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3688 3702 ('E', 'errorlog', '', _('name of error log file to write to')),
3689 3703 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3690 3704 ('a', 'address', '',
3691 3705 _('address to listen on (default: all interfaces)')),
3692 3706 ('', 'prefix', '',
3693 3707 _('prefix path to serve from (default: server root)')),
3694 3708 ('n', 'name', '',
3695 3709 _('name to show in web pages (default: working directory)')),
3696 3710 ('', 'webdir-conf', '', _('name of the webdir config file'
3697 3711 ' (serve more than one repository)')),
3698 3712 ('', 'pid-file', '', _('name of file to write process ID to')),
3699 3713 ('', 'stdio', None, _('for remote clients')),
3700 3714 ('t', 'templates', '', _('web templates to use')),
3701 3715 ('', 'style', '', _('template style to use')),
3702 3716 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3703 3717 ('', 'certificate', '', _('SSL certificate file'))],
3704 3718 _('[OPTION]...')),
3705 3719 "showconfig|debugconfig":
3706 3720 (showconfig,
3707 3721 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3708 3722 _('[-u] [NAME]...')),
3709 3723 "^summary|sum":
3710 3724 (summary,
3711 3725 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
3712 3726 "^status|st":
3713 3727 (status,
3714 3728 [('A', 'all', None, _('show status of all files')),
3715 3729 ('m', 'modified', None, _('show only modified files')),
3716 3730 ('a', 'added', None, _('show only added files')),
3717 3731 ('r', 'removed', None, _('show only removed files')),
3718 3732 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3719 3733 ('c', 'clean', None, _('show only files without changes')),
3720 3734 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3721 3735 ('i', 'ignored', None, _('show only ignored files')),
3722 3736 ('n', 'no-status', None, _('hide status prefix')),
3723 3737 ('C', 'copies', None, _('show source of copied files')),
3724 3738 ('0', 'print0', None,
3725 3739 _('end filenames with NUL, for use with xargs')),
3726 3740 ('', 'rev', [], _('show difference from revision')),
3727 3741 ('', 'change', '', _('list the changed files of a revision')),
3728 3742 ] + walkopts,
3729 3743 _('[OPTION]... [FILE]...')),
3730 3744 "tag":
3731 3745 (tag,
3732 3746 [('f', 'force', None, _('replace existing tag')),
3733 3747 ('l', 'local', None, _('make the tag local')),
3734 3748 ('r', 'rev', '', _('revision to tag')),
3735 3749 ('', 'remove', None, _('remove a tag')),
3736 3750 # -l/--local is already there, commitopts cannot be used
3737 3751 ('m', 'message', '', _('use <text> as commit message')),
3738 3752 ] + commitopts2,
3739 3753 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3740 3754 "tags": (tags, [], ''),
3741 3755 "tip":
3742 3756 (tip,
3743 3757 [('p', 'patch', None, _('show patch')),
3744 3758 ('g', 'git', None, _('use git extended diff format')),
3745 3759 ] + templateopts,
3746 3760 _('[-p] [-g]')),
3747 3761 "unbundle":
3748 3762 (unbundle,
3749 3763 [('u', 'update', None,
3750 3764 _('update to new branch head if changesets were unbundled'))],
3751 3765 _('[-u] FILE...')),
3752 3766 "^update|up|checkout|co":
3753 3767 (update,
3754 3768 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
3755 3769 ('c', 'check', None, _('check for uncommitted changes')),
3756 3770 ('d', 'date', '', _('tipmost revision matching date')),
3757 3771 ('r', 'rev', '', _('revision'))],
3758 3772 _('[-c] [-C] [-d DATE] [[-r] REV]')),
3759 3773 "verify": (verify, []),
3760 3774 "version": (version_, []),
3761 3775 }
3762 3776
3763 3777 norepo = ("clone init version help debugcommands debugcomplete debugdata"
3764 3778 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3765 3779 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,389 +1,391 b''
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from i18n import _
10 10 from lock import release
11 11 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
12 12 import lock, util, extensions, error, encoding, node
13 13 import merge as _merge
14 14 import verify as _verify
15 15 import errno, os, shutil
16 16
17 17 def _local(path):
18 18 return (os.path.isfile(util.drop_scheme('file', path)) and
19 19 bundlerepo or localrepo)
20 20
21 21 def addbranchrevs(lrepo, repo, branches, revs):
22 22 if not branches:
23 23 return revs or None, revs and revs[0] or None
24 24 branchmap = repo.branchmap()
25 25 revs = revs and list(revs) or []
26 26 for branch in branches:
27 27 if branch == '.':
28 28 if not lrepo or not lrepo.local():
29 29 raise util.Abort(_("dirstate branch not accessible"))
30 30 revs.append(lrepo.dirstate.branch())
31 31 else:
32 32 butf8 = encoding.fromlocal(branch)
33 33 if butf8 in branchmap:
34 34 revs.extend(node.hex(r) for r in reversed(branchmap[butf8]))
35 35 else:
36 36 revs.append(branch)
37 37 return revs, revs[0]
38 38
39 39 def parseurl(url, branches=None):
40 40 '''parse url#branch, returning url, branches+[branch]'''
41 41
42 42 if '#' not in url:
43 43 return url, branches or []
44 44 url, branch = url.split('#', 1)
45 45 return url, (branches or []) + [branch]
46 46
47 47 schemes = {
48 48 'bundle': bundlerepo,
49 49 'file': _local,
50 50 'http': httprepo,
51 51 'https': httprepo,
52 52 'ssh': sshrepo,
53 53 'static-http': statichttprepo,
54 54 }
55 55
56 56 def _lookup(path):
57 57 scheme = 'file'
58 58 if path:
59 59 c = path.find(':')
60 60 if c > 0:
61 61 scheme = path[:c]
62 62 thing = schemes.get(scheme) or schemes['file']
63 63 try:
64 64 return thing(path)
65 65 except TypeError:
66 66 return thing
67 67
68 68 def islocal(repo):
69 69 '''return true if repo or path is local'''
70 70 if isinstance(repo, str):
71 71 try:
72 72 return _lookup(repo).islocal(repo)
73 73 except AttributeError:
74 74 return False
75 75 return repo.local()
76 76
77 77 def repository(ui, path='', create=False):
78 78 """return a repository object for the specified path"""
79 79 repo = _lookup(path).instance(ui, path, create)
80 80 ui = getattr(repo, "ui", ui)
81 81 for name, module in extensions.extensions():
82 82 hook = getattr(module, 'reposetup', None)
83 83 if hook:
84 84 hook(ui, repo)
85 85 return repo
86 86
87 87 def defaultdest(source):
88 88 '''return default destination of clone if none is given'''
89 89 return os.path.basename(os.path.normpath(source))
90 90
91 91 def localpath(path):
92 92 if path.startswith('file://localhost/'):
93 93 return path[16:]
94 94 if path.startswith('file://'):
95 95 return path[7:]
96 96 if path.startswith('file:'):
97 97 return path[5:]
98 98 return path
99 99
100 100 def share(ui, source, dest=None, update=True):
101 101 '''create a shared repository'''
102 102
103 103 if not islocal(source):
104 104 raise util.Abort(_('can only share local repositories'))
105 105
106 106 if not dest:
107 107 dest = defaultdest(source)
108 108 else:
109 109 dest = ui.expandpath(dest)
110 110
111 111 if isinstance(source, str):
112 112 origsource = ui.expandpath(source)
113 113 source, branches = parseurl(origsource)
114 114 srcrepo = repository(ui, source)
115 115 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
116 116 else:
117 117 srcrepo = source
118 118 origsource = source = srcrepo.url()
119 119 checkout = None
120 120
121 121 sharedpath = srcrepo.sharedpath # if our source is already sharing
122 122
123 123 root = os.path.realpath(dest)
124 124 roothg = os.path.join(root, '.hg')
125 125
126 126 if os.path.exists(roothg):
127 127 raise util.Abort(_('destination already exists'))
128 128
129 129 if not os.path.isdir(root):
130 130 os.mkdir(root)
131 131 os.mkdir(roothg)
132 132
133 133 requirements = ''
134 134 try:
135 135 requirements = srcrepo.opener('requires').read()
136 136 except IOError, inst:
137 137 if inst.errno != errno.ENOENT:
138 138 raise
139 139
140 140 requirements += 'shared\n'
141 141 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
142 142 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
143 143
144 144 default = srcrepo.ui.config('paths', 'default')
145 145 if default:
146 146 f = file(os.path.join(roothg, 'hgrc'), 'w')
147 147 f.write('[paths]\ndefault = %s\n' % default)
148 148 f.close()
149 149
150 150 r = repository(ui, root)
151 151
152 152 if update:
153 153 r.ui.status(_("updating working directory\n"))
154 154 if update is not True:
155 155 checkout = update
156 156 for test in (checkout, 'default', 'tip'):
157 157 if test is None:
158 158 continue
159 159 try:
160 160 uprev = r.lookup(test)
161 161 break
162 162 except error.RepoLookupError:
163 163 continue
164 164 _update(r, uprev)
165 165
166 166 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
167 stream=False):
167 stream=False, branch=None):
168 168 """Make a copy of an existing repository.
169 169
170 170 Create a copy of an existing repository in a new directory. The
171 171 source and destination are URLs, as passed to the repository
172 172 function. Returns a pair of repository objects, the source and
173 173 newly created destination.
174 174
175 175 The location of the source is added to the new repository's
176 176 .hg/hgrc file, as the default to be used for future pulls and
177 177 pushes.
178 178
179 179 If an exception is raised, the partly cloned/updated destination
180 180 repository will be deleted.
181 181
182 182 Arguments:
183 183
184 184 source: repository object or URL
185 185
186 186 dest: URL of destination repository to create (defaults to base
187 187 name of source repository)
188 188
189 189 pull: always pull from source repository, even in local case
190 190
191 191 stream: stream raw data uncompressed from repository (fast over
192 192 LAN, slow over WAN)
193 193
194 194 rev: revision to clone up to (implies pull=True)
195 195
196 196 update: update working directory after clone completes, if
197 197 destination is local repository (True means update to default rev,
198 198 anything else is treated as a revision)
199
200 branch: branches to clone
199 201 """
200 202
201 203 if isinstance(source, str):
202 204 origsource = ui.expandpath(source)
203 source, branch = parseurl(origsource)
205 source, branch = parseurl(origsource, branch)
204 206 src_repo = repository(ui, source)
205 207 else:
206 208 src_repo = source
207 209 origsource = source = src_repo.url()
208 210 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
209 211
210 212 if dest is None:
211 213 dest = defaultdest(source)
212 214 ui.status(_("destination directory: %s\n") % dest)
213 215 else:
214 216 dest = ui.expandpath(dest)
215 217
216 218 dest = localpath(dest)
217 219 source = localpath(source)
218 220
219 221 if os.path.exists(dest):
220 222 if not os.path.isdir(dest):
221 223 raise util.Abort(_("destination '%s' already exists") % dest)
222 224 elif os.listdir(dest):
223 225 raise util.Abort(_("destination '%s' is not empty") % dest)
224 226
225 227 class DirCleanup(object):
226 228 def __init__(self, dir_):
227 229 self.rmtree = shutil.rmtree
228 230 self.dir_ = dir_
229 231 def close(self):
230 232 self.dir_ = None
231 233 def cleanup(self):
232 234 if self.dir_:
233 235 self.rmtree(self.dir_, True)
234 236
235 237 src_lock = dest_lock = dir_cleanup = None
236 238 try:
237 239 if islocal(dest):
238 240 dir_cleanup = DirCleanup(dest)
239 241
240 242 abspath = origsource
241 243 copy = False
242 244 if src_repo.cancopy() and islocal(dest):
243 245 abspath = os.path.abspath(util.drop_scheme('file', origsource))
244 246 copy = not pull and not rev
245 247
246 248 if copy:
247 249 try:
248 250 # we use a lock here because if we race with commit, we
249 251 # can end up with extra data in the cloned revlogs that's
250 252 # not pointed to by changesets, thus causing verify to
251 253 # fail
252 254 src_lock = src_repo.lock(wait=False)
253 255 except error.LockError:
254 256 copy = False
255 257
256 258 if copy:
257 259 src_repo.hook('preoutgoing', throw=True, source='clone')
258 260 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
259 261 if not os.path.exists(dest):
260 262 os.mkdir(dest)
261 263 else:
262 264 # only clean up directories we create ourselves
263 265 dir_cleanup.dir_ = hgdir
264 266 try:
265 267 dest_path = hgdir
266 268 os.mkdir(dest_path)
267 269 except OSError, inst:
268 270 if inst.errno == errno.EEXIST:
269 271 dir_cleanup.close()
270 272 raise util.Abort(_("destination '%s' already exists")
271 273 % dest)
272 274 raise
273 275
274 276 for f in src_repo.store.copylist():
275 277 src = os.path.join(src_repo.sharedpath, f)
276 278 dst = os.path.join(dest_path, f)
277 279 dstbase = os.path.dirname(dst)
278 280 if dstbase and not os.path.exists(dstbase):
279 281 os.mkdir(dstbase)
280 282 if os.path.exists(src):
281 283 if dst.endswith('data'):
282 284 # lock to avoid premature writing to the target
283 285 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
284 286 util.copyfiles(src, dst)
285 287
286 288 # we need to re-init the repo after manually copying the data
287 289 # into it
288 290 dest_repo = repository(ui, dest)
289 291 src_repo.hook('outgoing', source='clone', node='0'*40)
290 292 else:
291 293 try:
292 294 dest_repo = repository(ui, dest, create=True)
293 295 except OSError, inst:
294 296 if inst.errno == errno.EEXIST:
295 297 dir_cleanup.close()
296 298 raise util.Abort(_("destination '%s' already exists")
297 299 % dest)
298 300 raise
299 301
300 302 revs = None
301 303 if rev:
302 304 if 'lookup' not in src_repo.capabilities:
303 305 raise util.Abort(_("src repository does not support "
304 306 "revision lookup and so doesn't "
305 307 "support clone by revision"))
306 308 revs = [src_repo.lookup(r) for r in rev]
307 309 checkout = revs[0]
308 310 if dest_repo.local():
309 311 dest_repo.clone(src_repo, heads=revs, stream=stream)
310 312 elif src_repo.local():
311 313 src_repo.push(dest_repo, revs=revs)
312 314 else:
313 315 raise util.Abort(_("clone from remote to remote not supported"))
314 316
315 317 if dir_cleanup:
316 318 dir_cleanup.close()
317 319
318 320 if dest_repo.local():
319 321 fp = dest_repo.opener("hgrc", "w", text=True)
320 322 fp.write("[paths]\n")
321 323 fp.write("default = %s\n" % abspath)
322 324 fp.close()
323 325
324 326 dest_repo.ui.setconfig('paths', 'default', abspath)
325 327
326 328 if update:
327 329 if update is not True:
328 330 checkout = update
329 331 if src_repo.local():
330 332 checkout = src_repo.lookup(update)
331 333 for test in (checkout, 'default', 'tip'):
332 334 if test is None:
333 335 continue
334 336 try:
335 337 uprev = dest_repo.lookup(test)
336 338 break
337 339 except error.RepoLookupError:
338 340 continue
339 341 bn = dest_repo[uprev].branch()
340 342 dest_repo.ui.status(_("updating to branch %s\n")
341 343 % encoding.tolocal(bn))
342 344 _update(dest_repo, uprev)
343 345
344 346 return src_repo, dest_repo
345 347 finally:
346 348 release(src_lock, dest_lock)
347 349 if dir_cleanup is not None:
348 350 dir_cleanup.cleanup()
349 351
350 352 def _showstats(repo, stats):
351 353 repo.ui.status(_("%d files updated, %d files merged, "
352 354 "%d files removed, %d files unresolved\n") % stats)
353 355
354 356 def update(repo, node):
355 357 """update the working directory to node, merging linear changes"""
356 358 stats = _merge.update(repo, node, False, False, None)
357 359 _showstats(repo, stats)
358 360 if stats[3]:
359 361 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
360 362 return stats[3] > 0
361 363
362 364 # naming conflict in clone()
363 365 _update = update
364 366
365 367 def clean(repo, node, show_stats=True):
366 368 """forcibly switch the working directory to node, clobbering changes"""
367 369 stats = _merge.update(repo, node, False, True, None)
368 370 if show_stats:
369 371 _showstats(repo, stats)
370 372 return stats[3] > 0
371 373
372 374 def merge(repo, node, force=None, remind=True):
373 375 """branch merge with node, resolving changes"""
374 376 stats = _merge.update(repo, node, True, force, False)
375 377 _showstats(repo, stats)
376 378 if stats[3]:
377 379 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
378 380 "or 'hg update -C' to abandon\n"))
379 381 elif remind:
380 382 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
381 383 return stats[3] > 0
382 384
383 385 def revert(repo, node, choose):
384 386 """revert changes to revision in node without updating dirstate"""
385 387 return _merge.update(repo, node, False, True, choose)[3] > 0
386 388
387 389 def verify(repo):
388 390 """verify the consistency of a repository"""
389 391 return _verify.verify(repo)
@@ -1,41 +1,43 b''
1 1 #!/bin/sh
2 2
3 3 # test branch selection options
4 4 hg init branch
5 5 cd branch
6 6 hg branch a
7 7 echo a > foo
8 8 hg ci -d '0 0' -Ama
9 9 echo a2 > foo
10 10 hg ci -d '0 0' -ma2
11 11 hg up 0
12 12 hg branch c
13 13 echo c > foo
14 14 hg ci -d '0 0' -mc
15 15 cd ..
16 16 hg clone -r 0 branch branch2
17 17 cd branch2
18 18 hg up 0
19 19 hg branch b
20 20 echo b > foo
21 21 hg ci -d '0 0' -mb
22 22 hg up 0
23 23 hg branch -f b
24 24 echo b2 > foo
25 25 hg ci -d '0 0' -mb2
26 26
27 27 echo in rev c branch a
28 28 hg in -qr c ../branch#a
29 hg in -qr c -b a
29 30 echo out branch .
30 31 hg out -q ../branch#.
32 hg out -q -b .
31 33 echo clone branch b
32 34 cd ..
33 35 hg clone branch2#b branch3
34 36 hg -q -R branch3 heads b
35 37 hg -q -R branch3 parents
36 38 rm -rf branch3
37 39 echo clone rev a branch b
38 40 hg clone -r a branch2#b branch3
39 41 hg -q -R branch3 heads b
40 42 hg -q -R branch3 parents
41 43 rm -rf branch3
@@ -1,44 +1,47 b''
1 1 marked working directory as branch a
2 2 adding foo
3 3 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 4 marked working directory as branch c
5 5 created new head
6 6 requesting all changes
7 7 adding changesets
8 8 adding manifests
9 9 adding file changes
10 10 added 1 changesets with 1 changes to 1 files
11 11 updating to branch a
12 12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 13 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
14 14 marked working directory as branch b
15 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 marked working directory as branch b
17 17 created new head
18 18 in rev c branch a
19 19 1:dd6e60a716c6
20 20 2:f25d57ab0566
21 1:dd6e60a716c6
22 2:f25d57ab0566
21 23 out branch .
22 24 2:65511d0e2b55
25 2:65511d0e2b55
23 26 clone branch b
24 27 requesting all changes
25 28 adding changesets
26 29 adding manifests
27 30 adding file changes
28 31 added 3 changesets with 3 changes to 1 files (+1 heads)
29 32 updating to branch b
30 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 34 2:65511d0e2b55
32 35 1:b84708d77ab7
33 36 2:65511d0e2b55
34 37 clone rev a branch b
35 38 requesting all changes
36 39 adding changesets
37 40 adding manifests
38 41 adding file changes
39 42 added 3 changesets with 3 changes to 1 files (+1 heads)
40 43 updating to branch a
41 44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 45 2:65511d0e2b55
43 46 1:b84708d77ab7
44 47 0:5b65ba7c951d
@@ -1,231 +1,231 b''
1 1 % Show all commands except debug commands
2 2 add
3 3 addremove
4 4 annotate
5 5 archive
6 6 backout
7 7 bisect
8 8 branch
9 9 branches
10 10 bundle
11 11 cat
12 12 clone
13 13 commit
14 14 copy
15 15 diff
16 16 export
17 17 forget
18 18 grep
19 19 heads
20 20 help
21 21 identify
22 22 import
23 23 incoming
24 24 init
25 25 locate
26 26 log
27 27 manifest
28 28 merge
29 29 outgoing
30 30 parents
31 31 paths
32 32 pull
33 33 push
34 34 recover
35 35 remove
36 36 rename
37 37 resolve
38 38 revert
39 39 rollback
40 40 root
41 41 serve
42 42 showconfig
43 43 status
44 44 summary
45 45 tag
46 46 tags
47 47 tip
48 48 unbundle
49 49 update
50 50 verify
51 51 version
52 52
53 53 % Show all commands that start with "a"
54 54 add
55 55 addremove
56 56 annotate
57 57 archive
58 58
59 59 % Do not show debug commands if there are other candidates
60 60 diff
61 61
62 62 % Show debug commands if there are no other candidates
63 63 debugancestor
64 64 debugcheckstate
65 65 debugcommands
66 66 debugcomplete
67 67 debugconfig
68 68 debugdata
69 69 debugdate
70 70 debugfsinfo
71 71 debugindex
72 72 debugindexdot
73 73 debuginstall
74 74 debugrebuildstate
75 75 debugrename
76 76 debugsetparents
77 77 debugstate
78 78 debugsub
79 79 debugwalk
80 80
81 81 % Do not show the alias of a debug command if there are other candidates
82 82 % (this should hide rawcommit)
83 83 recover
84 84 remove
85 85 rename
86 86 resolve
87 87 revert
88 88 rollback
89 89 root
90 90
91 91 % Show the alias of a debug command if there are no other candidates
92 92
93 93
94 94 % Show the global options
95 95 --config
96 96 --cwd
97 97 --debug
98 98 --debugger
99 99 --encoding
100 100 --encodingmode
101 101 --help
102 102 --noninteractive
103 103 --profile
104 104 --quiet
105 105 --repository
106 106 --time
107 107 --traceback
108 108 --verbose
109 109 --version
110 110 -R
111 111 -h
112 112 -q
113 113 -v
114 114 -y
115 115
116 116 % Show the options for the "serve" command
117 117 --accesslog
118 118 --address
119 119 --certificate
120 120 --config
121 121 --cwd
122 122 --daemon
123 123 --daemon-pipefds
124 124 --debug
125 125 --debugger
126 126 --encoding
127 127 --encodingmode
128 128 --errorlog
129 129 --help
130 130 --ipv6
131 131 --name
132 132 --noninteractive
133 133 --pid-file
134 134 --port
135 135 --prefix
136 136 --profile
137 137 --quiet
138 138 --repository
139 139 --stdio
140 140 --style
141 141 --templates
142 142 --time
143 143 --traceback
144 144 --verbose
145 145 --version
146 146 --webdir-conf
147 147 -6
148 148 -A
149 149 -E
150 150 -R
151 151 -a
152 152 -d
153 153 -h
154 154 -n
155 155 -p
156 156 -q
157 157 -t
158 158 -v
159 159 -y
160 160
161 161 % Show an error if we use --options with an ambiguous abbreviation
162 162 hg: command 's' is ambiguous:
163 163 serve showconfig status summary
164 164
165 165 % Show all commands + options
166 166 add: include, exclude, dry-run
167 167 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
168 clone: noupdate, updaterev, rev, pull, uncompressed, ssh, remotecmd
168 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd
169 169 commit: addremove, close-branch, include, exclude, message, logfile, date, user
170 170 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude
171 171 export: output, switch-parent, rev, text, git, nodates
172 172 forget: include, exclude
173 173 init: ssh, remotecmd
174 174 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, prune, patch, git, limit, no-merges, style, template, include, exclude
175 175 merge: force, rev, preview
176 pull: update, force, rev, ssh, remotecmd
177 push: force, rev, ssh, remotecmd
176 pull: update, force, rev, branch, ssh, remotecmd
177 push: force, rev, branch, ssh, remotecmd
178 178 remove: after, force, include, exclude
179 179 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
180 180 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude
181 181 summary: remote
182 182 update: clean, check, date, rev
183 183 addremove: similarity, include, exclude, dry-run
184 184 archive: no-decode, prefix, rev, type, include, exclude
185 185 backout: merge, parent, rev, include, exclude, message, logfile, date, user
186 186 bisect: reset, good, bad, skip, command, noupdate
187 187 branch: force, clean
188 188 branches: active, closed
189 bundle: force, rev, base, all, type, ssh, remotecmd
189 bundle: force, rev, branch, base, all, type, ssh, remotecmd
190 190 cat: output, rev, decode, include, exclude
191 191 copy: after, force, include, exclude, dry-run
192 192 debugancestor:
193 193 debugcheckstate:
194 194 debugcommands:
195 195 debugcomplete: options
196 196 debugdata:
197 197 debugdate: extended
198 198 debugfsinfo:
199 199 debugindex:
200 200 debugindexdot:
201 201 debuginstall:
202 202 debugrebuildstate: rev
203 203 debugrename: rev
204 204 debugsetparents:
205 205 debugstate: nodates
206 206 debugsub: rev
207 207 debugwalk: include, exclude
208 208 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
209 209 heads: rev, topo, active, closed, style, template
210 210 help:
211 211 identify: rev, num, id, branch, tags
212 212 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
213 incoming: force, newest-first, bundle, rev, patch, git, limit, no-merges, style, template, ssh, remotecmd
213 incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, style, template, ssh, remotecmd
214 214 locate: rev, print0, fullpath, include, exclude
215 215 manifest: rev
216 outgoing: force, rev, newest-first, patch, git, limit, no-merges, style, template, ssh, remotecmd
216 outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, style, template, ssh, remotecmd
217 217 parents: rev, style, template
218 218 paths:
219 219 recover:
220 220 rename: after, force, include, exclude, dry-run
221 221 resolve: all, list, mark, unmark, no-status, include, exclude
222 222 revert: all, date, rev, no-backup, include, exclude, dry-run
223 223 rollback:
224 224 root:
225 225 showconfig: untrusted
226 226 tag: force, local, rev, remove, message, date, user
227 227 tags:
228 228 tip: patch, git, style, template
229 229 unbundle: update
230 230 verify:
231 231 version:
General Comments 0
You need to be logged in to leave comments. Login now