##// END OF EJS Templates
status: use match helpers for various users
Matt Mackall -
r6599:cd4db399 default
parent child Browse files
Show More
@@ -1,357 +1,358 b''
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7 #
7 #
8 # The hgk extension allows browsing the history of a repository in a
8 # The hgk extension allows browsing the history of a repository in a
9 # graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is
9 # graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is
10 # not distributed with Mercurial.)
10 # not distributed with Mercurial.)
11 #
11 #
12 # hgk consists of two parts: a Tcl script that does the displaying and
12 # hgk consists of two parts: a Tcl script that does the displaying and
13 # querying of information, and an extension to mercurial named hgk.py,
13 # querying of information, and an extension to mercurial named hgk.py,
14 # which provides hooks for hgk to get information. hgk can be found in
14 # which provides hooks for hgk to get information. hgk can be found in
15 # the contrib directory, and hgk.py can be found in the hgext
15 # the contrib directory, and hgk.py can be found in the hgext
16 # directory.
16 # directory.
17 #
17 #
18 # To load the hgext.py extension, add it to your .hgrc file (you have
18 # To load the hgext.py extension, add it to your .hgrc file (you have
19 # to use your global $HOME/.hgrc file, not one in a repository). You
19 # to use your global $HOME/.hgrc file, not one in a repository). You
20 # can specify an absolute path:
20 # can specify an absolute path:
21 #
21 #
22 # [extensions]
22 # [extensions]
23 # hgk=/usr/local/lib/hgk.py
23 # hgk=/usr/local/lib/hgk.py
24 #
24 #
25 # Mercurial can also scan the default python library path for a file
25 # Mercurial can also scan the default python library path for a file
26 # named 'hgk.py' if you set hgk empty:
26 # named 'hgk.py' if you set hgk empty:
27 #
27 #
28 # [extensions]
28 # [extensions]
29 # hgk=
29 # hgk=
30 #
30 #
31 # The hg view command will launch the hgk Tcl script. For this command
31 # The hg view command will launch the hgk Tcl script. For this command
32 # to work, hgk must be in your search path. Alternately, you can
32 # to work, hgk must be in your search path. Alternately, you can
33 # specify the path to hgk in your .hgrc file:
33 # specify the path to hgk in your .hgrc file:
34 #
34 #
35 # [hgk]
35 # [hgk]
36 # path=/location/of/hgk
36 # path=/location/of/hgk
37 #
37 #
38 # hgk can make use of the extdiff extension to visualize
38 # hgk can make use of the extdiff extension to visualize
39 # revisions. Assuming you had already configured extdiff vdiff
39 # revisions. Assuming you had already configured extdiff vdiff
40 # command, just add:
40 # command, just add:
41 #
41 #
42 # [hgk]
42 # [hgk]
43 # vdiff=vdiff
43 # vdiff=vdiff
44 #
44 #
45 # Revisions context menu will now display additional entries to fire
45 # Revisions context menu will now display additional entries to fire
46 # vdiff on hovered and selected revisions.
46 # vdiff on hovered and selected revisions.
47
47
48 import os
48 import os
49 from mercurial import commands, util, patch, revlog
49 from mercurial import commands, util, patch, revlog, cmdutil
50 from mercurial.node import nullid, nullrev, short
50 from mercurial.node import nullid, nullrev, short
51
51
52 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
52 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
53 """diff trees from two commits"""
53 """diff trees from two commits"""
54 def __difftree(repo, node1, node2, files=[]):
54 def __difftree(repo, node1, node2, files=[]):
55 assert node2 is not None
55 assert node2 is not None
56 mmap = repo.changectx(node1).manifest()
56 mmap = repo.changectx(node1).manifest()
57 mmap2 = repo.changectx(node2).manifest()
57 mmap2 = repo.changectx(node2).manifest()
58 status = repo.status(node1, node2, files=files)[:5]
58 m = cmdutil.matchfiles(repo, files)
59 status = repo.status(node1, node2, files=m.files(), match=m)[:5]
59 modified, added, removed, deleted, unknown = status
60 modified, added, removed, deleted, unknown = status
60
61
61 empty = short(nullid)
62 empty = short(nullid)
62
63
63 for f in modified:
64 for f in modified:
64 # TODO get file permissions
65 # TODO get file permissions
65 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
66 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
66 (short(mmap[f]), short(mmap2[f]), f, f))
67 (short(mmap[f]), short(mmap2[f]), f, f))
67 for f in added:
68 for f in added:
68 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
69 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
69 (empty, short(mmap2[f]), f, f))
70 (empty, short(mmap2[f]), f, f))
70 for f in removed:
71 for f in removed:
71 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
72 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
72 (short(mmap[f]), empty, f, f))
73 (short(mmap[f]), empty, f, f))
73 ##
74 ##
74
75
75 while True:
76 while True:
76 if opts['stdin']:
77 if opts['stdin']:
77 try:
78 try:
78 line = raw_input().split(' ')
79 line = raw_input().split(' ')
79 node1 = line[0]
80 node1 = line[0]
80 if len(line) > 1:
81 if len(line) > 1:
81 node2 = line[1]
82 node2 = line[1]
82 else:
83 else:
83 node2 = None
84 node2 = None
84 except EOFError:
85 except EOFError:
85 break
86 break
86 node1 = repo.lookup(node1)
87 node1 = repo.lookup(node1)
87 if node2:
88 if node2:
88 node2 = repo.lookup(node2)
89 node2 = repo.lookup(node2)
89 else:
90 else:
90 node2 = node1
91 node2 = node1
91 node1 = repo.changelog.parents(node1)[0]
92 node1 = repo.changelog.parents(node1)[0]
92 if opts['patch']:
93 if opts['patch']:
93 if opts['pretty']:
94 if opts['pretty']:
94 catcommit(ui, repo, node2, "")
95 catcommit(ui, repo, node2, "")
95 patch.diff(repo, node1, node2,
96 patch.diff(repo, node1, node2,
96 files=files,
97 files=files,
97 opts=patch.diffopts(ui, {'git': True}))
98 opts=patch.diffopts(ui, {'git': True}))
98 else:
99 else:
99 __difftree(repo, node1, node2, files=files)
100 __difftree(repo, node1, node2, files=files)
100 if not opts['stdin']:
101 if not opts['stdin']:
101 break
102 break
102
103
103 def catcommit(ui, repo, n, prefix, ctx=None):
104 def catcommit(ui, repo, n, prefix, ctx=None):
104 nlprefix = '\n' + prefix;
105 nlprefix = '\n' + prefix;
105 if ctx is None:
106 if ctx is None:
106 ctx = repo.changectx(n)
107 ctx = repo.changectx(n)
107 (p1, p2) = ctx.parents()
108 (p1, p2) = ctx.parents()
108 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
109 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
109 if p1: ui.write("parent %s\n" % short(p1.node()))
110 if p1: ui.write("parent %s\n" % short(p1.node()))
110 if p2: ui.write("parent %s\n" % short(p2.node()))
111 if p2: ui.write("parent %s\n" % short(p2.node()))
111 date = ctx.date()
112 date = ctx.date()
112 description = ctx.description().replace("\0", "")
113 description = ctx.description().replace("\0", "")
113 lines = description.splitlines()
114 lines = description.splitlines()
114 if lines and lines[-1].startswith('committer:'):
115 if lines and lines[-1].startswith('committer:'):
115 committer = lines[-1].split(': ')[1].rstrip()
116 committer = lines[-1].split(': ')[1].rstrip()
116 else:
117 else:
117 committer = ctx.user()
118 committer = ctx.user()
118
119
119 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
120 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
120 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
121 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
121 ui.write("revision %d\n" % ctx.rev())
122 ui.write("revision %d\n" % ctx.rev())
122 ui.write("branch %s\n\n" % ctx.branch())
123 ui.write("branch %s\n\n" % ctx.branch())
123
124
124 if prefix != "":
125 if prefix != "":
125 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
126 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
126 else:
127 else:
127 ui.write(description + "\n")
128 ui.write(description + "\n")
128 if prefix:
129 if prefix:
129 ui.write('\0')
130 ui.write('\0')
130
131
131 def base(ui, repo, node1, node2):
132 def base(ui, repo, node1, node2):
132 """Output common ancestor information"""
133 """Output common ancestor information"""
133 node1 = repo.lookup(node1)
134 node1 = repo.lookup(node1)
134 node2 = repo.lookup(node2)
135 node2 = repo.lookup(node2)
135 n = repo.changelog.ancestor(node1, node2)
136 n = repo.changelog.ancestor(node1, node2)
136 ui.write(short(n) + "\n")
137 ui.write(short(n) + "\n")
137
138
138 def catfile(ui, repo, type=None, r=None, **opts):
139 def catfile(ui, repo, type=None, r=None, **opts):
139 """cat a specific revision"""
140 """cat a specific revision"""
140 # in stdin mode, every line except the commit is prefixed with two
141 # in stdin mode, every line except the commit is prefixed with two
141 # spaces. This way the our caller can find the commit without magic
142 # spaces. This way the our caller can find the commit without magic
142 # strings
143 # strings
143 #
144 #
144 prefix = ""
145 prefix = ""
145 if opts['stdin']:
146 if opts['stdin']:
146 try:
147 try:
147 (type, r) = raw_input().split(' ');
148 (type, r) = raw_input().split(' ');
148 prefix = " "
149 prefix = " "
149 except EOFError:
150 except EOFError:
150 return
151 return
151
152
152 else:
153 else:
153 if not type or not r:
154 if not type or not r:
154 ui.warn("cat-file: type or revision not supplied\n")
155 ui.warn("cat-file: type or revision not supplied\n")
155 commands.help_(ui, 'cat-file')
156 commands.help_(ui, 'cat-file')
156
157
157 while r:
158 while r:
158 if type != "commit":
159 if type != "commit":
159 ui.warn("aborting hg cat-file only understands commits\n")
160 ui.warn("aborting hg cat-file only understands commits\n")
160 return 1;
161 return 1;
161 n = repo.lookup(r)
162 n = repo.lookup(r)
162 catcommit(ui, repo, n, prefix)
163 catcommit(ui, repo, n, prefix)
163 if opts['stdin']:
164 if opts['stdin']:
164 try:
165 try:
165 (type, r) = raw_input().split(' ');
166 (type, r) = raw_input().split(' ');
166 except EOFError:
167 except EOFError:
167 break
168 break
168 else:
169 else:
169 break
170 break
170
171
171 # git rev-tree is a confusing thing. You can supply a number of
172 # git rev-tree is a confusing thing. You can supply a number of
172 # commit sha1s on the command line, and it walks the commit history
173 # commit sha1s on the command line, and it walks the commit history
173 # telling you which commits are reachable from the supplied ones via
174 # telling you which commits are reachable from the supplied ones via
174 # a bitmask based on arg position.
175 # a bitmask based on arg position.
175 # you can specify a commit to stop at by starting the sha1 with ^
176 # you can specify a commit to stop at by starting the sha1 with ^
176 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
177 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
177 def chlogwalk():
178 def chlogwalk():
178 count = repo.changelog.count()
179 count = repo.changelog.count()
179 i = count
180 i = count
180 l = [0] * 100
181 l = [0] * 100
181 chunk = 100
182 chunk = 100
182 while True:
183 while True:
183 if chunk > i:
184 if chunk > i:
184 chunk = i
185 chunk = i
185 i = 0
186 i = 0
186 else:
187 else:
187 i -= chunk
188 i -= chunk
188
189
189 for x in xrange(0, chunk):
190 for x in xrange(0, chunk):
190 if i + x >= count:
191 if i + x >= count:
191 l[chunk - x:] = [0] * (chunk - x)
192 l[chunk - x:] = [0] * (chunk - x)
192 break
193 break
193 if full != None:
194 if full != None:
194 l[x] = repo.changectx(i + x)
195 l[x] = repo.changectx(i + x)
195 l[x].changeset() # force reading
196 l[x].changeset() # force reading
196 else:
197 else:
197 l[x] = 1
198 l[x] = 1
198 for x in xrange(chunk-1, -1, -1):
199 for x in xrange(chunk-1, -1, -1):
199 if l[x] != 0:
200 if l[x] != 0:
200 yield (i + x, full != None and l[x] or None)
201 yield (i + x, full != None and l[x] or None)
201 if i == 0:
202 if i == 0:
202 break
203 break
203
204
204 # calculate and return the reachability bitmask for sha
205 # calculate and return the reachability bitmask for sha
205 def is_reachable(ar, reachable, sha):
206 def is_reachable(ar, reachable, sha):
206 if len(ar) == 0:
207 if len(ar) == 0:
207 return 1
208 return 1
208 mask = 0
209 mask = 0
209 for i in xrange(len(ar)):
210 for i in xrange(len(ar)):
210 if sha in reachable[i]:
211 if sha in reachable[i]:
211 mask |= 1 << i
212 mask |= 1 << i
212
213
213 return mask
214 return mask
214
215
215 reachable = []
216 reachable = []
216 stop_sha1 = []
217 stop_sha1 = []
217 want_sha1 = []
218 want_sha1 = []
218 count = 0
219 count = 0
219
220
220 # figure out which commits they are asking for and which ones they
221 # figure out which commits they are asking for and which ones they
221 # want us to stop on
222 # want us to stop on
222 for i in xrange(len(args)):
223 for i in xrange(len(args)):
223 if args[i].startswith('^'):
224 if args[i].startswith('^'):
224 s = repo.lookup(args[i][1:])
225 s = repo.lookup(args[i][1:])
225 stop_sha1.append(s)
226 stop_sha1.append(s)
226 want_sha1.append(s)
227 want_sha1.append(s)
227 elif args[i] != 'HEAD':
228 elif args[i] != 'HEAD':
228 want_sha1.append(repo.lookup(args[i]))
229 want_sha1.append(repo.lookup(args[i]))
229
230
230 # calculate the graph for the supplied commits
231 # calculate the graph for the supplied commits
231 for i in xrange(len(want_sha1)):
232 for i in xrange(len(want_sha1)):
232 reachable.append({});
233 reachable.append({});
233 n = want_sha1[i];
234 n = want_sha1[i];
234 visit = [n];
235 visit = [n];
235 reachable[i][n] = 1
236 reachable[i][n] = 1
236 while visit:
237 while visit:
237 n = visit.pop(0)
238 n = visit.pop(0)
238 if n in stop_sha1:
239 if n in stop_sha1:
239 continue
240 continue
240 for p in repo.changelog.parents(n):
241 for p in repo.changelog.parents(n):
241 if p not in reachable[i]:
242 if p not in reachable[i]:
242 reachable[i][p] = 1
243 reachable[i][p] = 1
243 visit.append(p)
244 visit.append(p)
244 if p in stop_sha1:
245 if p in stop_sha1:
245 continue
246 continue
246
247
247 # walk the repository looking for commits that are in our
248 # walk the repository looking for commits that are in our
248 # reachability graph
249 # reachability graph
249 for i, ctx in chlogwalk():
250 for i, ctx in chlogwalk():
250 n = repo.changelog.node(i)
251 n = repo.changelog.node(i)
251 mask = is_reachable(want_sha1, reachable, n)
252 mask = is_reachable(want_sha1, reachable, n)
252 if mask:
253 if mask:
253 parentstr = ""
254 parentstr = ""
254 if parents:
255 if parents:
255 pp = repo.changelog.parents(n)
256 pp = repo.changelog.parents(n)
256 if pp[0] != nullid:
257 if pp[0] != nullid:
257 parentstr += " " + short(pp[0])
258 parentstr += " " + short(pp[0])
258 if pp[1] != nullid:
259 if pp[1] != nullid:
259 parentstr += " " + short(pp[1])
260 parentstr += " " + short(pp[1])
260 if not full:
261 if not full:
261 ui.write("%s%s\n" % (short(n), parentstr))
262 ui.write("%s%s\n" % (short(n), parentstr))
262 elif full == "commit":
263 elif full == "commit":
263 ui.write("%s%s\n" % (short(n), parentstr))
264 ui.write("%s%s\n" % (short(n), parentstr))
264 catcommit(ui, repo, n, ' ', ctx)
265 catcommit(ui, repo, n, ' ', ctx)
265 else:
266 else:
266 (p1, p2) = repo.changelog.parents(n)
267 (p1, p2) = repo.changelog.parents(n)
267 (h, h1, h2) = map(short, (n, p1, p2))
268 (h, h1, h2) = map(short, (n, p1, p2))
268 (i1, i2) = map(repo.changelog.rev, (p1, p2))
269 (i1, i2) = map(repo.changelog.rev, (p1, p2))
269
270
270 date = ctx.date()[0]
271 date = ctx.date()[0]
271 ui.write("%s %s:%s" % (date, h, mask))
272 ui.write("%s %s:%s" % (date, h, mask))
272 mask = is_reachable(want_sha1, reachable, p1)
273 mask = is_reachable(want_sha1, reachable, p1)
273 if i1 != nullrev and mask > 0:
274 if i1 != nullrev and mask > 0:
274 ui.write("%s:%s " % (h1, mask)),
275 ui.write("%s:%s " % (h1, mask)),
275 mask = is_reachable(want_sha1, reachable, p2)
276 mask = is_reachable(want_sha1, reachable, p2)
276 if i2 != nullrev and mask > 0:
277 if i2 != nullrev and mask > 0:
277 ui.write("%s:%s " % (h2, mask))
278 ui.write("%s:%s " % (h2, mask))
278 ui.write("\n")
279 ui.write("\n")
279 if maxnr and count >= maxnr:
280 if maxnr and count >= maxnr:
280 break
281 break
281 count += 1
282 count += 1
282
283
283 def revparse(ui, repo, *revs, **opts):
284 def revparse(ui, repo, *revs, **opts):
284 """Parse given revisions"""
285 """Parse given revisions"""
285 def revstr(rev):
286 def revstr(rev):
286 if rev == 'HEAD':
287 if rev == 'HEAD':
287 rev = 'tip'
288 rev = 'tip'
288 return revlog.hex(repo.lookup(rev))
289 return revlog.hex(repo.lookup(rev))
289
290
290 for r in revs:
291 for r in revs:
291 revrange = r.split(':', 1)
292 revrange = r.split(':', 1)
292 ui.write('%s\n' % revstr(revrange[0]))
293 ui.write('%s\n' % revstr(revrange[0]))
293 if len(revrange) == 2:
294 if len(revrange) == 2:
294 ui.write('^%s\n' % revstr(revrange[1]))
295 ui.write('^%s\n' % revstr(revrange[1]))
295
296
296 # git rev-list tries to order things by date, and has the ability to stop
297 # git rev-list tries to order things by date, and has the ability to stop
297 # at a given commit without walking the whole repo. TODO add the stop
298 # at a given commit without walking the whole repo. TODO add the stop
298 # parameter
299 # parameter
299 def revlist(ui, repo, *revs, **opts):
300 def revlist(ui, repo, *revs, **opts):
300 """print revisions"""
301 """print revisions"""
301 if opts['header']:
302 if opts['header']:
302 full = "commit"
303 full = "commit"
303 else:
304 else:
304 full = None
305 full = None
305 copy = [x for x in revs]
306 copy = [x for x in revs]
306 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
307 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
307
308
308 def config(ui, repo, **opts):
309 def config(ui, repo, **opts):
309 """print extension options"""
310 """print extension options"""
310 def writeopt(name, value):
311 def writeopt(name, value):
311 ui.write('k=%s\nv=%s\n' % (name, value))
312 ui.write('k=%s\nv=%s\n' % (name, value))
312
313
313 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
314 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
314
315
315
316
316 def view(ui, repo, *etc, **opts):
317 def view(ui, repo, *etc, **opts):
317 "start interactive history viewer"
318 "start interactive history viewer"
318 os.chdir(repo.root)
319 os.chdir(repo.root)
319 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
320 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
320 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
321 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
321 ui.debug("running %s\n" % cmd)
322 ui.debug("running %s\n" % cmd)
322 util.system(cmd)
323 util.system(cmd)
323
324
324 cmdtable = {
325 cmdtable = {
325 "^view":
326 "^view":
326 (view,
327 (view,
327 [('l', 'limit', '', 'limit number of changes displayed')],
328 [('l', 'limit', '', 'limit number of changes displayed')],
328 'hg view [-l LIMIT] [REVRANGE]'),
329 'hg view [-l LIMIT] [REVRANGE]'),
329 "debug-diff-tree":
330 "debug-diff-tree":
330 (difftree,
331 (difftree,
331 [('p', 'patch', None, 'generate patch'),
332 [('p', 'patch', None, 'generate patch'),
332 ('r', 'recursive', None, 'recursive'),
333 ('r', 'recursive', None, 'recursive'),
333 ('P', 'pretty', None, 'pretty'),
334 ('P', 'pretty', None, 'pretty'),
334 ('s', 'stdin', None, 'stdin'),
335 ('s', 'stdin', None, 'stdin'),
335 ('C', 'copy', None, 'detect copies'),
336 ('C', 'copy', None, 'detect copies'),
336 ('S', 'search', "", 'search')],
337 ('S', 'search', "", 'search')],
337 'hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...'),
338 'hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...'),
338 "debug-cat-file":
339 "debug-cat-file":
339 (catfile,
340 (catfile,
340 [('s', 'stdin', None, 'stdin')],
341 [('s', 'stdin', None, 'stdin')],
341 'hg debug-cat-file [OPTION]... TYPE FILE'),
342 'hg debug-cat-file [OPTION]... TYPE FILE'),
342 "debug-config":
343 "debug-config":
343 (config, [], 'hg debug-config'),
344 (config, [], 'hg debug-config'),
344 "debug-merge-base":
345 "debug-merge-base":
345 (base, [], 'hg debug-merge-base node node'),
346 (base, [], 'hg debug-merge-base node node'),
346 "debug-rev-parse":
347 "debug-rev-parse":
347 (revparse,
348 (revparse,
348 [('', 'default', '', 'ignored')],
349 [('', 'default', '', 'ignored')],
349 'hg debug-rev-parse REV'),
350 'hg debug-rev-parse REV'),
350 "debug-rev-list":
351 "debug-rev-list":
351 (revlist,
352 (revlist,
352 [('H', 'header', None, 'header'),
353 [('H', 'header', None, 'header'),
353 ('t', 'topo-order', None, 'topo-order'),
354 ('t', 'topo-order', None, 'topo-order'),
354 ('p', 'parents', None, 'parents'),
355 ('p', 'parents', None, 'parents'),
355 ('n', 'max-count', 0, 'max-count')],
356 ('n', 'max-count', 0, 'max-count')],
356 'hg debug-rev-list [options] revs'),
357 'hg debug-rev-list [options] revs'),
357 }
358 }
@@ -1,2366 +1,2364 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 '''patch management and development
8 '''patch management and development
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use "hg help command" for more details):
17 Common tasks (use "hg help command" for more details):
18
18
19 prepare repository to work with patches qinit
19 prepare repository to work with patches qinit
20 create new patch qnew
20 create new patch qnew
21 import existing patch qimport
21 import existing patch qimport
22
22
23 print patch series qseries
23 print patch series qseries
24 print applied patches qapplied
24 print applied patches qapplied
25 print name of top applied patch qtop
25 print name of top applied patch qtop
26
26
27 add known patch to applied stack qpush
27 add known patch to applied stack qpush
28 remove patch from applied stack qpop
28 remove patch from applied stack qpop
29 refresh contents of top applied patch qrefresh
29 refresh contents of top applied patch qrefresh
30 '''
30 '''
31
31
32 from mercurial.i18n import _
32 from mercurial.i18n import _
33 from mercurial.node import bin, hex, short
33 from mercurial.node import bin, hex, short
34 from mercurial.repo import RepoError
34 from mercurial.repo import RepoError
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
36 from mercurial import repair
36 from mercurial import repair
37 import os, sys, re, errno
37 import os, sys, re, errno
38
38
39 commands.norepo += " qclone"
39 commands.norepo += " qclone"
40
40
41 # Patch names looks like unix-file names.
41 # Patch names looks like unix-file names.
42 # They must be joinable with queue directory and result in the patch path.
42 # They must be joinable with queue directory and result in the patch path.
43 normname = util.normpath
43 normname = util.normpath
44
44
45 class statusentry:
45 class statusentry:
46 def __init__(self, rev, name=None):
46 def __init__(self, rev, name=None):
47 if not name:
47 if not name:
48 fields = rev.split(':', 1)
48 fields = rev.split(':', 1)
49 if len(fields) == 2:
49 if len(fields) == 2:
50 self.rev, self.name = fields
50 self.rev, self.name = fields
51 else:
51 else:
52 self.rev, self.name = None, None
52 self.rev, self.name = None, None
53 else:
53 else:
54 self.rev, self.name = rev, name
54 self.rev, self.name = rev, name
55
55
56 def __str__(self):
56 def __str__(self):
57 return self.rev + ':' + self.name
57 return self.rev + ':' + self.name
58
58
59 class queue:
59 class queue:
60 def __init__(self, ui, path, patchdir=None):
60 def __init__(self, ui, path, patchdir=None):
61 self.basepath = path
61 self.basepath = path
62 self.path = patchdir or os.path.join(path, "patches")
62 self.path = patchdir or os.path.join(path, "patches")
63 self.opener = util.opener(self.path)
63 self.opener = util.opener(self.path)
64 self.ui = ui
64 self.ui = ui
65 self.applied = []
65 self.applied = []
66 self.full_series = []
66 self.full_series = []
67 self.applied_dirty = 0
67 self.applied_dirty = 0
68 self.series_dirty = 0
68 self.series_dirty = 0
69 self.series_path = "series"
69 self.series_path = "series"
70 self.status_path = "status"
70 self.status_path = "status"
71 self.guards_path = "guards"
71 self.guards_path = "guards"
72 self.active_guards = None
72 self.active_guards = None
73 self.guards_dirty = False
73 self.guards_dirty = False
74 self._diffopts = None
74 self._diffopts = None
75
75
76 if os.path.exists(self.join(self.series_path)):
76 if os.path.exists(self.join(self.series_path)):
77 self.full_series = self.opener(self.series_path).read().splitlines()
77 self.full_series = self.opener(self.series_path).read().splitlines()
78 self.parse_series()
78 self.parse_series()
79
79
80 if os.path.exists(self.join(self.status_path)):
80 if os.path.exists(self.join(self.status_path)):
81 lines = self.opener(self.status_path).read().splitlines()
81 lines = self.opener(self.status_path).read().splitlines()
82 self.applied = [statusentry(l) for l in lines]
82 self.applied = [statusentry(l) for l in lines]
83
83
84 def diffopts(self):
84 def diffopts(self):
85 if self._diffopts is None:
85 if self._diffopts is None:
86 self._diffopts = patch.diffopts(self.ui)
86 self._diffopts = patch.diffopts(self.ui)
87 return self._diffopts
87 return self._diffopts
88
88
89 def join(self, *p):
89 def join(self, *p):
90 return os.path.join(self.path, *p)
90 return os.path.join(self.path, *p)
91
91
92 def find_series(self, patch):
92 def find_series(self, patch):
93 pre = re.compile("(\s*)([^#]+)")
93 pre = re.compile("(\s*)([^#]+)")
94 index = 0
94 index = 0
95 for l in self.full_series:
95 for l in self.full_series:
96 m = pre.match(l)
96 m = pre.match(l)
97 if m:
97 if m:
98 s = m.group(2)
98 s = m.group(2)
99 s = s.rstrip()
99 s = s.rstrip()
100 if s == patch:
100 if s == patch:
101 return index
101 return index
102 index += 1
102 index += 1
103 return None
103 return None
104
104
105 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
105 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
106
106
107 def parse_series(self):
107 def parse_series(self):
108 self.series = []
108 self.series = []
109 self.series_guards = []
109 self.series_guards = []
110 for l in self.full_series:
110 for l in self.full_series:
111 h = l.find('#')
111 h = l.find('#')
112 if h == -1:
112 if h == -1:
113 patch = l
113 patch = l
114 comment = ''
114 comment = ''
115 elif h == 0:
115 elif h == 0:
116 continue
116 continue
117 else:
117 else:
118 patch = l[:h]
118 patch = l[:h]
119 comment = l[h:]
119 comment = l[h:]
120 patch = patch.strip()
120 patch = patch.strip()
121 if patch:
121 if patch:
122 if patch in self.series:
122 if patch in self.series:
123 raise util.Abort(_('%s appears more than once in %s') %
123 raise util.Abort(_('%s appears more than once in %s') %
124 (patch, self.join(self.series_path)))
124 (patch, self.join(self.series_path)))
125 self.series.append(patch)
125 self.series.append(patch)
126 self.series_guards.append(self.guard_re.findall(comment))
126 self.series_guards.append(self.guard_re.findall(comment))
127
127
128 def check_guard(self, guard):
128 def check_guard(self, guard):
129 bad_chars = '# \t\r\n\f'
129 bad_chars = '# \t\r\n\f'
130 first = guard[0]
130 first = guard[0]
131 for c in '-+':
131 for c in '-+':
132 if first == c:
132 if first == c:
133 return (_('guard %r starts with invalid character: %r') %
133 return (_('guard %r starts with invalid character: %r') %
134 (guard, c))
134 (guard, c))
135 for c in bad_chars:
135 for c in bad_chars:
136 if c in guard:
136 if c in guard:
137 return _('invalid character in guard %r: %r') % (guard, c)
137 return _('invalid character in guard %r: %r') % (guard, c)
138
138
139 def set_active(self, guards):
139 def set_active(self, guards):
140 for guard in guards:
140 for guard in guards:
141 bad = self.check_guard(guard)
141 bad = self.check_guard(guard)
142 if bad:
142 if bad:
143 raise util.Abort(bad)
143 raise util.Abort(bad)
144 guards = dict.fromkeys(guards).keys()
144 guards = dict.fromkeys(guards).keys()
145 guards.sort()
145 guards.sort()
146 self.ui.debug('active guards: %s\n' % ' '.join(guards))
146 self.ui.debug('active guards: %s\n' % ' '.join(guards))
147 self.active_guards = guards
147 self.active_guards = guards
148 self.guards_dirty = True
148 self.guards_dirty = True
149
149
150 def active(self):
150 def active(self):
151 if self.active_guards is None:
151 if self.active_guards is None:
152 self.active_guards = []
152 self.active_guards = []
153 try:
153 try:
154 guards = self.opener(self.guards_path).read().split()
154 guards = self.opener(self.guards_path).read().split()
155 except IOError, err:
155 except IOError, err:
156 if err.errno != errno.ENOENT: raise
156 if err.errno != errno.ENOENT: raise
157 guards = []
157 guards = []
158 for i, guard in enumerate(guards):
158 for i, guard in enumerate(guards):
159 bad = self.check_guard(guard)
159 bad = self.check_guard(guard)
160 if bad:
160 if bad:
161 self.ui.warn('%s:%d: %s\n' %
161 self.ui.warn('%s:%d: %s\n' %
162 (self.join(self.guards_path), i + 1, bad))
162 (self.join(self.guards_path), i + 1, bad))
163 else:
163 else:
164 self.active_guards.append(guard)
164 self.active_guards.append(guard)
165 return self.active_guards
165 return self.active_guards
166
166
167 def set_guards(self, idx, guards):
167 def set_guards(self, idx, guards):
168 for g in guards:
168 for g in guards:
169 if len(g) < 2:
169 if len(g) < 2:
170 raise util.Abort(_('guard %r too short') % g)
170 raise util.Abort(_('guard %r too short') % g)
171 if g[0] not in '-+':
171 if g[0] not in '-+':
172 raise util.Abort(_('guard %r starts with invalid char') % g)
172 raise util.Abort(_('guard %r starts with invalid char') % g)
173 bad = self.check_guard(g[1:])
173 bad = self.check_guard(g[1:])
174 if bad:
174 if bad:
175 raise util.Abort(bad)
175 raise util.Abort(bad)
176 drop = self.guard_re.sub('', self.full_series[idx])
176 drop = self.guard_re.sub('', self.full_series[idx])
177 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
177 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
178 self.parse_series()
178 self.parse_series()
179 self.series_dirty = True
179 self.series_dirty = True
180
180
181 def pushable(self, idx):
181 def pushable(self, idx):
182 if isinstance(idx, str):
182 if isinstance(idx, str):
183 idx = self.series.index(idx)
183 idx = self.series.index(idx)
184 patchguards = self.series_guards[idx]
184 patchguards = self.series_guards[idx]
185 if not patchguards:
185 if not patchguards:
186 return True, None
186 return True, None
187 default = False
187 default = False
188 guards = self.active()
188 guards = self.active()
189 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
189 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
190 if exactneg:
190 if exactneg:
191 return False, exactneg[0]
191 return False, exactneg[0]
192 pos = [g for g in patchguards if g[0] == '+']
192 pos = [g for g in patchguards if g[0] == '+']
193 exactpos = [g for g in pos if g[1:] in guards]
193 exactpos = [g for g in pos if g[1:] in guards]
194 if pos:
194 if pos:
195 if exactpos:
195 if exactpos:
196 return True, exactpos[0]
196 return True, exactpos[0]
197 return False, pos
197 return False, pos
198 return True, ''
198 return True, ''
199
199
200 def explain_pushable(self, idx, all_patches=False):
200 def explain_pushable(self, idx, all_patches=False):
201 write = all_patches and self.ui.write or self.ui.warn
201 write = all_patches and self.ui.write or self.ui.warn
202 if all_patches or self.ui.verbose:
202 if all_patches or self.ui.verbose:
203 if isinstance(idx, str):
203 if isinstance(idx, str):
204 idx = self.series.index(idx)
204 idx = self.series.index(idx)
205 pushable, why = self.pushable(idx)
205 pushable, why = self.pushable(idx)
206 if all_patches and pushable:
206 if all_patches and pushable:
207 if why is None:
207 if why is None:
208 write(_('allowing %s - no guards in effect\n') %
208 write(_('allowing %s - no guards in effect\n') %
209 self.series[idx])
209 self.series[idx])
210 else:
210 else:
211 if not why:
211 if not why:
212 write(_('allowing %s - no matching negative guards\n') %
212 write(_('allowing %s - no matching negative guards\n') %
213 self.series[idx])
213 self.series[idx])
214 else:
214 else:
215 write(_('allowing %s - guarded by %r\n') %
215 write(_('allowing %s - guarded by %r\n') %
216 (self.series[idx], why))
216 (self.series[idx], why))
217 if not pushable:
217 if not pushable:
218 if why:
218 if why:
219 write(_('skipping %s - guarded by %r\n') %
219 write(_('skipping %s - guarded by %r\n') %
220 (self.series[idx], why))
220 (self.series[idx], why))
221 else:
221 else:
222 write(_('skipping %s - no matching guards\n') %
222 write(_('skipping %s - no matching guards\n') %
223 self.series[idx])
223 self.series[idx])
224
224
225 def save_dirty(self):
225 def save_dirty(self):
226 def write_list(items, path):
226 def write_list(items, path):
227 fp = self.opener(path, 'w')
227 fp = self.opener(path, 'w')
228 for i in items:
228 for i in items:
229 fp.write("%s\n" % i)
229 fp.write("%s\n" % i)
230 fp.close()
230 fp.close()
231 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
231 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
232 if self.series_dirty: write_list(self.full_series, self.series_path)
232 if self.series_dirty: write_list(self.full_series, self.series_path)
233 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
233 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
234
234
235 def readheaders(self, patch):
235 def readheaders(self, patch):
236 def eatdiff(lines):
236 def eatdiff(lines):
237 while lines:
237 while lines:
238 l = lines[-1]
238 l = lines[-1]
239 if (l.startswith("diff -") or
239 if (l.startswith("diff -") or
240 l.startswith("Index:") or
240 l.startswith("Index:") or
241 l.startswith("===========")):
241 l.startswith("===========")):
242 del lines[-1]
242 del lines[-1]
243 else:
243 else:
244 break
244 break
245 def eatempty(lines):
245 def eatempty(lines):
246 while lines:
246 while lines:
247 l = lines[-1]
247 l = lines[-1]
248 if re.match('\s*$', l):
248 if re.match('\s*$', l):
249 del lines[-1]
249 del lines[-1]
250 else:
250 else:
251 break
251 break
252
252
253 pf = self.join(patch)
253 pf = self.join(patch)
254 message = []
254 message = []
255 comments = []
255 comments = []
256 user = None
256 user = None
257 date = None
257 date = None
258 format = None
258 format = None
259 subject = None
259 subject = None
260 diffstart = 0
260 diffstart = 0
261
261
262 for line in file(pf):
262 for line in file(pf):
263 line = line.rstrip()
263 line = line.rstrip()
264 if line.startswith('diff --git'):
264 if line.startswith('diff --git'):
265 diffstart = 2
265 diffstart = 2
266 break
266 break
267 if diffstart:
267 if diffstart:
268 if line.startswith('+++ '):
268 if line.startswith('+++ '):
269 diffstart = 2
269 diffstart = 2
270 break
270 break
271 if line.startswith("--- "):
271 if line.startswith("--- "):
272 diffstart = 1
272 diffstart = 1
273 continue
273 continue
274 elif format == "hgpatch":
274 elif format == "hgpatch":
275 # parse values when importing the result of an hg export
275 # parse values when importing the result of an hg export
276 if line.startswith("# User "):
276 if line.startswith("# User "):
277 user = line[7:]
277 user = line[7:]
278 elif line.startswith("# Date "):
278 elif line.startswith("# Date "):
279 date = line[7:]
279 date = line[7:]
280 elif not line.startswith("# ") and line:
280 elif not line.startswith("# ") and line:
281 message.append(line)
281 message.append(line)
282 format = None
282 format = None
283 elif line == '# HG changeset patch':
283 elif line == '# HG changeset patch':
284 format = "hgpatch"
284 format = "hgpatch"
285 elif (format != "tagdone" and (line.startswith("Subject: ") or
285 elif (format != "tagdone" and (line.startswith("Subject: ") or
286 line.startswith("subject: "))):
286 line.startswith("subject: "))):
287 subject = line[9:]
287 subject = line[9:]
288 format = "tag"
288 format = "tag"
289 elif (format != "tagdone" and (line.startswith("From: ") or
289 elif (format != "tagdone" and (line.startswith("From: ") or
290 line.startswith("from: "))):
290 line.startswith("from: "))):
291 user = line[6:]
291 user = line[6:]
292 format = "tag"
292 format = "tag"
293 elif format == "tag" and line == "":
293 elif format == "tag" and line == "":
294 # when looking for tags (subject: from: etc) they
294 # when looking for tags (subject: from: etc) they
295 # end once you find a blank line in the source
295 # end once you find a blank line in the source
296 format = "tagdone"
296 format = "tagdone"
297 elif message or line:
297 elif message or line:
298 message.append(line)
298 message.append(line)
299 comments.append(line)
299 comments.append(line)
300
300
301 eatdiff(message)
301 eatdiff(message)
302 eatdiff(comments)
302 eatdiff(comments)
303 eatempty(message)
303 eatempty(message)
304 eatempty(comments)
304 eatempty(comments)
305
305
306 # make sure message isn't empty
306 # make sure message isn't empty
307 if format and format.startswith("tag") and subject:
307 if format and format.startswith("tag") and subject:
308 message.insert(0, "")
308 message.insert(0, "")
309 message.insert(0, subject)
309 message.insert(0, subject)
310 return (message, comments, user, date, diffstart > 1)
310 return (message, comments, user, date, diffstart > 1)
311
311
312 def removeundo(self, repo):
312 def removeundo(self, repo):
313 undo = repo.sjoin('undo')
313 undo = repo.sjoin('undo')
314 if not os.path.exists(undo):
314 if not os.path.exists(undo):
315 return
315 return
316 try:
316 try:
317 os.unlink(undo)
317 os.unlink(undo)
318 except OSError, inst:
318 except OSError, inst:
319 self.ui.warn('error removing undo: %s\n' % str(inst))
319 self.ui.warn('error removing undo: %s\n' % str(inst))
320
320
321 def printdiff(self, repo, node1, node2=None, files=None,
321 def printdiff(self, repo, node1, node2=None, files=None,
322 fp=None, changes=None, opts={}):
322 fp=None, changes=None, opts={}):
323 m = cmdutil.match(repo, files, opts)
323 m = cmdutil.match(repo, files, opts)
324 patch.diff(repo, node1, node2, m.files(), match=m,
324 patch.diff(repo, node1, node2, m.files(), match=m,
325 fp=fp, changes=changes, opts=self.diffopts())
325 fp=fp, changes=changes, opts=self.diffopts())
326
326
327 def mergeone(self, repo, mergeq, head, patch, rev):
327 def mergeone(self, repo, mergeq, head, patch, rev):
328 # first try just applying the patch
328 # first try just applying the patch
329 (err, n) = self.apply(repo, [ patch ], update_status=False,
329 (err, n) = self.apply(repo, [ patch ], update_status=False,
330 strict=True, merge=rev)
330 strict=True, merge=rev)
331
331
332 if err == 0:
332 if err == 0:
333 return (err, n)
333 return (err, n)
334
334
335 if n is None:
335 if n is None:
336 raise util.Abort(_("apply failed for patch %s") % patch)
336 raise util.Abort(_("apply failed for patch %s") % patch)
337
337
338 self.ui.warn("patch didn't work out, merging %s\n" % patch)
338 self.ui.warn("patch didn't work out, merging %s\n" % patch)
339
339
340 # apply failed, strip away that rev and merge.
340 # apply failed, strip away that rev and merge.
341 hg.clean(repo, head)
341 hg.clean(repo, head)
342 self.strip(repo, n, update=False, backup='strip')
342 self.strip(repo, n, update=False, backup='strip')
343
343
344 ctx = repo.changectx(rev)
344 ctx = repo.changectx(rev)
345 ret = hg.merge(repo, rev)
345 ret = hg.merge(repo, rev)
346 if ret:
346 if ret:
347 raise util.Abort(_("update returned %d") % ret)
347 raise util.Abort(_("update returned %d") % ret)
348 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
348 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
349 if n == None:
349 if n == None:
350 raise util.Abort(_("repo commit failed"))
350 raise util.Abort(_("repo commit failed"))
351 try:
351 try:
352 message, comments, user, date, patchfound = mergeq.readheaders(patch)
352 message, comments, user, date, patchfound = mergeq.readheaders(patch)
353 except:
353 except:
354 raise util.Abort(_("unable to read %s") % patch)
354 raise util.Abort(_("unable to read %s") % patch)
355
355
356 patchf = self.opener(patch, "w")
356 patchf = self.opener(patch, "w")
357 if comments:
357 if comments:
358 comments = "\n".join(comments) + '\n\n'
358 comments = "\n".join(comments) + '\n\n'
359 patchf.write(comments)
359 patchf.write(comments)
360 self.printdiff(repo, head, n, fp=patchf)
360 self.printdiff(repo, head, n, fp=patchf)
361 patchf.close()
361 patchf.close()
362 self.removeundo(repo)
362 self.removeundo(repo)
363 return (0, n)
363 return (0, n)
364
364
365 def qparents(self, repo, rev=None):
365 def qparents(self, repo, rev=None):
366 if rev is None:
366 if rev is None:
367 (p1, p2) = repo.dirstate.parents()
367 (p1, p2) = repo.dirstate.parents()
368 if p2 == revlog.nullid:
368 if p2 == revlog.nullid:
369 return p1
369 return p1
370 if len(self.applied) == 0:
370 if len(self.applied) == 0:
371 return None
371 return None
372 return revlog.bin(self.applied[-1].rev)
372 return revlog.bin(self.applied[-1].rev)
373 pp = repo.changelog.parents(rev)
373 pp = repo.changelog.parents(rev)
374 if pp[1] != revlog.nullid:
374 if pp[1] != revlog.nullid:
375 arevs = [ x.rev for x in self.applied ]
375 arevs = [ x.rev for x in self.applied ]
376 p0 = revlog.hex(pp[0])
376 p0 = revlog.hex(pp[0])
377 p1 = revlog.hex(pp[1])
377 p1 = revlog.hex(pp[1])
378 if p0 in arevs:
378 if p0 in arevs:
379 return pp[0]
379 return pp[0]
380 if p1 in arevs:
380 if p1 in arevs:
381 return pp[1]
381 return pp[1]
382 return pp[0]
382 return pp[0]
383
383
384 def mergepatch(self, repo, mergeq, series):
384 def mergepatch(self, repo, mergeq, series):
385 if len(self.applied) == 0:
385 if len(self.applied) == 0:
386 # each of the patches merged in will have two parents. This
386 # each of the patches merged in will have two parents. This
387 # can confuse the qrefresh, qdiff, and strip code because it
387 # can confuse the qrefresh, qdiff, and strip code because it
388 # needs to know which parent is actually in the patch queue.
388 # needs to know which parent is actually in the patch queue.
389 # so, we insert a merge marker with only one parent. This way
389 # so, we insert a merge marker with only one parent. This way
390 # the first patch in the queue is never a merge patch
390 # the first patch in the queue is never a merge patch
391 #
391 #
392 pname = ".hg.patches.merge.marker"
392 pname = ".hg.patches.merge.marker"
393 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
393 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
394 self.removeundo(repo)
394 self.removeundo(repo)
395 self.applied.append(statusentry(revlog.hex(n), pname))
395 self.applied.append(statusentry(revlog.hex(n), pname))
396 self.applied_dirty = 1
396 self.applied_dirty = 1
397
397
398 head = self.qparents(repo)
398 head = self.qparents(repo)
399
399
400 for patch in series:
400 for patch in series:
401 patch = mergeq.lookup(patch, strict=True)
401 patch = mergeq.lookup(patch, strict=True)
402 if not patch:
402 if not patch:
403 self.ui.warn("patch %s does not exist\n" % patch)
403 self.ui.warn("patch %s does not exist\n" % patch)
404 return (1, None)
404 return (1, None)
405 pushable, reason = self.pushable(patch)
405 pushable, reason = self.pushable(patch)
406 if not pushable:
406 if not pushable:
407 self.explain_pushable(patch, all_patches=True)
407 self.explain_pushable(patch, all_patches=True)
408 continue
408 continue
409 info = mergeq.isapplied(patch)
409 info = mergeq.isapplied(patch)
410 if not info:
410 if not info:
411 self.ui.warn("patch %s is not applied\n" % patch)
411 self.ui.warn("patch %s is not applied\n" % patch)
412 return (1, None)
412 return (1, None)
413 rev = revlog.bin(info[1])
413 rev = revlog.bin(info[1])
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
415 if head:
415 if head:
416 self.applied.append(statusentry(revlog.hex(head), patch))
416 self.applied.append(statusentry(revlog.hex(head), patch))
417 self.applied_dirty = 1
417 self.applied_dirty = 1
418 if err:
418 if err:
419 return (err, head)
419 return (err, head)
420 self.save_dirty()
420 self.save_dirty()
421 return (0, head)
421 return (0, head)
422
422
423 def patch(self, repo, patchfile):
423 def patch(self, repo, patchfile):
424 '''Apply patchfile to the working directory.
424 '''Apply patchfile to the working directory.
425 patchfile: file name of patch'''
425 patchfile: file name of patch'''
426 files = {}
426 files = {}
427 try:
427 try:
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
429 files=files)
429 files=files)
430 except Exception, inst:
430 except Exception, inst:
431 self.ui.note(str(inst) + '\n')
431 self.ui.note(str(inst) + '\n')
432 if not self.ui.verbose:
432 if not self.ui.verbose:
433 self.ui.warn("patch failed, unable to continue (try -v)\n")
433 self.ui.warn("patch failed, unable to continue (try -v)\n")
434 return (False, files, False)
434 return (False, files, False)
435
435
436 return (True, files, fuzz)
436 return (True, files, fuzz)
437
437
438 def apply(self, repo, series, list=False, update_status=True,
438 def apply(self, repo, series, list=False, update_status=True,
439 strict=False, patchdir=None, merge=None, all_files={}):
439 strict=False, patchdir=None, merge=None, all_files={}):
440 wlock = lock = tr = None
440 wlock = lock = tr = None
441 try:
441 try:
442 wlock = repo.wlock()
442 wlock = repo.wlock()
443 lock = repo.lock()
443 lock = repo.lock()
444 tr = repo.transaction()
444 tr = repo.transaction()
445 try:
445 try:
446 ret = self._apply(repo, series, list, update_status,
446 ret = self._apply(repo, series, list, update_status,
447 strict, patchdir, merge, all_files=all_files)
447 strict, patchdir, merge, all_files=all_files)
448 tr.close()
448 tr.close()
449 self.save_dirty()
449 self.save_dirty()
450 return ret
450 return ret
451 except:
451 except:
452 try:
452 try:
453 tr.abort()
453 tr.abort()
454 finally:
454 finally:
455 repo.invalidate()
455 repo.invalidate()
456 repo.dirstate.invalidate()
456 repo.dirstate.invalidate()
457 raise
457 raise
458 finally:
458 finally:
459 del tr, lock, wlock
459 del tr, lock, wlock
460 self.removeundo(repo)
460 self.removeundo(repo)
461
461
462 def _apply(self, repo, series, list=False, update_status=True,
462 def _apply(self, repo, series, list=False, update_status=True,
463 strict=False, patchdir=None, merge=None, all_files={}):
463 strict=False, patchdir=None, merge=None, all_files={}):
464 # TODO unify with commands.py
464 # TODO unify with commands.py
465 if not patchdir:
465 if not patchdir:
466 patchdir = self.path
466 patchdir = self.path
467 err = 0
467 err = 0
468 n = None
468 n = None
469 for patchname in series:
469 for patchname in series:
470 pushable, reason = self.pushable(patchname)
470 pushable, reason = self.pushable(patchname)
471 if not pushable:
471 if not pushable:
472 self.explain_pushable(patchname, all_patches=True)
472 self.explain_pushable(patchname, all_patches=True)
473 continue
473 continue
474 self.ui.warn("applying %s\n" % patchname)
474 self.ui.warn("applying %s\n" % patchname)
475 pf = os.path.join(patchdir, patchname)
475 pf = os.path.join(patchdir, patchname)
476
476
477 try:
477 try:
478 message, comments, user, date, patchfound = self.readheaders(patchname)
478 message, comments, user, date, patchfound = self.readheaders(patchname)
479 except:
479 except:
480 self.ui.warn("Unable to read %s\n" % patchname)
480 self.ui.warn("Unable to read %s\n" % patchname)
481 err = 1
481 err = 1
482 break
482 break
483
483
484 if not message:
484 if not message:
485 message = "imported patch %s\n" % patchname
485 message = "imported patch %s\n" % patchname
486 else:
486 else:
487 if list:
487 if list:
488 message.append("\nimported patch %s" % patchname)
488 message.append("\nimported patch %s" % patchname)
489 message = '\n'.join(message)
489 message = '\n'.join(message)
490
490
491 (patcherr, files, fuzz) = self.patch(repo, pf)
491 (patcherr, files, fuzz) = self.patch(repo, pf)
492 all_files.update(files)
492 all_files.update(files)
493 patcherr = not patcherr
493 patcherr = not patcherr
494
494
495 if merge and files:
495 if merge and files:
496 # Mark as removed/merged and update dirstate parent info
496 # Mark as removed/merged and update dirstate parent info
497 removed = []
497 removed = []
498 merged = []
498 merged = []
499 for f in files:
499 for f in files:
500 if os.path.exists(repo.wjoin(f)):
500 if os.path.exists(repo.wjoin(f)):
501 merged.append(f)
501 merged.append(f)
502 else:
502 else:
503 removed.append(f)
503 removed.append(f)
504 for f in removed:
504 for f in removed:
505 repo.dirstate.remove(f)
505 repo.dirstate.remove(f)
506 for f in merged:
506 for f in merged:
507 repo.dirstate.merge(f)
507 repo.dirstate.merge(f)
508 p1, p2 = repo.dirstate.parents()
508 p1, p2 = repo.dirstate.parents()
509 repo.dirstate.setparents(p1, merge)
509 repo.dirstate.setparents(p1, merge)
510 files = patch.updatedir(self.ui, repo, files)
510 files = patch.updatedir(self.ui, repo, files)
511 n = repo.commit(files, message, user, date, match=util.never,
511 n = repo.commit(files, message, user, date, match=util.never,
512 force=True)
512 force=True)
513
513
514 if n == None:
514 if n == None:
515 raise util.Abort(_("repo commit failed"))
515 raise util.Abort(_("repo commit failed"))
516
516
517 if update_status:
517 if update_status:
518 self.applied.append(statusentry(revlog.hex(n), patchname))
518 self.applied.append(statusentry(revlog.hex(n), patchname))
519
519
520 if patcherr:
520 if patcherr:
521 if not patchfound:
521 if not patchfound:
522 self.ui.warn("patch %s is empty\n" % patchname)
522 self.ui.warn("patch %s is empty\n" % patchname)
523 err = 0
523 err = 0
524 else:
524 else:
525 self.ui.warn("patch failed, rejects left in working dir\n")
525 self.ui.warn("patch failed, rejects left in working dir\n")
526 err = 1
526 err = 1
527 break
527 break
528
528
529 if fuzz and strict:
529 if fuzz and strict:
530 self.ui.warn("fuzz found when applying patch, stopping\n")
530 self.ui.warn("fuzz found when applying patch, stopping\n")
531 err = 1
531 err = 1
532 break
532 break
533 return (err, n)
533 return (err, n)
534
534
535 def delete(self, repo, patches, opts):
535 def delete(self, repo, patches, opts):
536 if not patches and not opts.get('rev'):
536 if not patches and not opts.get('rev'):
537 raise util.Abort(_('qdelete requires at least one revision or '
537 raise util.Abort(_('qdelete requires at least one revision or '
538 'patch name'))
538 'patch name'))
539
539
540 realpatches = []
540 realpatches = []
541 for patch in patches:
541 for patch in patches:
542 patch = self.lookup(patch, strict=True)
542 patch = self.lookup(patch, strict=True)
543 info = self.isapplied(patch)
543 info = self.isapplied(patch)
544 if info:
544 if info:
545 raise util.Abort(_("cannot delete applied patch %s") % patch)
545 raise util.Abort(_("cannot delete applied patch %s") % patch)
546 if patch not in self.series:
546 if patch not in self.series:
547 raise util.Abort(_("patch %s not in series file") % patch)
547 raise util.Abort(_("patch %s not in series file") % patch)
548 realpatches.append(patch)
548 realpatches.append(patch)
549
549
550 appliedbase = 0
550 appliedbase = 0
551 if opts.get('rev'):
551 if opts.get('rev'):
552 if not self.applied:
552 if not self.applied:
553 raise util.Abort(_('no patches applied'))
553 raise util.Abort(_('no patches applied'))
554 revs = cmdutil.revrange(repo, opts['rev'])
554 revs = cmdutil.revrange(repo, opts['rev'])
555 if len(revs) > 1 and revs[0] > revs[1]:
555 if len(revs) > 1 and revs[0] > revs[1]:
556 revs.reverse()
556 revs.reverse()
557 for rev in revs:
557 for rev in revs:
558 if appliedbase >= len(self.applied):
558 if appliedbase >= len(self.applied):
559 raise util.Abort(_("revision %d is not managed") % rev)
559 raise util.Abort(_("revision %d is not managed") % rev)
560
560
561 base = revlog.bin(self.applied[appliedbase].rev)
561 base = revlog.bin(self.applied[appliedbase].rev)
562 node = repo.changelog.node(rev)
562 node = repo.changelog.node(rev)
563 if node != base:
563 if node != base:
564 raise util.Abort(_("cannot delete revision %d above "
564 raise util.Abort(_("cannot delete revision %d above "
565 "applied patches") % rev)
565 "applied patches") % rev)
566 realpatches.append(self.applied[appliedbase].name)
566 realpatches.append(self.applied[appliedbase].name)
567 appliedbase += 1
567 appliedbase += 1
568
568
569 if not opts.get('keep'):
569 if not opts.get('keep'):
570 r = self.qrepo()
570 r = self.qrepo()
571 if r:
571 if r:
572 r.remove(realpatches, True)
572 r.remove(realpatches, True)
573 else:
573 else:
574 for p in realpatches:
574 for p in realpatches:
575 os.unlink(self.join(p))
575 os.unlink(self.join(p))
576
576
577 if appliedbase:
577 if appliedbase:
578 del self.applied[:appliedbase]
578 del self.applied[:appliedbase]
579 self.applied_dirty = 1
579 self.applied_dirty = 1
580 indices = [self.find_series(p) for p in realpatches]
580 indices = [self.find_series(p) for p in realpatches]
581 indices.sort()
581 indices.sort()
582 for i in indices[-1::-1]:
582 for i in indices[-1::-1]:
583 del self.full_series[i]
583 del self.full_series[i]
584 self.parse_series()
584 self.parse_series()
585 self.series_dirty = 1
585 self.series_dirty = 1
586
586
587 def check_toppatch(self, repo):
587 def check_toppatch(self, repo):
588 if len(self.applied) > 0:
588 if len(self.applied) > 0:
589 top = revlog.bin(self.applied[-1].rev)
589 top = revlog.bin(self.applied[-1].rev)
590 pp = repo.dirstate.parents()
590 pp = repo.dirstate.parents()
591 if top not in pp:
591 if top not in pp:
592 raise util.Abort(_("working directory revision is not qtip"))
592 raise util.Abort(_("working directory revision is not qtip"))
593 return top
593 return top
594 return None
594 return None
595 def check_localchanges(self, repo, force=False, refresh=True):
595 def check_localchanges(self, repo, force=False, refresh=True):
596 m, a, r, d = repo.status()[:4]
596 m, a, r, d = repo.status()[:4]
597 if m or a or r or d:
597 if m or a or r or d:
598 if not force:
598 if not force:
599 if refresh:
599 if refresh:
600 raise util.Abort(_("local changes found, refresh first"))
600 raise util.Abort(_("local changes found, refresh first"))
601 else:
601 else:
602 raise util.Abort(_("local changes found"))
602 raise util.Abort(_("local changes found"))
603 return m, a, r, d
603 return m, a, r, d
604
604
605 _reserved = ('series', 'status', 'guards')
605 _reserved = ('series', 'status', 'guards')
606 def check_reserved_name(self, name):
606 def check_reserved_name(self, name):
607 if (name in self._reserved or name.startswith('.hg')
607 if (name in self._reserved or name.startswith('.hg')
608 or name.startswith('.mq')):
608 or name.startswith('.mq')):
609 raise util.Abort(_('"%s" cannot be used as the name of a patch')
609 raise util.Abort(_('"%s" cannot be used as the name of a patch')
610 % name)
610 % name)
611
611
612 def new(self, repo, patch, *pats, **opts):
612 def new(self, repo, patch, *pats, **opts):
613 msg = opts.get('msg')
613 msg = opts.get('msg')
614 force = opts.get('force')
614 force = opts.get('force')
615 user = opts.get('user')
615 user = opts.get('user')
616 date = opts.get('date')
616 date = opts.get('date')
617 if date:
617 if date:
618 date = util.parsedate(date)
618 date = util.parsedate(date)
619 self.check_reserved_name(patch)
619 self.check_reserved_name(patch)
620 if os.path.exists(self.join(patch)):
620 if os.path.exists(self.join(patch)):
621 raise util.Abort(_('patch "%s" already exists') % patch)
621 raise util.Abort(_('patch "%s" already exists') % patch)
622 if opts.get('include') or opts.get('exclude') or pats:
622 if opts.get('include') or opts.get('exclude') or pats:
623 match = cmdutil.match(repo, pats, opts)
623 match = cmdutil.match(repo, pats, opts)
624 m, a, r, d = repo.status(files=match.files(), match=match)[:4]
624 m, a, r, d = repo.status(files=match.files(), match=match)[:4]
625 else:
625 else:
626 m, a, r, d = self.check_localchanges(repo, force)
626 m, a, r, d = self.check_localchanges(repo, force)
627 match = cmdutil.match(repo, m + a + r)
627 match = cmdutil.match(repo, m + a + r)
628 commitfiles = m + a + r
628 commitfiles = m + a + r
629 self.check_toppatch(repo)
629 self.check_toppatch(repo)
630 wlock = repo.wlock()
630 wlock = repo.wlock()
631 try:
631 try:
632 insert = self.full_series_end()
632 insert = self.full_series_end()
633 commitmsg = msg and msg or ("[mq]: %s" % patch)
633 commitmsg = msg and msg or ("[mq]: %s" % patch)
634 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
634 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
635 if n == None:
635 if n == None:
636 raise util.Abort(_("repo commit failed"))
636 raise util.Abort(_("repo commit failed"))
637 self.full_series[insert:insert] = [patch]
637 self.full_series[insert:insert] = [patch]
638 self.applied.append(statusentry(revlog.hex(n), patch))
638 self.applied.append(statusentry(revlog.hex(n), patch))
639 self.parse_series()
639 self.parse_series()
640 self.series_dirty = 1
640 self.series_dirty = 1
641 self.applied_dirty = 1
641 self.applied_dirty = 1
642 p = self.opener(patch, "w")
642 p = self.opener(patch, "w")
643 if date:
643 if date:
644 p.write("# HG changeset patch\n")
644 p.write("# HG changeset patch\n")
645 if user:
645 if user:
646 p.write("# User " + user + "\n")
646 p.write("# User " + user + "\n")
647 p.write("# Date %d %d\n" % date)
647 p.write("# Date %d %d\n" % date)
648 p.write("\n")
648 p.write("\n")
649 elif user:
649 elif user:
650 p.write("From: " + user + "\n")
650 p.write("From: " + user + "\n")
651 p.write("\n")
651 p.write("\n")
652 if msg:
652 if msg:
653 msg = msg + "\n"
653 msg = msg + "\n"
654 p.write(msg)
654 p.write(msg)
655 p.close()
655 p.close()
656 wlock = None
656 wlock = None
657 r = self.qrepo()
657 r = self.qrepo()
658 if r: r.add([patch])
658 if r: r.add([patch])
659 if commitfiles:
659 if commitfiles:
660 self.refresh(repo, short=True, git=opts.get('git'))
660 self.refresh(repo, short=True, git=opts.get('git'))
661 self.removeundo(repo)
661 self.removeundo(repo)
662 finally:
662 finally:
663 del wlock
663 del wlock
664
664
665 def strip(self, repo, rev, update=True, backup="all", force=None):
665 def strip(self, repo, rev, update=True, backup="all", force=None):
666 wlock = lock = None
666 wlock = lock = None
667 try:
667 try:
668 wlock = repo.wlock()
668 wlock = repo.wlock()
669 lock = repo.lock()
669 lock = repo.lock()
670
670
671 if update:
671 if update:
672 self.check_localchanges(repo, force=force, refresh=False)
672 self.check_localchanges(repo, force=force, refresh=False)
673 urev = self.qparents(repo, rev)
673 urev = self.qparents(repo, rev)
674 hg.clean(repo, urev)
674 hg.clean(repo, urev)
675 repo.dirstate.write()
675 repo.dirstate.write()
676
676
677 self.removeundo(repo)
677 self.removeundo(repo)
678 repair.strip(self.ui, repo, rev, backup)
678 repair.strip(self.ui, repo, rev, backup)
679 # strip may have unbundled a set of backed up revisions after
679 # strip may have unbundled a set of backed up revisions after
680 # the actual strip
680 # the actual strip
681 self.removeundo(repo)
681 self.removeundo(repo)
682 finally:
682 finally:
683 del lock, wlock
683 del lock, wlock
684
684
685 def isapplied(self, patch):
685 def isapplied(self, patch):
686 """returns (index, rev, patch)"""
686 """returns (index, rev, patch)"""
687 for i in xrange(len(self.applied)):
687 for i in xrange(len(self.applied)):
688 a = self.applied[i]
688 a = self.applied[i]
689 if a.name == patch:
689 if a.name == patch:
690 return (i, a.rev, a.name)
690 return (i, a.rev, a.name)
691 return None
691 return None
692
692
693 # if the exact patch name does not exist, we try a few
693 # if the exact patch name does not exist, we try a few
694 # variations. If strict is passed, we try only #1
694 # variations. If strict is passed, we try only #1
695 #
695 #
696 # 1) a number to indicate an offset in the series file
696 # 1) a number to indicate an offset in the series file
697 # 2) a unique substring of the patch name was given
697 # 2) a unique substring of the patch name was given
698 # 3) patchname[-+]num to indicate an offset in the series file
698 # 3) patchname[-+]num to indicate an offset in the series file
699 def lookup(self, patch, strict=False):
699 def lookup(self, patch, strict=False):
700 patch = patch and str(patch)
700 patch = patch and str(patch)
701
701
702 def partial_name(s):
702 def partial_name(s):
703 if s in self.series:
703 if s in self.series:
704 return s
704 return s
705 matches = [x for x in self.series if s in x]
705 matches = [x for x in self.series if s in x]
706 if len(matches) > 1:
706 if len(matches) > 1:
707 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
707 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
708 for m in matches:
708 for m in matches:
709 self.ui.warn(' %s\n' % m)
709 self.ui.warn(' %s\n' % m)
710 return None
710 return None
711 if matches:
711 if matches:
712 return matches[0]
712 return matches[0]
713 if len(self.series) > 0 and len(self.applied) > 0:
713 if len(self.series) > 0 and len(self.applied) > 0:
714 if s == 'qtip':
714 if s == 'qtip':
715 return self.series[self.series_end(True)-1]
715 return self.series[self.series_end(True)-1]
716 if s == 'qbase':
716 if s == 'qbase':
717 return self.series[0]
717 return self.series[0]
718 return None
718 return None
719 if patch == None:
719 if patch == None:
720 return None
720 return None
721
721
722 # we don't want to return a partial match until we make
722 # we don't want to return a partial match until we make
723 # sure the file name passed in does not exist (checked below)
723 # sure the file name passed in does not exist (checked below)
724 res = partial_name(patch)
724 res = partial_name(patch)
725 if res and res == patch:
725 if res and res == patch:
726 return res
726 return res
727
727
728 if not os.path.isfile(self.join(patch)):
728 if not os.path.isfile(self.join(patch)):
729 try:
729 try:
730 sno = int(patch)
730 sno = int(patch)
731 except(ValueError, OverflowError):
731 except(ValueError, OverflowError):
732 pass
732 pass
733 else:
733 else:
734 if sno < len(self.series):
734 if sno < len(self.series):
735 return self.series[sno]
735 return self.series[sno]
736 if not strict:
736 if not strict:
737 # return any partial match made above
737 # return any partial match made above
738 if res:
738 if res:
739 return res
739 return res
740 minus = patch.rfind('-')
740 minus = patch.rfind('-')
741 if minus >= 0:
741 if minus >= 0:
742 res = partial_name(patch[:minus])
742 res = partial_name(patch[:minus])
743 if res:
743 if res:
744 i = self.series.index(res)
744 i = self.series.index(res)
745 try:
745 try:
746 off = int(patch[minus+1:] or 1)
746 off = int(patch[minus+1:] or 1)
747 except(ValueError, OverflowError):
747 except(ValueError, OverflowError):
748 pass
748 pass
749 else:
749 else:
750 if i - off >= 0:
750 if i - off >= 0:
751 return self.series[i - off]
751 return self.series[i - off]
752 plus = patch.rfind('+')
752 plus = patch.rfind('+')
753 if plus >= 0:
753 if plus >= 0:
754 res = partial_name(patch[:plus])
754 res = partial_name(patch[:plus])
755 if res:
755 if res:
756 i = self.series.index(res)
756 i = self.series.index(res)
757 try:
757 try:
758 off = int(patch[plus+1:] or 1)
758 off = int(patch[plus+1:] or 1)
759 except(ValueError, OverflowError):
759 except(ValueError, OverflowError):
760 pass
760 pass
761 else:
761 else:
762 if i + off < len(self.series):
762 if i + off < len(self.series):
763 return self.series[i + off]
763 return self.series[i + off]
764 raise util.Abort(_("patch %s not in series") % patch)
764 raise util.Abort(_("patch %s not in series") % patch)
765
765
766 def push(self, repo, patch=None, force=False, list=False,
766 def push(self, repo, patch=None, force=False, list=False,
767 mergeq=None):
767 mergeq=None):
768 wlock = repo.wlock()
768 wlock = repo.wlock()
769 if repo.dirstate.parents()[0] != repo.changelog.tip():
769 if repo.dirstate.parents()[0] != repo.changelog.tip():
770 self.ui.status(_("(working directory not at tip)\n"))
770 self.ui.status(_("(working directory not at tip)\n"))
771
771
772 try:
772 try:
773 patch = self.lookup(patch)
773 patch = self.lookup(patch)
774 # Suppose our series file is: A B C and the current 'top'
774 # Suppose our series file is: A B C and the current 'top'
775 # patch is B. qpush C should be performed (moving forward)
775 # patch is B. qpush C should be performed (moving forward)
776 # qpush B is a NOP (no change) qpush A is an error (can't
776 # qpush B is a NOP (no change) qpush A is an error (can't
777 # go backwards with qpush)
777 # go backwards with qpush)
778 if patch:
778 if patch:
779 info = self.isapplied(patch)
779 info = self.isapplied(patch)
780 if info:
780 if info:
781 if info[0] < len(self.applied) - 1:
781 if info[0] < len(self.applied) - 1:
782 raise util.Abort(
782 raise util.Abort(
783 _("cannot push to a previous patch: %s") % patch)
783 _("cannot push to a previous patch: %s") % patch)
784 if info[0] < len(self.series) - 1:
784 if info[0] < len(self.series) - 1:
785 self.ui.warn(
785 self.ui.warn(
786 _('qpush: %s is already at the top\n') % patch)
786 _('qpush: %s is already at the top\n') % patch)
787 else:
787 else:
788 self.ui.warn(_('all patches are currently applied\n'))
788 self.ui.warn(_('all patches are currently applied\n'))
789 return
789 return
790
790
791 # Following the above example, starting at 'top' of B:
791 # Following the above example, starting at 'top' of B:
792 # qpush should be performed (pushes C), but a subsequent
792 # qpush should be performed (pushes C), but a subsequent
793 # qpush without an argument is an error (nothing to
793 # qpush without an argument is an error (nothing to
794 # apply). This allows a loop of "...while hg qpush..." to
794 # apply). This allows a loop of "...while hg qpush..." to
795 # work as it detects an error when done
795 # work as it detects an error when done
796 if self.series_end() == len(self.series):
796 if self.series_end() == len(self.series):
797 self.ui.warn(_('patch series already fully applied\n'))
797 self.ui.warn(_('patch series already fully applied\n'))
798 return 1
798 return 1
799 if not force:
799 if not force:
800 self.check_localchanges(repo)
800 self.check_localchanges(repo)
801
801
802 self.applied_dirty = 1;
802 self.applied_dirty = 1;
803 start = self.series_end()
803 start = self.series_end()
804 if start > 0:
804 if start > 0:
805 self.check_toppatch(repo)
805 self.check_toppatch(repo)
806 if not patch:
806 if not patch:
807 patch = self.series[start]
807 patch = self.series[start]
808 end = start + 1
808 end = start + 1
809 else:
809 else:
810 end = self.series.index(patch, start) + 1
810 end = self.series.index(patch, start) + 1
811 s = self.series[start:end]
811 s = self.series[start:end]
812 all_files = {}
812 all_files = {}
813 try:
813 try:
814 if mergeq:
814 if mergeq:
815 ret = self.mergepatch(repo, mergeq, s)
815 ret = self.mergepatch(repo, mergeq, s)
816 else:
816 else:
817 ret = self.apply(repo, s, list, all_files=all_files)
817 ret = self.apply(repo, s, list, all_files=all_files)
818 except:
818 except:
819 self.ui.warn(_('cleaning up working directory...'))
819 self.ui.warn(_('cleaning up working directory...'))
820 node = repo.dirstate.parents()[0]
820 node = repo.dirstate.parents()[0]
821 hg.revert(repo, node, None)
821 hg.revert(repo, node, None)
822 unknown = repo.status()[4]
822 unknown = repo.status()[4]
823 # only remove unknown files that we know we touched or
823 # only remove unknown files that we know we touched or
824 # created while patching
824 # created while patching
825 for f in unknown:
825 for f in unknown:
826 if f in all_files:
826 if f in all_files:
827 util.unlink(repo.wjoin(f))
827 util.unlink(repo.wjoin(f))
828 self.ui.warn(_('done\n'))
828 self.ui.warn(_('done\n'))
829 raise
829 raise
830 top = self.applied[-1].name
830 top = self.applied[-1].name
831 if ret[0]:
831 if ret[0]:
832 self.ui.write(
832 self.ui.write(
833 "Errors during apply, please fix and refresh %s\n" % top)
833 "Errors during apply, please fix and refresh %s\n" % top)
834 else:
834 else:
835 self.ui.write("Now at: %s\n" % top)
835 self.ui.write("Now at: %s\n" % top)
836 return ret[0]
836 return ret[0]
837 finally:
837 finally:
838 del wlock
838 del wlock
839
839
840 def pop(self, repo, patch=None, force=False, update=True, all=False):
840 def pop(self, repo, patch=None, force=False, update=True, all=False):
841 def getfile(f, rev, flags):
841 def getfile(f, rev, flags):
842 t = repo.file(f).read(rev)
842 t = repo.file(f).read(rev)
843 repo.wwrite(f, t, flags)
843 repo.wwrite(f, t, flags)
844
844
845 wlock = repo.wlock()
845 wlock = repo.wlock()
846 try:
846 try:
847 if patch:
847 if patch:
848 # index, rev, patch
848 # index, rev, patch
849 info = self.isapplied(patch)
849 info = self.isapplied(patch)
850 if not info:
850 if not info:
851 patch = self.lookup(patch)
851 patch = self.lookup(patch)
852 info = self.isapplied(patch)
852 info = self.isapplied(patch)
853 if not info:
853 if not info:
854 raise util.Abort(_("patch %s is not applied") % patch)
854 raise util.Abort(_("patch %s is not applied") % patch)
855
855
856 if len(self.applied) == 0:
856 if len(self.applied) == 0:
857 # Allow qpop -a to work repeatedly,
857 # Allow qpop -a to work repeatedly,
858 # but not qpop without an argument
858 # but not qpop without an argument
859 self.ui.warn(_("no patches applied\n"))
859 self.ui.warn(_("no patches applied\n"))
860 return not all
860 return not all
861
861
862 if not update:
862 if not update:
863 parents = repo.dirstate.parents()
863 parents = repo.dirstate.parents()
864 rr = [ revlog.bin(x.rev) for x in self.applied ]
864 rr = [ revlog.bin(x.rev) for x in self.applied ]
865 for p in parents:
865 for p in parents:
866 if p in rr:
866 if p in rr:
867 self.ui.warn("qpop: forcing dirstate update\n")
867 self.ui.warn("qpop: forcing dirstate update\n")
868 update = True
868 update = True
869
869
870 if not force and update:
870 if not force and update:
871 self.check_localchanges(repo)
871 self.check_localchanges(repo)
872
872
873 self.applied_dirty = 1;
873 self.applied_dirty = 1;
874 end = len(self.applied)
874 end = len(self.applied)
875 if not patch:
875 if not patch:
876 if all:
876 if all:
877 popi = 0
877 popi = 0
878 else:
878 else:
879 popi = len(self.applied) - 1
879 popi = len(self.applied) - 1
880 else:
880 else:
881 popi = info[0] + 1
881 popi = info[0] + 1
882 if popi >= end:
882 if popi >= end:
883 self.ui.warn("qpop: %s is already at the top\n" % patch)
883 self.ui.warn("qpop: %s is already at the top\n" % patch)
884 return
884 return
885 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
885 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
886
886
887 start = info[0]
887 start = info[0]
888 rev = revlog.bin(info[1])
888 rev = revlog.bin(info[1])
889
889
890 if update:
890 if update:
891 top = self.check_toppatch(repo)
891 top = self.check_toppatch(repo)
892
892
893 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
893 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
894 raise util.Abort("popping would remove a revision not "
894 raise util.Abort("popping would remove a revision not "
895 "managed by this patch queue")
895 "managed by this patch queue")
896
896
897 # we know there are no local changes, so we can make a simplified
897 # we know there are no local changes, so we can make a simplified
898 # form of hg.update.
898 # form of hg.update.
899 if update:
899 if update:
900 qp = self.qparents(repo, rev)
900 qp = self.qparents(repo, rev)
901 changes = repo.changelog.read(qp)
901 changes = repo.changelog.read(qp)
902 mmap = repo.manifest.read(changes[0])
902 mmap = repo.manifest.read(changes[0])
903 m, a, r, d, u = repo.status(qp, top)[:5]
903 m, a, r, d, u = repo.status(qp, top)[:5]
904 if d:
904 if d:
905 raise util.Abort("deletions found between repo revs")
905 raise util.Abort("deletions found between repo revs")
906 for f in m:
906 for f in m:
907 getfile(f, mmap[f], mmap.flags(f))
907 getfile(f, mmap[f], mmap.flags(f))
908 for f in r:
908 for f in r:
909 getfile(f, mmap[f], mmap.flags(f))
909 getfile(f, mmap[f], mmap.flags(f))
910 for f in m + r:
910 for f in m + r:
911 repo.dirstate.normal(f)
911 repo.dirstate.normal(f)
912 for f in a:
912 for f in a:
913 try:
913 try:
914 os.unlink(repo.wjoin(f))
914 os.unlink(repo.wjoin(f))
915 except OSError, e:
915 except OSError, e:
916 if e.errno != errno.ENOENT:
916 if e.errno != errno.ENOENT:
917 raise
917 raise
918 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
918 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
919 except: pass
919 except: pass
920 repo.dirstate.forget(f)
920 repo.dirstate.forget(f)
921 repo.dirstate.setparents(qp, revlog.nullid)
921 repo.dirstate.setparents(qp, revlog.nullid)
922 del self.applied[start:end]
922 del self.applied[start:end]
923 self.strip(repo, rev, update=False, backup='strip')
923 self.strip(repo, rev, update=False, backup='strip')
924 if len(self.applied):
924 if len(self.applied):
925 self.ui.write("Now at: %s\n" % self.applied[-1].name)
925 self.ui.write("Now at: %s\n" % self.applied[-1].name)
926 else:
926 else:
927 self.ui.write("Patch queue now empty\n")
927 self.ui.write("Patch queue now empty\n")
928 finally:
928 finally:
929 del wlock
929 del wlock
930
930
931 def diff(self, repo, pats, opts):
931 def diff(self, repo, pats, opts):
932 top = self.check_toppatch(repo)
932 top = self.check_toppatch(repo)
933 if not top:
933 if not top:
934 self.ui.write("No patches applied\n")
934 self.ui.write("No patches applied\n")
935 return
935 return
936 qp = self.qparents(repo, top)
936 qp = self.qparents(repo, top)
937 if opts.get('git'):
937 if opts.get('git'):
938 self.diffopts().git = True
938 self.diffopts().git = True
939 if opts.get('unified') is not None:
939 if opts.get('unified') is not None:
940 self.diffopts().context = opts['unified']
940 self.diffopts().context = opts['unified']
941 self.printdiff(repo, qp, files=pats, opts=opts)
941 self.printdiff(repo, qp, files=pats, opts=opts)
942
942
943 def refresh(self, repo, pats=None, **opts):
943 def refresh(self, repo, pats=None, **opts):
944 if len(self.applied) == 0:
944 if len(self.applied) == 0:
945 self.ui.write("No patches applied\n")
945 self.ui.write("No patches applied\n")
946 return 1
946 return 1
947 newdate = opts.get('date')
947 newdate = opts.get('date')
948 if newdate:
948 if newdate:
949 newdate = '%d %d' % util.parsedate(newdate)
949 newdate = '%d %d' % util.parsedate(newdate)
950 wlock = repo.wlock()
950 wlock = repo.wlock()
951 try:
951 try:
952 self.check_toppatch(repo)
952 self.check_toppatch(repo)
953 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
953 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
954 top = revlog.bin(top)
954 top = revlog.bin(top)
955 if repo.changelog.heads(top) != [top]:
955 if repo.changelog.heads(top) != [top]:
956 raise util.Abort("cannot refresh a revision with children")
956 raise util.Abort("cannot refresh a revision with children")
957 cparents = repo.changelog.parents(top)
957 cparents = repo.changelog.parents(top)
958 patchparent = self.qparents(repo, top)
958 patchparent = self.qparents(repo, top)
959 message, comments, user, date, patchfound = self.readheaders(patchfn)
959 message, comments, user, date, patchfound = self.readheaders(patchfn)
960
960
961 patchf = self.opener(patchfn, 'r+')
961 patchf = self.opener(patchfn, 'r+')
962
962
963 # if the patch was a git patch, refresh it as a git patch
963 # if the patch was a git patch, refresh it as a git patch
964 for line in patchf:
964 for line in patchf:
965 if line.startswith('diff --git'):
965 if line.startswith('diff --git'):
966 self.diffopts().git = True
966 self.diffopts().git = True
967 break
967 break
968
968
969 msg = opts.get('msg', '').rstrip()
969 msg = opts.get('msg', '').rstrip()
970 if msg and comments:
970 if msg and comments:
971 # Remove existing message, keeping the rest of the comments
971 # Remove existing message, keeping the rest of the comments
972 # fields.
972 # fields.
973 # If comments contains 'subject: ', message will prepend
973 # If comments contains 'subject: ', message will prepend
974 # the field and a blank line.
974 # the field and a blank line.
975 if message:
975 if message:
976 subj = 'subject: ' + message[0].lower()
976 subj = 'subject: ' + message[0].lower()
977 for i in xrange(len(comments)):
977 for i in xrange(len(comments)):
978 if subj == comments[i].lower():
978 if subj == comments[i].lower():
979 del comments[i]
979 del comments[i]
980 message = message[2:]
980 message = message[2:]
981 break
981 break
982 ci = 0
982 ci = 0
983 for mi in xrange(len(message)):
983 for mi in xrange(len(message)):
984 while message[mi] != comments[ci]:
984 while message[mi] != comments[ci]:
985 ci += 1
985 ci += 1
986 del comments[ci]
986 del comments[ci]
987
987
988 def setheaderfield(comments, prefixes, new):
988 def setheaderfield(comments, prefixes, new):
989 # Update all references to a field in the patch header.
989 # Update all references to a field in the patch header.
990 # If none found, add it email style.
990 # If none found, add it email style.
991 res = False
991 res = False
992 for prefix in prefixes:
992 for prefix in prefixes:
993 for i in xrange(len(comments)):
993 for i in xrange(len(comments)):
994 if comments[i].startswith(prefix):
994 if comments[i].startswith(prefix):
995 comments[i] = prefix + new
995 comments[i] = prefix + new
996 res = True
996 res = True
997 break
997 break
998 return res
998 return res
999
999
1000 newuser = opts.get('user')
1000 newuser = opts.get('user')
1001 if newuser:
1001 if newuser:
1002 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1002 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1003 try:
1003 try:
1004 patchheaderat = comments.index('# HG changeset patch')
1004 patchheaderat = comments.index('# HG changeset patch')
1005 comments.insert(patchheaderat + 1,'# User ' + newuser)
1005 comments.insert(patchheaderat + 1,'# User ' + newuser)
1006 except ValueError:
1006 except ValueError:
1007 comments = ['From: ' + newuser, ''] + comments
1007 comments = ['From: ' + newuser, ''] + comments
1008 user = newuser
1008 user = newuser
1009
1009
1010 if newdate:
1010 if newdate:
1011 if setheaderfield(comments, ['# Date '], newdate):
1011 if setheaderfield(comments, ['# Date '], newdate):
1012 date = newdate
1012 date = newdate
1013
1013
1014 if msg:
1014 if msg:
1015 comments.append(msg)
1015 comments.append(msg)
1016
1016
1017 patchf.seek(0)
1017 patchf.seek(0)
1018 patchf.truncate()
1018 patchf.truncate()
1019
1019
1020 if comments:
1020 if comments:
1021 comments = "\n".join(comments) + '\n\n'
1021 comments = "\n".join(comments) + '\n\n'
1022 patchf.write(comments)
1022 patchf.write(comments)
1023
1023
1024 if opts.get('git'):
1024 if opts.get('git'):
1025 self.diffopts().git = True
1025 self.diffopts().git = True
1026 matchfn = cmdutil.match(repo, pats, opts)
1026 matchfn = cmdutil.match(repo, pats, opts)
1027 tip = repo.changelog.tip()
1027 tip = repo.changelog.tip()
1028 if top == tip:
1028 if top == tip:
1029 # if the top of our patch queue is also the tip, there is an
1029 # if the top of our patch queue is also the tip, there is an
1030 # optimization here. We update the dirstate in place and strip
1030 # optimization here. We update the dirstate in place and strip
1031 # off the tip commit. Then just commit the current directory
1031 # off the tip commit. Then just commit the current directory
1032 # tree. We can also send repo.commit the list of files
1032 # tree. We can also send repo.commit the list of files
1033 # changed to speed up the diff
1033 # changed to speed up the diff
1034 #
1034 #
1035 # in short mode, we only diff the files included in the
1035 # in short mode, we only diff the files included in the
1036 # patch already
1036 # patch already
1037 #
1037 #
1038 # this should really read:
1038 # this should really read:
1039 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1039 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1040 # but we do it backwards to take advantage of manifest/chlog
1040 # but we do it backwards to take advantage of manifest/chlog
1041 # caching against the next repo.status call
1041 # caching against the next repo.status call
1042 #
1042 #
1043 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1043 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1044 changes = repo.changelog.read(tip)
1044 changes = repo.changelog.read(tip)
1045 man = repo.manifest.read(changes[0])
1045 man = repo.manifest.read(changes[0])
1046 aaa = aa[:]
1046 aaa = aa[:]
1047 if opts.get('short'):
1047 if opts.get('short'):
1048 filelist = mm + aa + dd
1048 match = cmdutil.matchfiles(repo, mm + aa + dd)
1049 match = dict.fromkeys(filelist).__contains__
1050 else:
1049 else:
1051 filelist = None
1050 match = cmdutil.matchall(repo)
1052 match = util.always
1051 m, a, r, d, u = repo.status(files=match.files(), match=match)[:5]
1053 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
1054
1052
1055 # we might end up with files that were added between
1053 # we might end up with files that were added between
1056 # tip and the dirstate parent, but then changed in the
1054 # tip and the dirstate parent, but then changed in the
1057 # local dirstate. in this case, we want them to only
1055 # local dirstate. in this case, we want them to only
1058 # show up in the added section
1056 # show up in the added section
1059 for x in m:
1057 for x in m:
1060 if x not in aa:
1058 if x not in aa:
1061 mm.append(x)
1059 mm.append(x)
1062 # we might end up with files added by the local dirstate that
1060 # we might end up with files added by the local dirstate that
1063 # were deleted by the patch. In this case, they should only
1061 # were deleted by the patch. In this case, they should only
1064 # show up in the changed section.
1062 # show up in the changed section.
1065 for x in a:
1063 for x in a:
1066 if x in dd:
1064 if x in dd:
1067 del dd[dd.index(x)]
1065 del dd[dd.index(x)]
1068 mm.append(x)
1066 mm.append(x)
1069 else:
1067 else:
1070 aa.append(x)
1068 aa.append(x)
1071 # make sure any files deleted in the local dirstate
1069 # make sure any files deleted in the local dirstate
1072 # are not in the add or change column of the patch
1070 # are not in the add or change column of the patch
1073 forget = []
1071 forget = []
1074 for x in d + r:
1072 for x in d + r:
1075 if x in aa:
1073 if x in aa:
1076 del aa[aa.index(x)]
1074 del aa[aa.index(x)]
1077 forget.append(x)
1075 forget.append(x)
1078 continue
1076 continue
1079 elif x in mm:
1077 elif x in mm:
1080 del mm[mm.index(x)]
1078 del mm[mm.index(x)]
1081 dd.append(x)
1079 dd.append(x)
1082
1080
1083 m = util.unique(mm)
1081 m = util.unique(mm)
1084 r = util.unique(dd)
1082 r = util.unique(dd)
1085 a = util.unique(aa)
1083 a = util.unique(aa)
1086 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1084 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1087 filelist = util.unique(c[0] + c[1] + c[2])
1085 filelist = util.unique(c[0] + c[1] + c[2])
1088 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1086 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1089 fp=patchf, changes=c, opts=self.diffopts())
1087 fp=patchf, changes=c, opts=self.diffopts())
1090 patchf.close()
1088 patchf.close()
1091
1089
1092 repo.dirstate.setparents(*cparents)
1090 repo.dirstate.setparents(*cparents)
1093 copies = {}
1091 copies = {}
1094 for dst in a:
1092 for dst in a:
1095 src = repo.dirstate.copied(dst)
1093 src = repo.dirstate.copied(dst)
1096 if src is not None:
1094 if src is not None:
1097 copies.setdefault(src, []).append(dst)
1095 copies.setdefault(src, []).append(dst)
1098 repo.dirstate.add(dst)
1096 repo.dirstate.add(dst)
1099 # remember the copies between patchparent and tip
1097 # remember the copies between patchparent and tip
1100 # this may be slow, so don't do it if we're not tracking copies
1098 # this may be slow, so don't do it if we're not tracking copies
1101 if self.diffopts().git:
1099 if self.diffopts().git:
1102 for dst in aaa:
1100 for dst in aaa:
1103 f = repo.file(dst)
1101 f = repo.file(dst)
1104 src = f.renamed(man[dst])
1102 src = f.renamed(man[dst])
1105 if src:
1103 if src:
1106 copies[src[0]] = copies.get(dst, [])
1104 copies[src[0]] = copies.get(dst, [])
1107 if dst in a:
1105 if dst in a:
1108 copies[src[0]].append(dst)
1106 copies[src[0]].append(dst)
1109 # we can't copy a file created by the patch itself
1107 # we can't copy a file created by the patch itself
1110 if dst in copies:
1108 if dst in copies:
1111 del copies[dst]
1109 del copies[dst]
1112 for src, dsts in copies.iteritems():
1110 for src, dsts in copies.iteritems():
1113 for dst in dsts:
1111 for dst in dsts:
1114 repo.dirstate.copy(src, dst)
1112 repo.dirstate.copy(src, dst)
1115 for f in r:
1113 for f in r:
1116 repo.dirstate.remove(f)
1114 repo.dirstate.remove(f)
1117 # if the patch excludes a modified file, mark that
1115 # if the patch excludes a modified file, mark that
1118 # file with mtime=0 so status can see it.
1116 # file with mtime=0 so status can see it.
1119 mm = []
1117 mm = []
1120 for i in xrange(len(m)-1, -1, -1):
1118 for i in xrange(len(m)-1, -1, -1):
1121 if not matchfn(m[i]):
1119 if not matchfn(m[i]):
1122 mm.append(m[i])
1120 mm.append(m[i])
1123 del m[i]
1121 del m[i]
1124 for f in m:
1122 for f in m:
1125 repo.dirstate.normal(f)
1123 repo.dirstate.normal(f)
1126 for f in mm:
1124 for f in mm:
1127 repo.dirstate.normallookup(f)
1125 repo.dirstate.normallookup(f)
1128 for f in forget:
1126 for f in forget:
1129 repo.dirstate.forget(f)
1127 repo.dirstate.forget(f)
1130
1128
1131 if not msg:
1129 if not msg:
1132 if not message:
1130 if not message:
1133 message = "[mq]: %s\n" % patchfn
1131 message = "[mq]: %s\n" % patchfn
1134 else:
1132 else:
1135 message = "\n".join(message)
1133 message = "\n".join(message)
1136 else:
1134 else:
1137 message = msg
1135 message = msg
1138
1136
1139 if not user:
1137 if not user:
1140 user = changes[1]
1138 user = changes[1]
1141
1139
1142 self.applied.pop()
1140 self.applied.pop()
1143 self.applied_dirty = 1
1141 self.applied_dirty = 1
1144 self.strip(repo, top, update=False,
1142 self.strip(repo, top, update=False,
1145 backup='strip')
1143 backup='strip')
1146 n = repo.commit(filelist, message, user, date, match=matchfn,
1144 n = repo.commit(filelist, message, user, date, match=matchfn,
1147 force=1)
1145 force=1)
1148 self.applied.append(statusentry(revlog.hex(n), patchfn))
1146 self.applied.append(statusentry(revlog.hex(n), patchfn))
1149 self.removeundo(repo)
1147 self.removeundo(repo)
1150 else:
1148 else:
1151 self.printdiff(repo, patchparent, fp=patchf)
1149 self.printdiff(repo, patchparent, fp=patchf)
1152 patchf.close()
1150 patchf.close()
1153 added = repo.status()[1]
1151 added = repo.status()[1]
1154 for a in added:
1152 for a in added:
1155 f = repo.wjoin(a)
1153 f = repo.wjoin(a)
1156 try:
1154 try:
1157 os.unlink(f)
1155 os.unlink(f)
1158 except OSError, e:
1156 except OSError, e:
1159 if e.errno != errno.ENOENT:
1157 if e.errno != errno.ENOENT:
1160 raise
1158 raise
1161 try: os.removedirs(os.path.dirname(f))
1159 try: os.removedirs(os.path.dirname(f))
1162 except: pass
1160 except: pass
1163 # forget the file copies in the dirstate
1161 # forget the file copies in the dirstate
1164 # push should readd the files later on
1162 # push should readd the files later on
1165 repo.dirstate.forget(a)
1163 repo.dirstate.forget(a)
1166 self.pop(repo, force=True)
1164 self.pop(repo, force=True)
1167 self.push(repo, force=True)
1165 self.push(repo, force=True)
1168 finally:
1166 finally:
1169 del wlock
1167 del wlock
1170
1168
1171 def init(self, repo, create=False):
1169 def init(self, repo, create=False):
1172 if not create and os.path.isdir(self.path):
1170 if not create and os.path.isdir(self.path):
1173 raise util.Abort(_("patch queue directory already exists"))
1171 raise util.Abort(_("patch queue directory already exists"))
1174 try:
1172 try:
1175 os.mkdir(self.path)
1173 os.mkdir(self.path)
1176 except OSError, inst:
1174 except OSError, inst:
1177 if inst.errno != errno.EEXIST or not create:
1175 if inst.errno != errno.EEXIST or not create:
1178 raise
1176 raise
1179 if create:
1177 if create:
1180 return self.qrepo(create=True)
1178 return self.qrepo(create=True)
1181
1179
1182 def unapplied(self, repo, patch=None):
1180 def unapplied(self, repo, patch=None):
1183 if patch and patch not in self.series:
1181 if patch and patch not in self.series:
1184 raise util.Abort(_("patch %s is not in series file") % patch)
1182 raise util.Abort(_("patch %s is not in series file") % patch)
1185 if not patch:
1183 if not patch:
1186 start = self.series_end()
1184 start = self.series_end()
1187 else:
1185 else:
1188 start = self.series.index(patch) + 1
1186 start = self.series.index(patch) + 1
1189 unapplied = []
1187 unapplied = []
1190 for i in xrange(start, len(self.series)):
1188 for i in xrange(start, len(self.series)):
1191 pushable, reason = self.pushable(i)
1189 pushable, reason = self.pushable(i)
1192 if pushable:
1190 if pushable:
1193 unapplied.append((i, self.series[i]))
1191 unapplied.append((i, self.series[i]))
1194 self.explain_pushable(i)
1192 self.explain_pushable(i)
1195 return unapplied
1193 return unapplied
1196
1194
1197 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1195 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1198 summary=False):
1196 summary=False):
1199 def displayname(patchname):
1197 def displayname(patchname):
1200 if summary:
1198 if summary:
1201 msg = self.readheaders(patchname)[0]
1199 msg = self.readheaders(patchname)[0]
1202 msg = msg and ': ' + msg[0] or ': '
1200 msg = msg and ': ' + msg[0] or ': '
1203 else:
1201 else:
1204 msg = ''
1202 msg = ''
1205 return '%s%s' % (patchname, msg)
1203 return '%s%s' % (patchname, msg)
1206
1204
1207 applied = dict.fromkeys([p.name for p in self.applied])
1205 applied = dict.fromkeys([p.name for p in self.applied])
1208 if length is None:
1206 if length is None:
1209 length = len(self.series) - start
1207 length = len(self.series) - start
1210 if not missing:
1208 if not missing:
1211 for i in xrange(start, start+length):
1209 for i in xrange(start, start+length):
1212 patch = self.series[i]
1210 patch = self.series[i]
1213 if patch in applied:
1211 if patch in applied:
1214 stat = 'A'
1212 stat = 'A'
1215 elif self.pushable(i)[0]:
1213 elif self.pushable(i)[0]:
1216 stat = 'U'
1214 stat = 'U'
1217 else:
1215 else:
1218 stat = 'G'
1216 stat = 'G'
1219 pfx = ''
1217 pfx = ''
1220 if self.ui.verbose:
1218 if self.ui.verbose:
1221 pfx = '%d %s ' % (i, stat)
1219 pfx = '%d %s ' % (i, stat)
1222 elif status and status != stat:
1220 elif status and status != stat:
1223 continue
1221 continue
1224 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1222 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1225 else:
1223 else:
1226 msng_list = []
1224 msng_list = []
1227 for root, dirs, files in os.walk(self.path):
1225 for root, dirs, files in os.walk(self.path):
1228 d = root[len(self.path) + 1:]
1226 d = root[len(self.path) + 1:]
1229 for f in files:
1227 for f in files:
1230 fl = os.path.join(d, f)
1228 fl = os.path.join(d, f)
1231 if (fl not in self.series and
1229 if (fl not in self.series and
1232 fl not in (self.status_path, self.series_path,
1230 fl not in (self.status_path, self.series_path,
1233 self.guards_path)
1231 self.guards_path)
1234 and not fl.startswith('.')):
1232 and not fl.startswith('.')):
1235 msng_list.append(fl)
1233 msng_list.append(fl)
1236 msng_list.sort()
1234 msng_list.sort()
1237 for x in msng_list:
1235 for x in msng_list:
1238 pfx = self.ui.verbose and ('D ') or ''
1236 pfx = self.ui.verbose and ('D ') or ''
1239 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1237 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1240
1238
1241 def issaveline(self, l):
1239 def issaveline(self, l):
1242 if l.name == '.hg.patches.save.line':
1240 if l.name == '.hg.patches.save.line':
1243 return True
1241 return True
1244
1242
1245 def qrepo(self, create=False):
1243 def qrepo(self, create=False):
1246 if create or os.path.isdir(self.join(".hg")):
1244 if create or os.path.isdir(self.join(".hg")):
1247 return hg.repository(self.ui, path=self.path, create=create)
1245 return hg.repository(self.ui, path=self.path, create=create)
1248
1246
1249 def restore(self, repo, rev, delete=None, qupdate=None):
1247 def restore(self, repo, rev, delete=None, qupdate=None):
1250 c = repo.changelog.read(rev)
1248 c = repo.changelog.read(rev)
1251 desc = c[4].strip()
1249 desc = c[4].strip()
1252 lines = desc.splitlines()
1250 lines = desc.splitlines()
1253 i = 0
1251 i = 0
1254 datastart = None
1252 datastart = None
1255 series = []
1253 series = []
1256 applied = []
1254 applied = []
1257 qpp = None
1255 qpp = None
1258 for i in xrange(0, len(lines)):
1256 for i in xrange(0, len(lines)):
1259 if lines[i] == 'Patch Data:':
1257 if lines[i] == 'Patch Data:':
1260 datastart = i + 1
1258 datastart = i + 1
1261 elif lines[i].startswith('Dirstate:'):
1259 elif lines[i].startswith('Dirstate:'):
1262 l = lines[i].rstrip()
1260 l = lines[i].rstrip()
1263 l = l[10:].split(' ')
1261 l = l[10:].split(' ')
1264 qpp = [ bin(x) for x in l ]
1262 qpp = [ bin(x) for x in l ]
1265 elif datastart != None:
1263 elif datastart != None:
1266 l = lines[i].rstrip()
1264 l = lines[i].rstrip()
1267 se = statusentry(l)
1265 se = statusentry(l)
1268 file_ = se.name
1266 file_ = se.name
1269 if se.rev:
1267 if se.rev:
1270 applied.append(se)
1268 applied.append(se)
1271 else:
1269 else:
1272 series.append(file_)
1270 series.append(file_)
1273 if datastart == None:
1271 if datastart == None:
1274 self.ui.warn("No saved patch data found\n")
1272 self.ui.warn("No saved patch data found\n")
1275 return 1
1273 return 1
1276 self.ui.warn("restoring status: %s\n" % lines[0])
1274 self.ui.warn("restoring status: %s\n" % lines[0])
1277 self.full_series = series
1275 self.full_series = series
1278 self.applied = applied
1276 self.applied = applied
1279 self.parse_series()
1277 self.parse_series()
1280 self.series_dirty = 1
1278 self.series_dirty = 1
1281 self.applied_dirty = 1
1279 self.applied_dirty = 1
1282 heads = repo.changelog.heads()
1280 heads = repo.changelog.heads()
1283 if delete:
1281 if delete:
1284 if rev not in heads:
1282 if rev not in heads:
1285 self.ui.warn("save entry has children, leaving it alone\n")
1283 self.ui.warn("save entry has children, leaving it alone\n")
1286 else:
1284 else:
1287 self.ui.warn("removing save entry %s\n" % short(rev))
1285 self.ui.warn("removing save entry %s\n" % short(rev))
1288 pp = repo.dirstate.parents()
1286 pp = repo.dirstate.parents()
1289 if rev in pp:
1287 if rev in pp:
1290 update = True
1288 update = True
1291 else:
1289 else:
1292 update = False
1290 update = False
1293 self.strip(repo, rev, update=update, backup='strip')
1291 self.strip(repo, rev, update=update, backup='strip')
1294 if qpp:
1292 if qpp:
1295 self.ui.warn("saved queue repository parents: %s %s\n" %
1293 self.ui.warn("saved queue repository parents: %s %s\n" %
1296 (short(qpp[0]), short(qpp[1])))
1294 (short(qpp[0]), short(qpp[1])))
1297 if qupdate:
1295 if qupdate:
1298 self.ui.status(_("queue directory updating\n"))
1296 self.ui.status(_("queue directory updating\n"))
1299 r = self.qrepo()
1297 r = self.qrepo()
1300 if not r:
1298 if not r:
1301 self.ui.warn("Unable to load queue repository\n")
1299 self.ui.warn("Unable to load queue repository\n")
1302 return 1
1300 return 1
1303 hg.clean(r, qpp[0])
1301 hg.clean(r, qpp[0])
1304
1302
1305 def save(self, repo, msg=None):
1303 def save(self, repo, msg=None):
1306 if len(self.applied) == 0:
1304 if len(self.applied) == 0:
1307 self.ui.warn("save: no patches applied, exiting\n")
1305 self.ui.warn("save: no patches applied, exiting\n")
1308 return 1
1306 return 1
1309 if self.issaveline(self.applied[-1]):
1307 if self.issaveline(self.applied[-1]):
1310 self.ui.warn("status is already saved\n")
1308 self.ui.warn("status is already saved\n")
1311 return 1
1309 return 1
1312
1310
1313 ar = [ ':' + x for x in self.full_series ]
1311 ar = [ ':' + x for x in self.full_series ]
1314 if not msg:
1312 if not msg:
1315 msg = "hg patches saved state"
1313 msg = "hg patches saved state"
1316 else:
1314 else:
1317 msg = "hg patches: " + msg.rstrip('\r\n')
1315 msg = "hg patches: " + msg.rstrip('\r\n')
1318 r = self.qrepo()
1316 r = self.qrepo()
1319 if r:
1317 if r:
1320 pp = r.dirstate.parents()
1318 pp = r.dirstate.parents()
1321 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1319 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1322 msg += "\n\nPatch Data:\n"
1320 msg += "\n\nPatch Data:\n"
1323 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1321 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1324 "\n".join(ar) + '\n' or "")
1322 "\n".join(ar) + '\n' or "")
1325 n = repo.commit(None, text, user=None, force=1)
1323 n = repo.commit(None, text, user=None, force=1)
1326 if not n:
1324 if not n:
1327 self.ui.warn("repo commit failed\n")
1325 self.ui.warn("repo commit failed\n")
1328 return 1
1326 return 1
1329 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1327 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1330 self.applied_dirty = 1
1328 self.applied_dirty = 1
1331 self.removeundo(repo)
1329 self.removeundo(repo)
1332
1330
1333 def full_series_end(self):
1331 def full_series_end(self):
1334 if len(self.applied) > 0:
1332 if len(self.applied) > 0:
1335 p = self.applied[-1].name
1333 p = self.applied[-1].name
1336 end = self.find_series(p)
1334 end = self.find_series(p)
1337 if end == None:
1335 if end == None:
1338 return len(self.full_series)
1336 return len(self.full_series)
1339 return end + 1
1337 return end + 1
1340 return 0
1338 return 0
1341
1339
1342 def series_end(self, all_patches=False):
1340 def series_end(self, all_patches=False):
1343 """If all_patches is False, return the index of the next pushable patch
1341 """If all_patches is False, return the index of the next pushable patch
1344 in the series, or the series length. If all_patches is True, return the
1342 in the series, or the series length. If all_patches is True, return the
1345 index of the first patch past the last applied one.
1343 index of the first patch past the last applied one.
1346 """
1344 """
1347 end = 0
1345 end = 0
1348 def next(start):
1346 def next(start):
1349 if all_patches:
1347 if all_patches:
1350 return start
1348 return start
1351 i = start
1349 i = start
1352 while i < len(self.series):
1350 while i < len(self.series):
1353 p, reason = self.pushable(i)
1351 p, reason = self.pushable(i)
1354 if p:
1352 if p:
1355 break
1353 break
1356 self.explain_pushable(i)
1354 self.explain_pushable(i)
1357 i += 1
1355 i += 1
1358 return i
1356 return i
1359 if len(self.applied) > 0:
1357 if len(self.applied) > 0:
1360 p = self.applied[-1].name
1358 p = self.applied[-1].name
1361 try:
1359 try:
1362 end = self.series.index(p)
1360 end = self.series.index(p)
1363 except ValueError:
1361 except ValueError:
1364 return 0
1362 return 0
1365 return next(end + 1)
1363 return next(end + 1)
1366 return next(end)
1364 return next(end)
1367
1365
1368 def appliedname(self, index):
1366 def appliedname(self, index):
1369 pname = self.applied[index].name
1367 pname = self.applied[index].name
1370 if not self.ui.verbose:
1368 if not self.ui.verbose:
1371 p = pname
1369 p = pname
1372 else:
1370 else:
1373 p = str(self.series.index(pname)) + " " + pname
1371 p = str(self.series.index(pname)) + " " + pname
1374 return p
1372 return p
1375
1373
1376 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1374 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1377 force=None, git=False):
1375 force=None, git=False):
1378 def checkseries(patchname):
1376 def checkseries(patchname):
1379 if patchname in self.series:
1377 if patchname in self.series:
1380 raise util.Abort(_('patch %s is already in the series file')
1378 raise util.Abort(_('patch %s is already in the series file')
1381 % patchname)
1379 % patchname)
1382 def checkfile(patchname):
1380 def checkfile(patchname):
1383 if not force and os.path.exists(self.join(patchname)):
1381 if not force and os.path.exists(self.join(patchname)):
1384 raise util.Abort(_('patch "%s" already exists')
1382 raise util.Abort(_('patch "%s" already exists')
1385 % patchname)
1383 % patchname)
1386
1384
1387 if rev:
1385 if rev:
1388 if files:
1386 if files:
1389 raise util.Abort(_('option "-r" not valid when importing '
1387 raise util.Abort(_('option "-r" not valid when importing '
1390 'files'))
1388 'files'))
1391 rev = cmdutil.revrange(repo, rev)
1389 rev = cmdutil.revrange(repo, rev)
1392 rev.sort(lambda x, y: cmp(y, x))
1390 rev.sort(lambda x, y: cmp(y, x))
1393 if (len(files) > 1 or len(rev) > 1) and patchname:
1391 if (len(files) > 1 or len(rev) > 1) and patchname:
1394 raise util.Abort(_('option "-n" not valid when importing multiple '
1392 raise util.Abort(_('option "-n" not valid when importing multiple '
1395 'patches'))
1393 'patches'))
1396 i = 0
1394 i = 0
1397 added = []
1395 added = []
1398 if rev:
1396 if rev:
1399 # If mq patches are applied, we can only import revisions
1397 # If mq patches are applied, we can only import revisions
1400 # that form a linear path to qbase.
1398 # that form a linear path to qbase.
1401 # Otherwise, they should form a linear path to a head.
1399 # Otherwise, they should form a linear path to a head.
1402 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1400 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1403 if len(heads) > 1:
1401 if len(heads) > 1:
1404 raise util.Abort(_('revision %d is the root of more than one '
1402 raise util.Abort(_('revision %d is the root of more than one '
1405 'branch') % rev[-1])
1403 'branch') % rev[-1])
1406 if self.applied:
1404 if self.applied:
1407 base = revlog.hex(repo.changelog.node(rev[0]))
1405 base = revlog.hex(repo.changelog.node(rev[0]))
1408 if base in [n.rev for n in self.applied]:
1406 if base in [n.rev for n in self.applied]:
1409 raise util.Abort(_('revision %d is already managed')
1407 raise util.Abort(_('revision %d is already managed')
1410 % rev[0])
1408 % rev[0])
1411 if heads != [revlog.bin(self.applied[-1].rev)]:
1409 if heads != [revlog.bin(self.applied[-1].rev)]:
1412 raise util.Abort(_('revision %d is not the parent of '
1410 raise util.Abort(_('revision %d is not the parent of '
1413 'the queue') % rev[0])
1411 'the queue') % rev[0])
1414 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1412 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1415 lastparent = repo.changelog.parentrevs(base)[0]
1413 lastparent = repo.changelog.parentrevs(base)[0]
1416 else:
1414 else:
1417 if heads != [repo.changelog.node(rev[0])]:
1415 if heads != [repo.changelog.node(rev[0])]:
1418 raise util.Abort(_('revision %d has unmanaged children')
1416 raise util.Abort(_('revision %d has unmanaged children')
1419 % rev[0])
1417 % rev[0])
1420 lastparent = None
1418 lastparent = None
1421
1419
1422 if git:
1420 if git:
1423 self.diffopts().git = True
1421 self.diffopts().git = True
1424
1422
1425 for r in rev:
1423 for r in rev:
1426 p1, p2 = repo.changelog.parentrevs(r)
1424 p1, p2 = repo.changelog.parentrevs(r)
1427 n = repo.changelog.node(r)
1425 n = repo.changelog.node(r)
1428 if p2 != revlog.nullrev:
1426 if p2 != revlog.nullrev:
1429 raise util.Abort(_('cannot import merge revision %d') % r)
1427 raise util.Abort(_('cannot import merge revision %d') % r)
1430 if lastparent and lastparent != r:
1428 if lastparent and lastparent != r:
1431 raise util.Abort(_('revision %d is not the parent of %d')
1429 raise util.Abort(_('revision %d is not the parent of %d')
1432 % (r, lastparent))
1430 % (r, lastparent))
1433 lastparent = p1
1431 lastparent = p1
1434
1432
1435 if not patchname:
1433 if not patchname:
1436 patchname = normname('%d.diff' % r)
1434 patchname = normname('%d.diff' % r)
1437 self.check_reserved_name(patchname)
1435 self.check_reserved_name(patchname)
1438 checkseries(patchname)
1436 checkseries(patchname)
1439 checkfile(patchname)
1437 checkfile(patchname)
1440 self.full_series.insert(0, patchname)
1438 self.full_series.insert(0, patchname)
1441
1439
1442 patchf = self.opener(patchname, "w")
1440 patchf = self.opener(patchname, "w")
1443 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1441 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1444 patchf.close()
1442 patchf.close()
1445
1443
1446 se = statusentry(revlog.hex(n), patchname)
1444 se = statusentry(revlog.hex(n), patchname)
1447 self.applied.insert(0, se)
1445 self.applied.insert(0, se)
1448
1446
1449 added.append(patchname)
1447 added.append(patchname)
1450 patchname = None
1448 patchname = None
1451 self.parse_series()
1449 self.parse_series()
1452 self.applied_dirty = 1
1450 self.applied_dirty = 1
1453
1451
1454 for filename in files:
1452 for filename in files:
1455 if existing:
1453 if existing:
1456 if filename == '-':
1454 if filename == '-':
1457 raise util.Abort(_('-e is incompatible with import from -'))
1455 raise util.Abort(_('-e is incompatible with import from -'))
1458 if not patchname:
1456 if not patchname:
1459 patchname = normname(filename)
1457 patchname = normname(filename)
1460 self.check_reserved_name(patchname)
1458 self.check_reserved_name(patchname)
1461 if not os.path.isfile(self.join(patchname)):
1459 if not os.path.isfile(self.join(patchname)):
1462 raise util.Abort(_("patch %s does not exist") % patchname)
1460 raise util.Abort(_("patch %s does not exist") % patchname)
1463 else:
1461 else:
1464 try:
1462 try:
1465 if filename == '-':
1463 if filename == '-':
1466 if not patchname:
1464 if not patchname:
1467 raise util.Abort(_('need --name to import a patch from -'))
1465 raise util.Abort(_('need --name to import a patch from -'))
1468 text = sys.stdin.read()
1466 text = sys.stdin.read()
1469 else:
1467 else:
1470 text = file(filename, 'rb').read()
1468 text = file(filename, 'rb').read()
1471 except IOError:
1469 except IOError:
1472 raise util.Abort(_("unable to read %s") % patchname)
1470 raise util.Abort(_("unable to read %s") % patchname)
1473 if not patchname:
1471 if not patchname:
1474 patchname = normname(os.path.basename(filename))
1472 patchname = normname(os.path.basename(filename))
1475 self.check_reserved_name(patchname)
1473 self.check_reserved_name(patchname)
1476 checkfile(patchname)
1474 checkfile(patchname)
1477 patchf = self.opener(patchname, "w")
1475 patchf = self.opener(patchname, "w")
1478 patchf.write(text)
1476 patchf.write(text)
1479 checkseries(patchname)
1477 checkseries(patchname)
1480 index = self.full_series_end() + i
1478 index = self.full_series_end() + i
1481 self.full_series[index:index] = [patchname]
1479 self.full_series[index:index] = [patchname]
1482 self.parse_series()
1480 self.parse_series()
1483 self.ui.warn("adding %s to series file\n" % patchname)
1481 self.ui.warn("adding %s to series file\n" % patchname)
1484 i += 1
1482 i += 1
1485 added.append(patchname)
1483 added.append(patchname)
1486 patchname = None
1484 patchname = None
1487 self.series_dirty = 1
1485 self.series_dirty = 1
1488 qrepo = self.qrepo()
1486 qrepo = self.qrepo()
1489 if qrepo:
1487 if qrepo:
1490 qrepo.add(added)
1488 qrepo.add(added)
1491
1489
1492 def delete(ui, repo, *patches, **opts):
1490 def delete(ui, repo, *patches, **opts):
1493 """remove patches from queue
1491 """remove patches from queue
1494
1492
1495 The patches must not be applied, unless they are arguments to
1493 The patches must not be applied, unless they are arguments to
1496 the --rev parameter. At least one patch or revision is required.
1494 the --rev parameter. At least one patch or revision is required.
1497
1495
1498 With --rev, mq will stop managing the named revisions (converting
1496 With --rev, mq will stop managing the named revisions (converting
1499 them to regular mercurial changesets). The patches must be applied
1497 them to regular mercurial changesets). The patches must be applied
1500 and at the base of the stack. This option is useful when the patches
1498 and at the base of the stack. This option is useful when the patches
1501 have been applied upstream.
1499 have been applied upstream.
1502
1500
1503 With --keep, the patch files are preserved in the patch directory."""
1501 With --keep, the patch files are preserved in the patch directory."""
1504 q = repo.mq
1502 q = repo.mq
1505 q.delete(repo, patches, opts)
1503 q.delete(repo, patches, opts)
1506 q.save_dirty()
1504 q.save_dirty()
1507 return 0
1505 return 0
1508
1506
1509 def applied(ui, repo, patch=None, **opts):
1507 def applied(ui, repo, patch=None, **opts):
1510 """print the patches already applied"""
1508 """print the patches already applied"""
1511 q = repo.mq
1509 q = repo.mq
1512 if patch:
1510 if patch:
1513 if patch not in q.series:
1511 if patch not in q.series:
1514 raise util.Abort(_("patch %s is not in series file") % patch)
1512 raise util.Abort(_("patch %s is not in series file") % patch)
1515 end = q.series.index(patch) + 1
1513 end = q.series.index(patch) + 1
1516 else:
1514 else:
1517 end = q.series_end(True)
1515 end = q.series_end(True)
1518 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1516 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1519
1517
1520 def unapplied(ui, repo, patch=None, **opts):
1518 def unapplied(ui, repo, patch=None, **opts):
1521 """print the patches not yet applied"""
1519 """print the patches not yet applied"""
1522 q = repo.mq
1520 q = repo.mq
1523 if patch:
1521 if patch:
1524 if patch not in q.series:
1522 if patch not in q.series:
1525 raise util.Abort(_("patch %s is not in series file") % patch)
1523 raise util.Abort(_("patch %s is not in series file") % patch)
1526 start = q.series.index(patch) + 1
1524 start = q.series.index(patch) + 1
1527 else:
1525 else:
1528 start = q.series_end(True)
1526 start = q.series_end(True)
1529 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1527 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1530
1528
1531 def qimport(ui, repo, *filename, **opts):
1529 def qimport(ui, repo, *filename, **opts):
1532 """import a patch
1530 """import a patch
1533
1531
1534 The patch will have the same name as its source file unless you
1532 The patch will have the same name as its source file unless you
1535 give it a new one with --name.
1533 give it a new one with --name.
1536
1534
1537 You can register an existing patch inside the patch directory
1535 You can register an existing patch inside the patch directory
1538 with the --existing flag.
1536 with the --existing flag.
1539
1537
1540 With --force, an existing patch of the same name will be overwritten.
1538 With --force, an existing patch of the same name will be overwritten.
1541
1539
1542 An existing changeset may be placed under mq control with --rev
1540 An existing changeset may be placed under mq control with --rev
1543 (e.g. qimport --rev tip -n patch will place tip under mq control).
1541 (e.g. qimport --rev tip -n patch will place tip under mq control).
1544 With --git, patches imported with --rev will use the git diff
1542 With --git, patches imported with --rev will use the git diff
1545 format.
1543 format.
1546 """
1544 """
1547 q = repo.mq
1545 q = repo.mq
1548 q.qimport(repo, filename, patchname=opts['name'],
1546 q.qimport(repo, filename, patchname=opts['name'],
1549 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1547 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1550 git=opts['git'])
1548 git=opts['git'])
1551 q.save_dirty()
1549 q.save_dirty()
1552 return 0
1550 return 0
1553
1551
1554 def init(ui, repo, **opts):
1552 def init(ui, repo, **opts):
1555 """init a new queue repository
1553 """init a new queue repository
1556
1554
1557 The queue repository is unversioned by default. If -c is
1555 The queue repository is unversioned by default. If -c is
1558 specified, qinit will create a separate nested repository
1556 specified, qinit will create a separate nested repository
1559 for patches (qinit -c may also be run later to convert
1557 for patches (qinit -c may also be run later to convert
1560 an unversioned patch repository into a versioned one).
1558 an unversioned patch repository into a versioned one).
1561 You can use qcommit to commit changes to this queue repository."""
1559 You can use qcommit to commit changes to this queue repository."""
1562 q = repo.mq
1560 q = repo.mq
1563 r = q.init(repo, create=opts['create_repo'])
1561 r = q.init(repo, create=opts['create_repo'])
1564 q.save_dirty()
1562 q.save_dirty()
1565 if r:
1563 if r:
1566 if not os.path.exists(r.wjoin('.hgignore')):
1564 if not os.path.exists(r.wjoin('.hgignore')):
1567 fp = r.wopener('.hgignore', 'w')
1565 fp = r.wopener('.hgignore', 'w')
1568 fp.write('^\\.hg\n')
1566 fp.write('^\\.hg\n')
1569 fp.write('^\\.mq\n')
1567 fp.write('^\\.mq\n')
1570 fp.write('syntax: glob\n')
1568 fp.write('syntax: glob\n')
1571 fp.write('status\n')
1569 fp.write('status\n')
1572 fp.write('guards\n')
1570 fp.write('guards\n')
1573 fp.close()
1571 fp.close()
1574 if not os.path.exists(r.wjoin('series')):
1572 if not os.path.exists(r.wjoin('series')):
1575 r.wopener('series', 'w').close()
1573 r.wopener('series', 'w').close()
1576 r.add(['.hgignore', 'series'])
1574 r.add(['.hgignore', 'series'])
1577 commands.add(ui, r)
1575 commands.add(ui, r)
1578 return 0
1576 return 0
1579
1577
1580 def clone(ui, source, dest=None, **opts):
1578 def clone(ui, source, dest=None, **opts):
1581 '''clone main and patch repository at same time
1579 '''clone main and patch repository at same time
1582
1580
1583 If source is local, destination will have no patches applied. If
1581 If source is local, destination will have no patches applied. If
1584 source is remote, this command can not check if patches are
1582 source is remote, this command can not check if patches are
1585 applied in source, so cannot guarantee that patches are not
1583 applied in source, so cannot guarantee that patches are not
1586 applied in destination. If you clone remote repository, be sure
1584 applied in destination. If you clone remote repository, be sure
1587 before that it has no patches applied.
1585 before that it has no patches applied.
1588
1586
1589 Source patch repository is looked for in <src>/.hg/patches by
1587 Source patch repository is looked for in <src>/.hg/patches by
1590 default. Use -p <url> to change.
1588 default. Use -p <url> to change.
1591
1589
1592 The patch directory must be a nested mercurial repository, as
1590 The patch directory must be a nested mercurial repository, as
1593 would be created by qinit -c.
1591 would be created by qinit -c.
1594 '''
1592 '''
1595 def patchdir(repo):
1593 def patchdir(repo):
1596 url = repo.url()
1594 url = repo.url()
1597 if url.endswith('/'):
1595 if url.endswith('/'):
1598 url = url[:-1]
1596 url = url[:-1]
1599 return url + '/.hg/patches'
1597 return url + '/.hg/patches'
1600 cmdutil.setremoteconfig(ui, opts)
1598 cmdutil.setremoteconfig(ui, opts)
1601 if dest is None:
1599 if dest is None:
1602 dest = hg.defaultdest(source)
1600 dest = hg.defaultdest(source)
1603 sr = hg.repository(ui, ui.expandpath(source))
1601 sr = hg.repository(ui, ui.expandpath(source))
1604 patchespath = opts['patches'] or patchdir(sr)
1602 patchespath = opts['patches'] or patchdir(sr)
1605 try:
1603 try:
1606 pr = hg.repository(ui, patchespath)
1604 pr = hg.repository(ui, patchespath)
1607 except RepoError:
1605 except RepoError:
1608 raise util.Abort(_('versioned patch repository not found'
1606 raise util.Abort(_('versioned patch repository not found'
1609 ' (see qinit -c)'))
1607 ' (see qinit -c)'))
1610 qbase, destrev = None, None
1608 qbase, destrev = None, None
1611 if sr.local():
1609 if sr.local():
1612 if sr.mq.applied:
1610 if sr.mq.applied:
1613 qbase = revlog.bin(sr.mq.applied[0].rev)
1611 qbase = revlog.bin(sr.mq.applied[0].rev)
1614 if not hg.islocal(dest):
1612 if not hg.islocal(dest):
1615 heads = dict.fromkeys(sr.heads())
1613 heads = dict.fromkeys(sr.heads())
1616 for h in sr.heads(qbase):
1614 for h in sr.heads(qbase):
1617 del heads[h]
1615 del heads[h]
1618 destrev = heads.keys()
1616 destrev = heads.keys()
1619 destrev.append(sr.changelog.parents(qbase)[0])
1617 destrev.append(sr.changelog.parents(qbase)[0])
1620 elif sr.capable('lookup'):
1618 elif sr.capable('lookup'):
1621 try:
1619 try:
1622 qbase = sr.lookup('qbase')
1620 qbase = sr.lookup('qbase')
1623 except RepoError:
1621 except RepoError:
1624 pass
1622 pass
1625 ui.note(_('cloning main repo\n'))
1623 ui.note(_('cloning main repo\n'))
1626 sr, dr = hg.clone(ui, sr.url(), dest,
1624 sr, dr = hg.clone(ui, sr.url(), dest,
1627 pull=opts['pull'],
1625 pull=opts['pull'],
1628 rev=destrev,
1626 rev=destrev,
1629 update=False,
1627 update=False,
1630 stream=opts['uncompressed'])
1628 stream=opts['uncompressed'])
1631 ui.note(_('cloning patch repo\n'))
1629 ui.note(_('cloning patch repo\n'))
1632 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1630 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1633 pull=opts['pull'], update=not opts['noupdate'],
1631 pull=opts['pull'], update=not opts['noupdate'],
1634 stream=opts['uncompressed'])
1632 stream=opts['uncompressed'])
1635 if dr.local():
1633 if dr.local():
1636 if qbase:
1634 if qbase:
1637 ui.note(_('stripping applied patches from destination repo\n'))
1635 ui.note(_('stripping applied patches from destination repo\n'))
1638 dr.mq.strip(dr, qbase, update=False, backup=None)
1636 dr.mq.strip(dr, qbase, update=False, backup=None)
1639 if not opts['noupdate']:
1637 if not opts['noupdate']:
1640 ui.note(_('updating destination repo\n'))
1638 ui.note(_('updating destination repo\n'))
1641 hg.update(dr, dr.changelog.tip())
1639 hg.update(dr, dr.changelog.tip())
1642
1640
1643 def commit(ui, repo, *pats, **opts):
1641 def commit(ui, repo, *pats, **opts):
1644 """commit changes in the queue repository"""
1642 """commit changes in the queue repository"""
1645 q = repo.mq
1643 q = repo.mq
1646 r = q.qrepo()
1644 r = q.qrepo()
1647 if not r: raise util.Abort('no queue repository')
1645 if not r: raise util.Abort('no queue repository')
1648 commands.commit(r.ui, r, *pats, **opts)
1646 commands.commit(r.ui, r, *pats, **opts)
1649
1647
1650 def series(ui, repo, **opts):
1648 def series(ui, repo, **opts):
1651 """print the entire series file"""
1649 """print the entire series file"""
1652 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1650 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1653 return 0
1651 return 0
1654
1652
1655 def top(ui, repo, **opts):
1653 def top(ui, repo, **opts):
1656 """print the name of the current patch"""
1654 """print the name of the current patch"""
1657 q = repo.mq
1655 q = repo.mq
1658 t = q.applied and q.series_end(True) or 0
1656 t = q.applied and q.series_end(True) or 0
1659 if t:
1657 if t:
1660 return q.qseries(repo, start=t-1, length=1, status='A',
1658 return q.qseries(repo, start=t-1, length=1, status='A',
1661 summary=opts.get('summary'))
1659 summary=opts.get('summary'))
1662 else:
1660 else:
1663 ui.write("No patches applied\n")
1661 ui.write("No patches applied\n")
1664 return 1
1662 return 1
1665
1663
1666 def next(ui, repo, **opts):
1664 def next(ui, repo, **opts):
1667 """print the name of the next patch"""
1665 """print the name of the next patch"""
1668 q = repo.mq
1666 q = repo.mq
1669 end = q.series_end()
1667 end = q.series_end()
1670 if end == len(q.series):
1668 if end == len(q.series):
1671 ui.write("All patches applied\n")
1669 ui.write("All patches applied\n")
1672 return 1
1670 return 1
1673 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1671 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1674
1672
1675 def prev(ui, repo, **opts):
1673 def prev(ui, repo, **opts):
1676 """print the name of the previous patch"""
1674 """print the name of the previous patch"""
1677 q = repo.mq
1675 q = repo.mq
1678 l = len(q.applied)
1676 l = len(q.applied)
1679 if l == 1:
1677 if l == 1:
1680 ui.write("Only one patch applied\n")
1678 ui.write("Only one patch applied\n")
1681 return 1
1679 return 1
1682 if not l:
1680 if not l:
1683 ui.write("No patches applied\n")
1681 ui.write("No patches applied\n")
1684 return 1
1682 return 1
1685 return q.qseries(repo, start=l-2, length=1, status='A',
1683 return q.qseries(repo, start=l-2, length=1, status='A',
1686 summary=opts.get('summary'))
1684 summary=opts.get('summary'))
1687
1685
1688 def setupheaderopts(ui, opts):
1686 def setupheaderopts(ui, opts):
1689 def do(opt,val):
1687 def do(opt,val):
1690 if not opts[opt] and opts['current' + opt]:
1688 if not opts[opt] and opts['current' + opt]:
1691 opts[opt] = val
1689 opts[opt] = val
1692 do('user', ui.username())
1690 do('user', ui.username())
1693 do('date', "%d %d" % util.makedate())
1691 do('date', "%d %d" % util.makedate())
1694
1692
1695 def new(ui, repo, patch, *args, **opts):
1693 def new(ui, repo, patch, *args, **opts):
1696 """create a new patch
1694 """create a new patch
1697
1695
1698 qnew creates a new patch on top of the currently-applied patch
1696 qnew creates a new patch on top of the currently-applied patch
1699 (if any). It will refuse to run if there are any outstanding
1697 (if any). It will refuse to run if there are any outstanding
1700 changes unless -f is specified, in which case the patch will
1698 changes unless -f is specified, in which case the patch will
1701 be initialised with them. You may also use -I, -X, and/or a list of
1699 be initialised with them. You may also use -I, -X, and/or a list of
1702 files after the patch name to add only changes to matching files
1700 files after the patch name to add only changes to matching files
1703 to the new patch, leaving the rest as uncommitted modifications.
1701 to the new patch, leaving the rest as uncommitted modifications.
1704
1702
1705 -e, -m or -l set the patch header as well as the commit message.
1703 -e, -m or -l set the patch header as well as the commit message.
1706 If none is specified, the patch header is empty and the
1704 If none is specified, the patch header is empty and the
1707 commit message is '[mq]: PATCH'"""
1705 commit message is '[mq]: PATCH'"""
1708 q = repo.mq
1706 q = repo.mq
1709 message = cmdutil.logmessage(opts)
1707 message = cmdutil.logmessage(opts)
1710 if opts['edit']:
1708 if opts['edit']:
1711 message = ui.edit(message, ui.username())
1709 message = ui.edit(message, ui.username())
1712 opts['msg'] = message
1710 opts['msg'] = message
1713 setupheaderopts(ui, opts)
1711 setupheaderopts(ui, opts)
1714 q.new(repo, patch, *args, **opts)
1712 q.new(repo, patch, *args, **opts)
1715 q.save_dirty()
1713 q.save_dirty()
1716 return 0
1714 return 0
1717
1715
1718 def refresh(ui, repo, *pats, **opts):
1716 def refresh(ui, repo, *pats, **opts):
1719 """update the current patch
1717 """update the current patch
1720
1718
1721 If any file patterns are provided, the refreshed patch will contain only
1719 If any file patterns are provided, the refreshed patch will contain only
1722 the modifications that match those patterns; the remaining modifications
1720 the modifications that match those patterns; the remaining modifications
1723 will remain in the working directory.
1721 will remain in the working directory.
1724
1722
1725 hg add/remove/copy/rename work as usual, though you might want to use
1723 hg add/remove/copy/rename work as usual, though you might want to use
1726 git-style patches (--git or [diff] git=1) to track copies and renames.
1724 git-style patches (--git or [diff] git=1) to track copies and renames.
1727 """
1725 """
1728 q = repo.mq
1726 q = repo.mq
1729 message = cmdutil.logmessage(opts)
1727 message = cmdutil.logmessage(opts)
1730 if opts['edit']:
1728 if opts['edit']:
1731 if not q.applied:
1729 if not q.applied:
1732 ui.write(_("No patches applied\n"))
1730 ui.write(_("No patches applied\n"))
1733 return 1
1731 return 1
1734 if message:
1732 if message:
1735 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1733 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1736 patch = q.applied[-1].name
1734 patch = q.applied[-1].name
1737 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1735 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1738 message = ui.edit('\n'.join(message), user or ui.username())
1736 message = ui.edit('\n'.join(message), user or ui.username())
1739 setupheaderopts(ui, opts)
1737 setupheaderopts(ui, opts)
1740 ret = q.refresh(repo, pats, msg=message, **opts)
1738 ret = q.refresh(repo, pats, msg=message, **opts)
1741 q.save_dirty()
1739 q.save_dirty()
1742 return ret
1740 return ret
1743
1741
1744 def diff(ui, repo, *pats, **opts):
1742 def diff(ui, repo, *pats, **opts):
1745 """diff of the current patch"""
1743 """diff of the current patch"""
1746 repo.mq.diff(repo, pats, opts)
1744 repo.mq.diff(repo, pats, opts)
1747 return 0
1745 return 0
1748
1746
1749 def fold(ui, repo, *files, **opts):
1747 def fold(ui, repo, *files, **opts):
1750 """fold the named patches into the current patch
1748 """fold the named patches into the current patch
1751
1749
1752 Patches must not yet be applied. Each patch will be successively
1750 Patches must not yet be applied. Each patch will be successively
1753 applied to the current patch in the order given. If all the
1751 applied to the current patch in the order given. If all the
1754 patches apply successfully, the current patch will be refreshed
1752 patches apply successfully, the current patch will be refreshed
1755 with the new cumulative patch, and the folded patches will
1753 with the new cumulative patch, and the folded patches will
1756 be deleted. With -k/--keep, the folded patch files will not
1754 be deleted. With -k/--keep, the folded patch files will not
1757 be removed afterwards.
1755 be removed afterwards.
1758
1756
1759 The header for each folded patch will be concatenated with
1757 The header for each folded patch will be concatenated with
1760 the current patch header, separated by a line of '* * *'."""
1758 the current patch header, separated by a line of '* * *'."""
1761
1759
1762 q = repo.mq
1760 q = repo.mq
1763
1761
1764 if not files:
1762 if not files:
1765 raise util.Abort(_('qfold requires at least one patch name'))
1763 raise util.Abort(_('qfold requires at least one patch name'))
1766 if not q.check_toppatch(repo):
1764 if not q.check_toppatch(repo):
1767 raise util.Abort(_('No patches applied'))
1765 raise util.Abort(_('No patches applied'))
1768
1766
1769 message = cmdutil.logmessage(opts)
1767 message = cmdutil.logmessage(opts)
1770 if opts['edit']:
1768 if opts['edit']:
1771 if message:
1769 if message:
1772 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1770 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1773
1771
1774 parent = q.lookup('qtip')
1772 parent = q.lookup('qtip')
1775 patches = []
1773 patches = []
1776 messages = []
1774 messages = []
1777 for f in files:
1775 for f in files:
1778 p = q.lookup(f)
1776 p = q.lookup(f)
1779 if p in patches or p == parent:
1777 if p in patches or p == parent:
1780 ui.warn(_('Skipping already folded patch %s') % p)
1778 ui.warn(_('Skipping already folded patch %s') % p)
1781 if q.isapplied(p):
1779 if q.isapplied(p):
1782 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1780 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1783 patches.append(p)
1781 patches.append(p)
1784
1782
1785 for p in patches:
1783 for p in patches:
1786 if not message:
1784 if not message:
1787 messages.append(q.readheaders(p)[0])
1785 messages.append(q.readheaders(p)[0])
1788 pf = q.join(p)
1786 pf = q.join(p)
1789 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1787 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1790 if not patchsuccess:
1788 if not patchsuccess:
1791 raise util.Abort(_('Error folding patch %s') % p)
1789 raise util.Abort(_('Error folding patch %s') % p)
1792 patch.updatedir(ui, repo, files)
1790 patch.updatedir(ui, repo, files)
1793
1791
1794 if not message:
1792 if not message:
1795 message, comments, user = q.readheaders(parent)[0:3]
1793 message, comments, user = q.readheaders(parent)[0:3]
1796 for msg in messages:
1794 for msg in messages:
1797 message.append('* * *')
1795 message.append('* * *')
1798 message.extend(msg)
1796 message.extend(msg)
1799 message = '\n'.join(message)
1797 message = '\n'.join(message)
1800
1798
1801 if opts['edit']:
1799 if opts['edit']:
1802 message = ui.edit(message, user or ui.username())
1800 message = ui.edit(message, user or ui.username())
1803
1801
1804 q.refresh(repo, msg=message)
1802 q.refresh(repo, msg=message)
1805 q.delete(repo, patches, opts)
1803 q.delete(repo, patches, opts)
1806 q.save_dirty()
1804 q.save_dirty()
1807
1805
1808 def goto(ui, repo, patch, **opts):
1806 def goto(ui, repo, patch, **opts):
1809 '''push or pop patches until named patch is at top of stack'''
1807 '''push or pop patches until named patch is at top of stack'''
1810 q = repo.mq
1808 q = repo.mq
1811 patch = q.lookup(patch)
1809 patch = q.lookup(patch)
1812 if q.isapplied(patch):
1810 if q.isapplied(patch):
1813 ret = q.pop(repo, patch, force=opts['force'])
1811 ret = q.pop(repo, patch, force=opts['force'])
1814 else:
1812 else:
1815 ret = q.push(repo, patch, force=opts['force'])
1813 ret = q.push(repo, patch, force=opts['force'])
1816 q.save_dirty()
1814 q.save_dirty()
1817 return ret
1815 return ret
1818
1816
1819 def guard(ui, repo, *args, **opts):
1817 def guard(ui, repo, *args, **opts):
1820 '''set or print guards for a patch
1818 '''set or print guards for a patch
1821
1819
1822 Guards control whether a patch can be pushed. A patch with no
1820 Guards control whether a patch can be pushed. A patch with no
1823 guards is always pushed. A patch with a positive guard ("+foo") is
1821 guards is always pushed. A patch with a positive guard ("+foo") is
1824 pushed only if the qselect command has activated it. A patch with
1822 pushed only if the qselect command has activated it. A patch with
1825 a negative guard ("-foo") is never pushed if the qselect command
1823 a negative guard ("-foo") is never pushed if the qselect command
1826 has activated it.
1824 has activated it.
1827
1825
1828 With no arguments, print the currently active guards.
1826 With no arguments, print the currently active guards.
1829 With arguments, set guards for the named patch.
1827 With arguments, set guards for the named patch.
1830
1828
1831 To set a negative guard "-foo" on topmost patch ("--" is needed so
1829 To set a negative guard "-foo" on topmost patch ("--" is needed so
1832 hg will not interpret "-foo" as an option):
1830 hg will not interpret "-foo" as an option):
1833 hg qguard -- -foo
1831 hg qguard -- -foo
1834
1832
1835 To set guards on another patch:
1833 To set guards on another patch:
1836 hg qguard other.patch +2.6.17 -stable
1834 hg qguard other.patch +2.6.17 -stable
1837 '''
1835 '''
1838 def status(idx):
1836 def status(idx):
1839 guards = q.series_guards[idx] or ['unguarded']
1837 guards = q.series_guards[idx] or ['unguarded']
1840 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1838 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1841 q = repo.mq
1839 q = repo.mq
1842 patch = None
1840 patch = None
1843 args = list(args)
1841 args = list(args)
1844 if opts['list']:
1842 if opts['list']:
1845 if args or opts['none']:
1843 if args or opts['none']:
1846 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1844 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1847 for i in xrange(len(q.series)):
1845 for i in xrange(len(q.series)):
1848 status(i)
1846 status(i)
1849 return
1847 return
1850 if not args or args[0][0:1] in '-+':
1848 if not args or args[0][0:1] in '-+':
1851 if not q.applied:
1849 if not q.applied:
1852 raise util.Abort(_('no patches applied'))
1850 raise util.Abort(_('no patches applied'))
1853 patch = q.applied[-1].name
1851 patch = q.applied[-1].name
1854 if patch is None and args[0][0:1] not in '-+':
1852 if patch is None and args[0][0:1] not in '-+':
1855 patch = args.pop(0)
1853 patch = args.pop(0)
1856 if patch is None:
1854 if patch is None:
1857 raise util.Abort(_('no patch to work with'))
1855 raise util.Abort(_('no patch to work with'))
1858 if args or opts['none']:
1856 if args or opts['none']:
1859 idx = q.find_series(patch)
1857 idx = q.find_series(patch)
1860 if idx is None:
1858 if idx is None:
1861 raise util.Abort(_('no patch named %s') % patch)
1859 raise util.Abort(_('no patch named %s') % patch)
1862 q.set_guards(idx, args)
1860 q.set_guards(idx, args)
1863 q.save_dirty()
1861 q.save_dirty()
1864 else:
1862 else:
1865 status(q.series.index(q.lookup(patch)))
1863 status(q.series.index(q.lookup(patch)))
1866
1864
1867 def header(ui, repo, patch=None):
1865 def header(ui, repo, patch=None):
1868 """Print the header of the topmost or specified patch"""
1866 """Print the header of the topmost or specified patch"""
1869 q = repo.mq
1867 q = repo.mq
1870
1868
1871 if patch:
1869 if patch:
1872 patch = q.lookup(patch)
1870 patch = q.lookup(patch)
1873 else:
1871 else:
1874 if not q.applied:
1872 if not q.applied:
1875 ui.write('No patches applied\n')
1873 ui.write('No patches applied\n')
1876 return 1
1874 return 1
1877 patch = q.lookup('qtip')
1875 patch = q.lookup('qtip')
1878 message = repo.mq.readheaders(patch)[0]
1876 message = repo.mq.readheaders(patch)[0]
1879
1877
1880 ui.write('\n'.join(message) + '\n')
1878 ui.write('\n'.join(message) + '\n')
1881
1879
1882 def lastsavename(path):
1880 def lastsavename(path):
1883 (directory, base) = os.path.split(path)
1881 (directory, base) = os.path.split(path)
1884 names = os.listdir(directory)
1882 names = os.listdir(directory)
1885 namere = re.compile("%s.([0-9]+)" % base)
1883 namere = re.compile("%s.([0-9]+)" % base)
1886 maxindex = None
1884 maxindex = None
1887 maxname = None
1885 maxname = None
1888 for f in names:
1886 for f in names:
1889 m = namere.match(f)
1887 m = namere.match(f)
1890 if m:
1888 if m:
1891 index = int(m.group(1))
1889 index = int(m.group(1))
1892 if maxindex == None or index > maxindex:
1890 if maxindex == None or index > maxindex:
1893 maxindex = index
1891 maxindex = index
1894 maxname = f
1892 maxname = f
1895 if maxname:
1893 if maxname:
1896 return (os.path.join(directory, maxname), maxindex)
1894 return (os.path.join(directory, maxname), maxindex)
1897 return (None, None)
1895 return (None, None)
1898
1896
1899 def savename(path):
1897 def savename(path):
1900 (last, index) = lastsavename(path)
1898 (last, index) = lastsavename(path)
1901 if last is None:
1899 if last is None:
1902 index = 0
1900 index = 0
1903 newpath = path + ".%d" % (index + 1)
1901 newpath = path + ".%d" % (index + 1)
1904 return newpath
1902 return newpath
1905
1903
1906 def push(ui, repo, patch=None, **opts):
1904 def push(ui, repo, patch=None, **opts):
1907 """push the next patch onto the stack
1905 """push the next patch onto the stack
1908
1906
1909 When --force is applied, all local changes in patched files will be lost.
1907 When --force is applied, all local changes in patched files will be lost.
1910 """
1908 """
1911 q = repo.mq
1909 q = repo.mq
1912 mergeq = None
1910 mergeq = None
1913
1911
1914 if opts['all']:
1912 if opts['all']:
1915 if not q.series:
1913 if not q.series:
1916 ui.warn(_('no patches in series\n'))
1914 ui.warn(_('no patches in series\n'))
1917 return 0
1915 return 0
1918 patch = q.series[-1]
1916 patch = q.series[-1]
1919 if opts['merge']:
1917 if opts['merge']:
1920 if opts['name']:
1918 if opts['name']:
1921 newpath = opts['name']
1919 newpath = opts['name']
1922 else:
1920 else:
1923 newpath, i = lastsavename(q.path)
1921 newpath, i = lastsavename(q.path)
1924 if not newpath:
1922 if not newpath:
1925 ui.warn("no saved queues found, please use -n\n")
1923 ui.warn("no saved queues found, please use -n\n")
1926 return 1
1924 return 1
1927 mergeq = queue(ui, repo.join(""), newpath)
1925 mergeq = queue(ui, repo.join(""), newpath)
1928 ui.warn("merging with queue at: %s\n" % mergeq.path)
1926 ui.warn("merging with queue at: %s\n" % mergeq.path)
1929 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1927 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1930 mergeq=mergeq)
1928 mergeq=mergeq)
1931 return ret
1929 return ret
1932
1930
1933 def pop(ui, repo, patch=None, **opts):
1931 def pop(ui, repo, patch=None, **opts):
1934 """pop the current patch off the stack"""
1932 """pop the current patch off the stack"""
1935 localupdate = True
1933 localupdate = True
1936 if opts['name']:
1934 if opts['name']:
1937 q = queue(ui, repo.join(""), repo.join(opts['name']))
1935 q = queue(ui, repo.join(""), repo.join(opts['name']))
1938 ui.warn('using patch queue: %s\n' % q.path)
1936 ui.warn('using patch queue: %s\n' % q.path)
1939 localupdate = False
1937 localupdate = False
1940 else:
1938 else:
1941 q = repo.mq
1939 q = repo.mq
1942 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1940 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1943 all=opts['all'])
1941 all=opts['all'])
1944 q.save_dirty()
1942 q.save_dirty()
1945 return ret
1943 return ret
1946
1944
1947 def rename(ui, repo, patch, name=None, **opts):
1945 def rename(ui, repo, patch, name=None, **opts):
1948 """rename a patch
1946 """rename a patch
1949
1947
1950 With one argument, renames the current patch to PATCH1.
1948 With one argument, renames the current patch to PATCH1.
1951 With two arguments, renames PATCH1 to PATCH2."""
1949 With two arguments, renames PATCH1 to PATCH2."""
1952
1950
1953 q = repo.mq
1951 q = repo.mq
1954
1952
1955 if not name:
1953 if not name:
1956 name = patch
1954 name = patch
1957 patch = None
1955 patch = None
1958
1956
1959 if patch:
1957 if patch:
1960 patch = q.lookup(patch)
1958 patch = q.lookup(patch)
1961 else:
1959 else:
1962 if not q.applied:
1960 if not q.applied:
1963 ui.write(_('No patches applied\n'))
1961 ui.write(_('No patches applied\n'))
1964 return
1962 return
1965 patch = q.lookup('qtip')
1963 patch = q.lookup('qtip')
1966 absdest = q.join(name)
1964 absdest = q.join(name)
1967 if os.path.isdir(absdest):
1965 if os.path.isdir(absdest):
1968 name = normname(os.path.join(name, os.path.basename(patch)))
1966 name = normname(os.path.join(name, os.path.basename(patch)))
1969 absdest = q.join(name)
1967 absdest = q.join(name)
1970 if os.path.exists(absdest):
1968 if os.path.exists(absdest):
1971 raise util.Abort(_('%s already exists') % absdest)
1969 raise util.Abort(_('%s already exists') % absdest)
1972
1970
1973 if name in q.series:
1971 if name in q.series:
1974 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1972 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1975
1973
1976 if ui.verbose:
1974 if ui.verbose:
1977 ui.write('Renaming %s to %s\n' % (patch, name))
1975 ui.write('Renaming %s to %s\n' % (patch, name))
1978 i = q.find_series(patch)
1976 i = q.find_series(patch)
1979 guards = q.guard_re.findall(q.full_series[i])
1977 guards = q.guard_re.findall(q.full_series[i])
1980 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1978 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1981 q.parse_series()
1979 q.parse_series()
1982 q.series_dirty = 1
1980 q.series_dirty = 1
1983
1981
1984 info = q.isapplied(patch)
1982 info = q.isapplied(patch)
1985 if info:
1983 if info:
1986 q.applied[info[0]] = statusentry(info[1], name)
1984 q.applied[info[0]] = statusentry(info[1], name)
1987 q.applied_dirty = 1
1985 q.applied_dirty = 1
1988
1986
1989 util.rename(q.join(patch), absdest)
1987 util.rename(q.join(patch), absdest)
1990 r = q.qrepo()
1988 r = q.qrepo()
1991 if r:
1989 if r:
1992 wlock = r.wlock()
1990 wlock = r.wlock()
1993 try:
1991 try:
1994 if r.dirstate[name] == 'r':
1992 if r.dirstate[name] == 'r':
1995 r.undelete([name])
1993 r.undelete([name])
1996 r.copy(patch, name)
1994 r.copy(patch, name)
1997 r.remove([patch], False)
1995 r.remove([patch], False)
1998 finally:
1996 finally:
1999 del wlock
1997 del wlock
2000
1998
2001 q.save_dirty()
1999 q.save_dirty()
2002
2000
2003 def restore(ui, repo, rev, **opts):
2001 def restore(ui, repo, rev, **opts):
2004 """restore the queue state saved by a rev"""
2002 """restore the queue state saved by a rev"""
2005 rev = repo.lookup(rev)
2003 rev = repo.lookup(rev)
2006 q = repo.mq
2004 q = repo.mq
2007 q.restore(repo, rev, delete=opts['delete'],
2005 q.restore(repo, rev, delete=opts['delete'],
2008 qupdate=opts['update'])
2006 qupdate=opts['update'])
2009 q.save_dirty()
2007 q.save_dirty()
2010 return 0
2008 return 0
2011
2009
2012 def save(ui, repo, **opts):
2010 def save(ui, repo, **opts):
2013 """save current queue state"""
2011 """save current queue state"""
2014 q = repo.mq
2012 q = repo.mq
2015 message = cmdutil.logmessage(opts)
2013 message = cmdutil.logmessage(opts)
2016 ret = q.save(repo, msg=message)
2014 ret = q.save(repo, msg=message)
2017 if ret:
2015 if ret:
2018 return ret
2016 return ret
2019 q.save_dirty()
2017 q.save_dirty()
2020 if opts['copy']:
2018 if opts['copy']:
2021 path = q.path
2019 path = q.path
2022 if opts['name']:
2020 if opts['name']:
2023 newpath = os.path.join(q.basepath, opts['name'])
2021 newpath = os.path.join(q.basepath, opts['name'])
2024 if os.path.exists(newpath):
2022 if os.path.exists(newpath):
2025 if not os.path.isdir(newpath):
2023 if not os.path.isdir(newpath):
2026 raise util.Abort(_('destination %s exists and is not '
2024 raise util.Abort(_('destination %s exists and is not '
2027 'a directory') % newpath)
2025 'a directory') % newpath)
2028 if not opts['force']:
2026 if not opts['force']:
2029 raise util.Abort(_('destination %s exists, '
2027 raise util.Abort(_('destination %s exists, '
2030 'use -f to force') % newpath)
2028 'use -f to force') % newpath)
2031 else:
2029 else:
2032 newpath = savename(path)
2030 newpath = savename(path)
2033 ui.warn("copy %s to %s\n" % (path, newpath))
2031 ui.warn("copy %s to %s\n" % (path, newpath))
2034 util.copyfiles(path, newpath)
2032 util.copyfiles(path, newpath)
2035 if opts['empty']:
2033 if opts['empty']:
2036 try:
2034 try:
2037 os.unlink(q.join(q.status_path))
2035 os.unlink(q.join(q.status_path))
2038 except:
2036 except:
2039 pass
2037 pass
2040 return 0
2038 return 0
2041
2039
2042 def strip(ui, repo, rev, **opts):
2040 def strip(ui, repo, rev, **opts):
2043 """strip a revision and all later revs on the same branch"""
2041 """strip a revision and all later revs on the same branch"""
2044 rev = repo.lookup(rev)
2042 rev = repo.lookup(rev)
2045 backup = 'all'
2043 backup = 'all'
2046 if opts['backup']:
2044 if opts['backup']:
2047 backup = 'strip'
2045 backup = 'strip'
2048 elif opts['nobackup']:
2046 elif opts['nobackup']:
2049 backup = 'none'
2047 backup = 'none'
2050 update = repo.dirstate.parents()[0] != revlog.nullid
2048 update = repo.dirstate.parents()[0] != revlog.nullid
2051 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2049 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2052 return 0
2050 return 0
2053
2051
2054 def select(ui, repo, *args, **opts):
2052 def select(ui, repo, *args, **opts):
2055 '''set or print guarded patches to push
2053 '''set or print guarded patches to push
2056
2054
2057 Use the qguard command to set or print guards on patch, then use
2055 Use the qguard command to set or print guards on patch, then use
2058 qselect to tell mq which guards to use. A patch will be pushed if it
2056 qselect to tell mq which guards to use. A patch will be pushed if it
2059 has no guards or any positive guards match the currently selected guard,
2057 has no guards or any positive guards match the currently selected guard,
2060 but will not be pushed if any negative guards match the current guard.
2058 but will not be pushed if any negative guards match the current guard.
2061 For example:
2059 For example:
2062
2060
2063 qguard foo.patch -stable (negative guard)
2061 qguard foo.patch -stable (negative guard)
2064 qguard bar.patch +stable (positive guard)
2062 qguard bar.patch +stable (positive guard)
2065 qselect stable
2063 qselect stable
2066
2064
2067 This activates the "stable" guard. mq will skip foo.patch (because
2065 This activates the "stable" guard. mq will skip foo.patch (because
2068 it has a negative match) but push bar.patch (because it
2066 it has a negative match) but push bar.patch (because it
2069 has a positive match).
2067 has a positive match).
2070
2068
2071 With no arguments, prints the currently active guards.
2069 With no arguments, prints the currently active guards.
2072 With one argument, sets the active guard.
2070 With one argument, sets the active guard.
2073
2071
2074 Use -n/--none to deactivate guards (no other arguments needed).
2072 Use -n/--none to deactivate guards (no other arguments needed).
2075 When no guards are active, patches with positive guards are skipped
2073 When no guards are active, patches with positive guards are skipped
2076 and patches with negative guards are pushed.
2074 and patches with negative guards are pushed.
2077
2075
2078 qselect can change the guards on applied patches. It does not pop
2076 qselect can change the guards on applied patches. It does not pop
2079 guarded patches by default. Use --pop to pop back to the last applied
2077 guarded patches by default. Use --pop to pop back to the last applied
2080 patch that is not guarded. Use --reapply (which implies --pop) to push
2078 patch that is not guarded. Use --reapply (which implies --pop) to push
2081 back to the current patch afterwards, but skip guarded patches.
2079 back to the current patch afterwards, but skip guarded patches.
2082
2080
2083 Use -s/--series to print a list of all guards in the series file (no
2081 Use -s/--series to print a list of all guards in the series file (no
2084 other arguments needed). Use -v for more information.'''
2082 other arguments needed). Use -v for more information.'''
2085
2083
2086 q = repo.mq
2084 q = repo.mq
2087 guards = q.active()
2085 guards = q.active()
2088 if args or opts['none']:
2086 if args or opts['none']:
2089 old_unapplied = q.unapplied(repo)
2087 old_unapplied = q.unapplied(repo)
2090 old_guarded = [i for i in xrange(len(q.applied)) if
2088 old_guarded = [i for i in xrange(len(q.applied)) if
2091 not q.pushable(i)[0]]
2089 not q.pushable(i)[0]]
2092 q.set_active(args)
2090 q.set_active(args)
2093 q.save_dirty()
2091 q.save_dirty()
2094 if not args:
2092 if not args:
2095 ui.status(_('guards deactivated\n'))
2093 ui.status(_('guards deactivated\n'))
2096 if not opts['pop'] and not opts['reapply']:
2094 if not opts['pop'] and not opts['reapply']:
2097 unapplied = q.unapplied(repo)
2095 unapplied = q.unapplied(repo)
2098 guarded = [i for i in xrange(len(q.applied))
2096 guarded = [i for i in xrange(len(q.applied))
2099 if not q.pushable(i)[0]]
2097 if not q.pushable(i)[0]]
2100 if len(unapplied) != len(old_unapplied):
2098 if len(unapplied) != len(old_unapplied):
2101 ui.status(_('number of unguarded, unapplied patches has '
2099 ui.status(_('number of unguarded, unapplied patches has '
2102 'changed from %d to %d\n') %
2100 'changed from %d to %d\n') %
2103 (len(old_unapplied), len(unapplied)))
2101 (len(old_unapplied), len(unapplied)))
2104 if len(guarded) != len(old_guarded):
2102 if len(guarded) != len(old_guarded):
2105 ui.status(_('number of guarded, applied patches has changed '
2103 ui.status(_('number of guarded, applied patches has changed '
2106 'from %d to %d\n') %
2104 'from %d to %d\n') %
2107 (len(old_guarded), len(guarded)))
2105 (len(old_guarded), len(guarded)))
2108 elif opts['series']:
2106 elif opts['series']:
2109 guards = {}
2107 guards = {}
2110 noguards = 0
2108 noguards = 0
2111 for gs in q.series_guards:
2109 for gs in q.series_guards:
2112 if not gs:
2110 if not gs:
2113 noguards += 1
2111 noguards += 1
2114 for g in gs:
2112 for g in gs:
2115 guards.setdefault(g, 0)
2113 guards.setdefault(g, 0)
2116 guards[g] += 1
2114 guards[g] += 1
2117 if ui.verbose:
2115 if ui.verbose:
2118 guards['NONE'] = noguards
2116 guards['NONE'] = noguards
2119 guards = guards.items()
2117 guards = guards.items()
2120 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2118 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2121 if guards:
2119 if guards:
2122 ui.note(_('guards in series file:\n'))
2120 ui.note(_('guards in series file:\n'))
2123 for guard, count in guards:
2121 for guard, count in guards:
2124 ui.note('%2d ' % count)
2122 ui.note('%2d ' % count)
2125 ui.write(guard, '\n')
2123 ui.write(guard, '\n')
2126 else:
2124 else:
2127 ui.note(_('no guards in series file\n'))
2125 ui.note(_('no guards in series file\n'))
2128 else:
2126 else:
2129 if guards:
2127 if guards:
2130 ui.note(_('active guards:\n'))
2128 ui.note(_('active guards:\n'))
2131 for g in guards:
2129 for g in guards:
2132 ui.write(g, '\n')
2130 ui.write(g, '\n')
2133 else:
2131 else:
2134 ui.write(_('no active guards\n'))
2132 ui.write(_('no active guards\n'))
2135 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2133 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2136 popped = False
2134 popped = False
2137 if opts['pop'] or opts['reapply']:
2135 if opts['pop'] or opts['reapply']:
2138 for i in xrange(len(q.applied)):
2136 for i in xrange(len(q.applied)):
2139 pushable, reason = q.pushable(i)
2137 pushable, reason = q.pushable(i)
2140 if not pushable:
2138 if not pushable:
2141 ui.status(_('popping guarded patches\n'))
2139 ui.status(_('popping guarded patches\n'))
2142 popped = True
2140 popped = True
2143 if i == 0:
2141 if i == 0:
2144 q.pop(repo, all=True)
2142 q.pop(repo, all=True)
2145 else:
2143 else:
2146 q.pop(repo, i-1)
2144 q.pop(repo, i-1)
2147 break
2145 break
2148 if popped:
2146 if popped:
2149 try:
2147 try:
2150 if reapply:
2148 if reapply:
2151 ui.status(_('reapplying unguarded patches\n'))
2149 ui.status(_('reapplying unguarded patches\n'))
2152 q.push(repo, reapply)
2150 q.push(repo, reapply)
2153 finally:
2151 finally:
2154 q.save_dirty()
2152 q.save_dirty()
2155
2153
2156 def reposetup(ui, repo):
2154 def reposetup(ui, repo):
2157 class mqrepo(repo.__class__):
2155 class mqrepo(repo.__class__):
2158 def abort_if_wdir_patched(self, errmsg, force=False):
2156 def abort_if_wdir_patched(self, errmsg, force=False):
2159 if self.mq.applied and not force:
2157 if self.mq.applied and not force:
2160 parent = revlog.hex(self.dirstate.parents()[0])
2158 parent = revlog.hex(self.dirstate.parents()[0])
2161 if parent in [s.rev for s in self.mq.applied]:
2159 if parent in [s.rev for s in self.mq.applied]:
2162 raise util.Abort(errmsg)
2160 raise util.Abort(errmsg)
2163
2161
2164 def commit(self, *args, **opts):
2162 def commit(self, *args, **opts):
2165 if len(args) >= 6:
2163 if len(args) >= 6:
2166 force = args[5]
2164 force = args[5]
2167 else:
2165 else:
2168 force = opts.get('force')
2166 force = opts.get('force')
2169 self.abort_if_wdir_patched(
2167 self.abort_if_wdir_patched(
2170 _('cannot commit over an applied mq patch'),
2168 _('cannot commit over an applied mq patch'),
2171 force)
2169 force)
2172
2170
2173 return super(mqrepo, self).commit(*args, **opts)
2171 return super(mqrepo, self).commit(*args, **opts)
2174
2172
2175 def push(self, remote, force=False, revs=None):
2173 def push(self, remote, force=False, revs=None):
2176 if self.mq.applied and not force and not revs:
2174 if self.mq.applied and not force and not revs:
2177 raise util.Abort(_('source has mq patches applied'))
2175 raise util.Abort(_('source has mq patches applied'))
2178 return super(mqrepo, self).push(remote, force, revs)
2176 return super(mqrepo, self).push(remote, force, revs)
2179
2177
2180 def tags(self):
2178 def tags(self):
2181 if self.tagscache:
2179 if self.tagscache:
2182 return self.tagscache
2180 return self.tagscache
2183
2181
2184 tagscache = super(mqrepo, self).tags()
2182 tagscache = super(mqrepo, self).tags()
2185
2183
2186 q = self.mq
2184 q = self.mq
2187 if not q.applied:
2185 if not q.applied:
2188 return tagscache
2186 return tagscache
2189
2187
2190 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2188 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2191
2189
2192 if mqtags[-1][0] not in self.changelog.nodemap:
2190 if mqtags[-1][0] not in self.changelog.nodemap:
2193 self.ui.warn('mq status file refers to unknown node %s\n'
2191 self.ui.warn('mq status file refers to unknown node %s\n'
2194 % revlog.short(mqtags[-1][0]))
2192 % revlog.short(mqtags[-1][0]))
2195 return tagscache
2193 return tagscache
2196
2194
2197 mqtags.append((mqtags[-1][0], 'qtip'))
2195 mqtags.append((mqtags[-1][0], 'qtip'))
2198 mqtags.append((mqtags[0][0], 'qbase'))
2196 mqtags.append((mqtags[0][0], 'qbase'))
2199 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2197 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2200 for patch in mqtags:
2198 for patch in mqtags:
2201 if patch[1] in tagscache:
2199 if patch[1] in tagscache:
2202 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2200 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2203 else:
2201 else:
2204 tagscache[patch[1]] = patch[0]
2202 tagscache[patch[1]] = patch[0]
2205
2203
2206 return tagscache
2204 return tagscache
2207
2205
2208 def _branchtags(self, partial, lrev):
2206 def _branchtags(self, partial, lrev):
2209 q = self.mq
2207 q = self.mq
2210 if not q.applied:
2208 if not q.applied:
2211 return super(mqrepo, self)._branchtags(partial, lrev)
2209 return super(mqrepo, self)._branchtags(partial, lrev)
2212
2210
2213 cl = self.changelog
2211 cl = self.changelog
2214 qbasenode = revlog.bin(q.applied[0].rev)
2212 qbasenode = revlog.bin(q.applied[0].rev)
2215 if qbasenode not in cl.nodemap:
2213 if qbasenode not in cl.nodemap:
2216 self.ui.warn('mq status file refers to unknown node %s\n'
2214 self.ui.warn('mq status file refers to unknown node %s\n'
2217 % revlog.short(qbasenode))
2215 % revlog.short(qbasenode))
2218 return super(mqrepo, self)._branchtags(partial, lrev)
2216 return super(mqrepo, self)._branchtags(partial, lrev)
2219
2217
2220 qbase = cl.rev(qbasenode)
2218 qbase = cl.rev(qbasenode)
2221 start = lrev + 1
2219 start = lrev + 1
2222 if start < qbase:
2220 if start < qbase:
2223 # update the cache (excluding the patches) and save it
2221 # update the cache (excluding the patches) and save it
2224 self._updatebranchcache(partial, lrev+1, qbase)
2222 self._updatebranchcache(partial, lrev+1, qbase)
2225 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2223 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2226 start = qbase
2224 start = qbase
2227 # if start = qbase, the cache is as updated as it should be.
2225 # if start = qbase, the cache is as updated as it should be.
2228 # if start > qbase, the cache includes (part of) the patches.
2226 # if start > qbase, the cache includes (part of) the patches.
2229 # we might as well use it, but we won't save it.
2227 # we might as well use it, but we won't save it.
2230
2228
2231 # update the cache up to the tip
2229 # update the cache up to the tip
2232 self._updatebranchcache(partial, start, cl.count())
2230 self._updatebranchcache(partial, start, cl.count())
2233
2231
2234 return partial
2232 return partial
2235
2233
2236 if repo.local():
2234 if repo.local():
2237 repo.__class__ = mqrepo
2235 repo.__class__ = mqrepo
2238 repo.mq = queue(ui, repo.join(""))
2236 repo.mq = queue(ui, repo.join(""))
2239
2237
2240 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2238 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2241
2239
2242 headeropts = [
2240 headeropts = [
2243 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2241 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2244 ('u', 'user', '', _('add "From: <given user>" to patch')),
2242 ('u', 'user', '', _('add "From: <given user>" to patch')),
2245 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2243 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2246 ('d', 'date', '', _('add "Date: <given date>" to patch'))]
2244 ('d', 'date', '', _('add "Date: <given date>" to patch'))]
2247
2245
2248 cmdtable = {
2246 cmdtable = {
2249 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2247 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2250 "qclone":
2248 "qclone":
2251 (clone,
2249 (clone,
2252 [('', 'pull', None, _('use pull protocol to copy metadata')),
2250 [('', 'pull', None, _('use pull protocol to copy metadata')),
2253 ('U', 'noupdate', None, _('do not update the new working directories')),
2251 ('U', 'noupdate', None, _('do not update the new working directories')),
2254 ('', 'uncompressed', None,
2252 ('', 'uncompressed', None,
2255 _('use uncompressed transfer (fast over LAN)')),
2253 _('use uncompressed transfer (fast over LAN)')),
2256 ('p', 'patches', '', _('location of source patch repo')),
2254 ('p', 'patches', '', _('location of source patch repo')),
2257 ] + commands.remoteopts,
2255 ] + commands.remoteopts,
2258 _('hg qclone [OPTION]... SOURCE [DEST]')),
2256 _('hg qclone [OPTION]... SOURCE [DEST]')),
2259 "qcommit|qci":
2257 "qcommit|qci":
2260 (commit,
2258 (commit,
2261 commands.table["^commit|ci"][1],
2259 commands.table["^commit|ci"][1],
2262 _('hg qcommit [OPTION]... [FILE]...')),
2260 _('hg qcommit [OPTION]... [FILE]...')),
2263 "^qdiff":
2261 "^qdiff":
2264 (diff,
2262 (diff,
2265 [('g', 'git', None, _('use git extended diff format')),
2263 [('g', 'git', None, _('use git extended diff format')),
2266 ('U', 'unified', 3, _('number of lines of context to show')),
2264 ('U', 'unified', 3, _('number of lines of context to show')),
2267 ] + commands.walkopts,
2265 ] + commands.walkopts,
2268 _('hg qdiff [-I] [-X] [-U NUM] [-g] [FILE]...')),
2266 _('hg qdiff [-I] [-X] [-U NUM] [-g] [FILE]...')),
2269 "qdelete|qremove|qrm":
2267 "qdelete|qremove|qrm":
2270 (delete,
2268 (delete,
2271 [('k', 'keep', None, _('keep patch file')),
2269 [('k', 'keep', None, _('keep patch file')),
2272 ('r', 'rev', [], _('stop managing a revision'))],
2270 ('r', 'rev', [], _('stop managing a revision'))],
2273 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2271 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2274 'qfold':
2272 'qfold':
2275 (fold,
2273 (fold,
2276 [('e', 'edit', None, _('edit patch header')),
2274 [('e', 'edit', None, _('edit patch header')),
2277 ('k', 'keep', None, _('keep folded patch files')),
2275 ('k', 'keep', None, _('keep folded patch files')),
2278 ] + commands.commitopts,
2276 ] + commands.commitopts,
2279 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2277 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2280 'qgoto':
2278 'qgoto':
2281 (goto,
2279 (goto,
2282 [('f', 'force', None, _('overwrite any local changes'))],
2280 [('f', 'force', None, _('overwrite any local changes'))],
2283 _('hg qgoto [OPTION]... PATCH')),
2281 _('hg qgoto [OPTION]... PATCH')),
2284 'qguard':
2282 'qguard':
2285 (guard,
2283 (guard,
2286 [('l', 'list', None, _('list all patches and guards')),
2284 [('l', 'list', None, _('list all patches and guards')),
2287 ('n', 'none', None, _('drop all guards'))],
2285 ('n', 'none', None, _('drop all guards'))],
2288 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2286 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2289 'qheader': (header, [], _('hg qheader [PATCH]')),
2287 'qheader': (header, [], _('hg qheader [PATCH]')),
2290 "^qimport":
2288 "^qimport":
2291 (qimport,
2289 (qimport,
2292 [('e', 'existing', None, 'import file in patch dir'),
2290 [('e', 'existing', None, 'import file in patch dir'),
2293 ('n', 'name', '', 'patch file name'),
2291 ('n', 'name', '', 'patch file name'),
2294 ('f', 'force', None, 'overwrite existing files'),
2292 ('f', 'force', None, 'overwrite existing files'),
2295 ('r', 'rev', [], 'place existing revisions under mq control'),
2293 ('r', 'rev', [], 'place existing revisions under mq control'),
2296 ('g', 'git', None, _('use git extended diff format'))],
2294 ('g', 'git', None, _('use git extended diff format'))],
2297 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2295 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2298 "^qinit":
2296 "^qinit":
2299 (init,
2297 (init,
2300 [('c', 'create-repo', None, 'create queue repository')],
2298 [('c', 'create-repo', None, 'create queue repository')],
2301 _('hg qinit [-c]')),
2299 _('hg qinit [-c]')),
2302 "qnew":
2300 "qnew":
2303 (new,
2301 (new,
2304 [('e', 'edit', None, _('edit commit message')),
2302 [('e', 'edit', None, _('edit commit message')),
2305 ('f', 'force', None, _('import uncommitted changes into patch')),
2303 ('f', 'force', None, _('import uncommitted changes into patch')),
2306 ('g', 'git', None, _('use git extended diff format')),
2304 ('g', 'git', None, _('use git extended diff format')),
2307 ] + commands.walkopts + commands.commitopts + headeropts,
2305 ] + commands.walkopts + commands.commitopts + headeropts,
2308 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2306 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2309 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2307 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2310 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2308 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2311 "^qpop":
2309 "^qpop":
2312 (pop,
2310 (pop,
2313 [('a', 'all', None, _('pop all patches')),
2311 [('a', 'all', None, _('pop all patches')),
2314 ('n', 'name', '', _('queue name to pop')),
2312 ('n', 'name', '', _('queue name to pop')),
2315 ('f', 'force', None, _('forget any local changes'))],
2313 ('f', 'force', None, _('forget any local changes'))],
2316 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2314 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2317 "^qpush":
2315 "^qpush":
2318 (push,
2316 (push,
2319 [('f', 'force', None, _('apply if the patch has rejects')),
2317 [('f', 'force', None, _('apply if the patch has rejects')),
2320 ('l', 'list', None, _('list patch name in commit text')),
2318 ('l', 'list', None, _('list patch name in commit text')),
2321 ('a', 'all', None, _('apply all patches')),
2319 ('a', 'all', None, _('apply all patches')),
2322 ('m', 'merge', None, _('merge from another queue')),
2320 ('m', 'merge', None, _('merge from another queue')),
2323 ('n', 'name', '', _('merge queue name'))],
2321 ('n', 'name', '', _('merge queue name'))],
2324 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2322 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2325 "^qrefresh":
2323 "^qrefresh":
2326 (refresh,
2324 (refresh,
2327 [('e', 'edit', None, _('edit commit message')),
2325 [('e', 'edit', None, _('edit commit message')),
2328 ('g', 'git', None, _('use git extended diff format')),
2326 ('g', 'git', None, _('use git extended diff format')),
2329 ('s', 'short', None, _('refresh only files already in the patch')),
2327 ('s', 'short', None, _('refresh only files already in the patch')),
2330 ] + commands.walkopts + commands.commitopts + headeropts,
2328 ] + commands.walkopts + commands.commitopts + headeropts,
2331 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2329 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2332 'qrename|qmv':
2330 'qrename|qmv':
2333 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2331 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2334 "qrestore":
2332 "qrestore":
2335 (restore,
2333 (restore,
2336 [('d', 'delete', None, _('delete save entry')),
2334 [('d', 'delete', None, _('delete save entry')),
2337 ('u', 'update', None, _('update queue working dir'))],
2335 ('u', 'update', None, _('update queue working dir'))],
2338 _('hg qrestore [-d] [-u] REV')),
2336 _('hg qrestore [-d] [-u] REV')),
2339 "qsave":
2337 "qsave":
2340 (save,
2338 (save,
2341 [('c', 'copy', None, _('copy patch directory')),
2339 [('c', 'copy', None, _('copy patch directory')),
2342 ('n', 'name', '', _('copy directory name')),
2340 ('n', 'name', '', _('copy directory name')),
2343 ('e', 'empty', None, _('clear queue status file')),
2341 ('e', 'empty', None, _('clear queue status file')),
2344 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2342 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2345 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2343 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2346 "qselect":
2344 "qselect":
2347 (select,
2345 (select,
2348 [('n', 'none', None, _('disable all guards')),
2346 [('n', 'none', None, _('disable all guards')),
2349 ('s', 'series', None, _('list all guards in series file')),
2347 ('s', 'series', None, _('list all guards in series file')),
2350 ('', 'pop', None, _('pop to before first guarded applied patch')),
2348 ('', 'pop', None, _('pop to before first guarded applied patch')),
2351 ('', 'reapply', None, _('pop, then reapply patches'))],
2349 ('', 'reapply', None, _('pop, then reapply patches'))],
2352 _('hg qselect [OPTION]... [GUARD]...')),
2350 _('hg qselect [OPTION]... [GUARD]...')),
2353 "qseries":
2351 "qseries":
2354 (series,
2352 (series,
2355 [('m', 'missing', None, _('print patches not in series')),
2353 [('m', 'missing', None, _('print patches not in series')),
2356 ] + seriesopts,
2354 ] + seriesopts,
2357 _('hg qseries [-ms]')),
2355 _('hg qseries [-ms]')),
2358 "^strip":
2356 "^strip":
2359 (strip,
2357 (strip,
2360 [('f', 'force', None, _('force removal with local changes')),
2358 [('f', 'force', None, _('force removal with local changes')),
2361 ('b', 'backup', None, _('bundle unrelated changesets')),
2359 ('b', 'backup', None, _('bundle unrelated changesets')),
2362 ('n', 'nobackup', None, _('no backups'))],
2360 ('n', 'nobackup', None, _('no backups'))],
2363 _('hg strip [-f] [-b] [-n] REV')),
2361 _('hg strip [-f] [-b] [-n] REV')),
2364 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2362 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2365 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2363 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2366 }
2364 }
@@ -1,3327 +1,3328 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from repo import RepoError, NoCapability
9 from repo import RepoError, NoCapability
10 from i18n import _
10 from i18n import _
11 import os, re, sys, urllib
11 import os, re, sys, urllib
12 import hg, util, revlog, bundlerepo, extensions, copies
12 import hg, util, revlog, bundlerepo, extensions, copies
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import version, socket
14 import version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 import merge as merge_
16 import merge as merge_
17
17
18 # Commands start here, listed alphabetically
18 # Commands start here, listed alphabetically
19
19
20 def add(ui, repo, *pats, **opts):
20 def add(ui, repo, *pats, **opts):
21 """add the specified files on the next commit
21 """add the specified files on the next commit
22
22
23 Schedule files to be version controlled and added to the repository.
23 Schedule files to be version controlled and added to the repository.
24
24
25 The files will be added to the repository at the next commit. To
25 The files will be added to the repository at the next commit. To
26 undo an add before that, see hg revert.
26 undo an add before that, see hg revert.
27
27
28 If no names are given, add all files in the repository.
28 If no names are given, add all files in the repository.
29 """
29 """
30
30
31 rejected = None
31 rejected = None
32 exacts = {}
32 exacts = {}
33 names = []
33 names = []
34 m = cmdutil.match(repo, pats, opts)
34 m = cmdutil.match(repo, pats, opts)
35 m.bad = lambda x,y: True
35 m.bad = lambda x,y: True
36 for abs in repo.walk(m):
36 for abs in repo.walk(m):
37 if m.exact(abs):
37 if m.exact(abs):
38 if ui.verbose:
38 if ui.verbose:
39 ui.status(_('adding %s\n') % m.rel(abs))
39 ui.status(_('adding %s\n') % m.rel(abs))
40 names.append(abs)
40 names.append(abs)
41 exacts[abs] = 1
41 exacts[abs] = 1
42 elif abs not in repo.dirstate:
42 elif abs not in repo.dirstate:
43 ui.status(_('adding %s\n') % m.rel(abs))
43 ui.status(_('adding %s\n') % m.rel(abs))
44 names.append(abs)
44 names.append(abs)
45 if not opts.get('dry_run'):
45 if not opts.get('dry_run'):
46 rejected = repo.add(names)
46 rejected = repo.add(names)
47 rejected = [p for p in rejected if p in exacts]
47 rejected = [p for p in rejected if p in exacts]
48 return rejected and 1 or 0
48 return rejected and 1 or 0
49
49
50 def addremove(ui, repo, *pats, **opts):
50 def addremove(ui, repo, *pats, **opts):
51 """add all new files, delete all missing files
51 """add all new files, delete all missing files
52
52
53 Add all new files and remove all missing files from the repository.
53 Add all new files and remove all missing files from the repository.
54
54
55 New files are ignored if they match any of the patterns in .hgignore. As
55 New files are ignored if they match any of the patterns in .hgignore. As
56 with add, these changes take effect at the next commit.
56 with add, these changes take effect at the next commit.
57
57
58 Use the -s option to detect renamed files. With a parameter > 0,
58 Use the -s option to detect renamed files. With a parameter > 0,
59 this compares every removed file with every added file and records
59 this compares every removed file with every added file and records
60 those similar enough as renames. This option takes a percentage
60 those similar enough as renames. This option takes a percentage
61 between 0 (disabled) and 100 (files must be identical) as its
61 between 0 (disabled) and 100 (files must be identical) as its
62 parameter. Detecting renamed files this way can be expensive.
62 parameter. Detecting renamed files this way can be expensive.
63 """
63 """
64 try:
64 try:
65 sim = float(opts.get('similarity') or 0)
65 sim = float(opts.get('similarity') or 0)
66 except ValueError:
66 except ValueError:
67 raise util.Abort(_('similarity must be a number'))
67 raise util.Abort(_('similarity must be a number'))
68 if sim < 0 or sim > 100:
68 if sim < 0 or sim > 100:
69 raise util.Abort(_('similarity must be between 0 and 100'))
69 raise util.Abort(_('similarity must be between 0 and 100'))
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
71
71
72 def annotate(ui, repo, *pats, **opts):
72 def annotate(ui, repo, *pats, **opts):
73 """show changeset information per file line
73 """show changeset information per file line
74
74
75 List changes in files, showing the revision id responsible for each line
75 List changes in files, showing the revision id responsible for each line
76
76
77 This command is useful to discover who did a change or when a change took
77 This command is useful to discover who did a change or when a change took
78 place.
78 place.
79
79
80 Without the -a option, annotate will avoid processing files it
80 Without the -a option, annotate will avoid processing files it
81 detects as binary. With -a, annotate will generate an annotation
81 detects as binary. With -a, annotate will generate an annotation
82 anyway, probably with undesirable results.
82 anyway, probably with undesirable results.
83 """
83 """
84 datefunc = ui.quiet and util.shortdate or util.datestr
84 datefunc = ui.quiet and util.shortdate or util.datestr
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
86
86
87 if not pats:
87 if not pats:
88 raise util.Abort(_('at least one file name or pattern required'))
88 raise util.Abort(_('at least one file name or pattern required'))
89
89
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
91 ('number', lambda x: str(x[0].rev())),
91 ('number', lambda x: str(x[0].rev())),
92 ('changeset', lambda x: short(x[0].node())),
92 ('changeset', lambda x: short(x[0].node())),
93 ('date', getdate),
93 ('date', getdate),
94 ('follow', lambda x: x[0].path()),
94 ('follow', lambda x: x[0].path()),
95 ]
95 ]
96
96
97 if (not opts['user'] and not opts['changeset'] and not opts['date']
97 if (not opts['user'] and not opts['changeset'] and not opts['date']
98 and not opts['follow']):
98 and not opts['follow']):
99 opts['number'] = 1
99 opts['number'] = 1
100
100
101 linenumber = opts.get('line_number') is not None
101 linenumber = opts.get('line_number') is not None
102 if (linenumber and (not opts['changeset']) and (not opts['number'])):
102 if (linenumber and (not opts['changeset']) and (not opts['number'])):
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
104
104
105 funcmap = [func for op, func in opmap if opts.get(op)]
105 funcmap = [func for op, func in opmap if opts.get(op)]
106 if linenumber:
106 if linenumber:
107 lastfunc = funcmap[-1]
107 lastfunc = funcmap[-1]
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
109
109
110 ctx = repo.changectx(opts['rev'])
110 ctx = repo.changectx(opts['rev'])
111
111
112 m = cmdutil.match(repo, pats, opts)
112 m = cmdutil.match(repo, pats, opts)
113 for abs in repo.walk(m, ctx.node()):
113 for abs in repo.walk(m, ctx.node()):
114 fctx = ctx.filectx(abs)
114 fctx = ctx.filectx(abs)
115 if not opts['text'] and util.binary(fctx.data()):
115 if not opts['text'] and util.binary(fctx.data()):
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
117 continue
117 continue
118
118
119 lines = fctx.annotate(follow=opts.get('follow'),
119 lines = fctx.annotate(follow=opts.get('follow'),
120 linenumber=linenumber)
120 linenumber=linenumber)
121 pieces = []
121 pieces = []
122
122
123 for f in funcmap:
123 for f in funcmap:
124 l = [f(n) for n, dummy in lines]
124 l = [f(n) for n, dummy in lines]
125 if l:
125 if l:
126 m = max(map(len, l))
126 m = max(map(len, l))
127 pieces.append(["%*s" % (m, x) for x in l])
127 pieces.append(["%*s" % (m, x) for x in l])
128
128
129 if pieces:
129 if pieces:
130 for p, l in zip(zip(*pieces), lines):
130 for p, l in zip(zip(*pieces), lines):
131 ui.write("%s: %s" % (" ".join(p), l[1]))
131 ui.write("%s: %s" % (" ".join(p), l[1]))
132
132
133 def archive(ui, repo, dest, **opts):
133 def archive(ui, repo, dest, **opts):
134 '''create unversioned archive of a repository revision
134 '''create unversioned archive of a repository revision
135
135
136 By default, the revision used is the parent of the working
136 By default, the revision used is the parent of the working
137 directory; use "-r" to specify a different revision.
137 directory; use "-r" to specify a different revision.
138
138
139 To specify the type of archive to create, use "-t". Valid
139 To specify the type of archive to create, use "-t". Valid
140 types are:
140 types are:
141
141
142 "files" (default): a directory full of files
142 "files" (default): a directory full of files
143 "tar": tar archive, uncompressed
143 "tar": tar archive, uncompressed
144 "tbz2": tar archive, compressed using bzip2
144 "tbz2": tar archive, compressed using bzip2
145 "tgz": tar archive, compressed using gzip
145 "tgz": tar archive, compressed using gzip
146 "uzip": zip archive, uncompressed
146 "uzip": zip archive, uncompressed
147 "zip": zip archive, compressed using deflate
147 "zip": zip archive, compressed using deflate
148
148
149 The exact name of the destination archive or directory is given
149 The exact name of the destination archive or directory is given
150 using a format string; see "hg help export" for details.
150 using a format string; see "hg help export" for details.
151
151
152 Each member added to an archive file has a directory prefix
152 Each member added to an archive file has a directory prefix
153 prepended. Use "-p" to specify a format string for the prefix.
153 prepended. Use "-p" to specify a format string for the prefix.
154 The default is the basename of the archive, with suffixes removed.
154 The default is the basename of the archive, with suffixes removed.
155 '''
155 '''
156
156
157 ctx = repo.changectx(opts['rev'])
157 ctx = repo.changectx(opts['rev'])
158 if not ctx:
158 if not ctx:
159 raise util.Abort(_('repository has no revisions'))
159 raise util.Abort(_('repository has no revisions'))
160 node = ctx.node()
160 node = ctx.node()
161 dest = cmdutil.make_filename(repo, dest, node)
161 dest = cmdutil.make_filename(repo, dest, node)
162 if os.path.realpath(dest) == repo.root:
162 if os.path.realpath(dest) == repo.root:
163 raise util.Abort(_('repository root cannot be destination'))
163 raise util.Abort(_('repository root cannot be destination'))
164 matchfn = cmdutil.match(repo, [], opts)
164 matchfn = cmdutil.match(repo, [], opts)
165 kind = opts.get('type') or 'files'
165 kind = opts.get('type') or 'files'
166 prefix = opts['prefix']
166 prefix = opts['prefix']
167 if dest == '-':
167 if dest == '-':
168 if kind == 'files':
168 if kind == 'files':
169 raise util.Abort(_('cannot archive plain files to stdout'))
169 raise util.Abort(_('cannot archive plain files to stdout'))
170 dest = sys.stdout
170 dest = sys.stdout
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
172 prefix = cmdutil.make_filename(repo, prefix, node)
172 prefix = cmdutil.make_filename(repo, prefix, node)
173 archival.archive(repo, dest, node, kind, not opts['no_decode'],
173 archival.archive(repo, dest, node, kind, not opts['no_decode'],
174 matchfn, prefix)
174 matchfn, prefix)
175
175
176 def backout(ui, repo, node=None, rev=None, **opts):
176 def backout(ui, repo, node=None, rev=None, **opts):
177 '''reverse effect of earlier changeset
177 '''reverse effect of earlier changeset
178
178
179 Commit the backed out changes as a new changeset. The new
179 Commit the backed out changes as a new changeset. The new
180 changeset is a child of the backed out changeset.
180 changeset is a child of the backed out changeset.
181
181
182 If you back out a changeset other than the tip, a new head is
182 If you back out a changeset other than the tip, a new head is
183 created. This head will be the new tip and you should merge this
183 created. This head will be the new tip and you should merge this
184 backout changeset with another head (current one by default).
184 backout changeset with another head (current one by default).
185
185
186 The --merge option remembers the parent of the working directory
186 The --merge option remembers the parent of the working directory
187 before starting the backout, then merges the new head with that
187 before starting the backout, then merges the new head with that
188 changeset afterwards. This saves you from doing the merge by
188 changeset afterwards. This saves you from doing the merge by
189 hand. The result of this merge is not committed, as for a normal
189 hand. The result of this merge is not committed, as for a normal
190 merge.
190 merge.
191
191
192 See 'hg help dates' for a list of formats valid for -d/--date.
192 See 'hg help dates' for a list of formats valid for -d/--date.
193 '''
193 '''
194 if rev and node:
194 if rev and node:
195 raise util.Abort(_("please specify just one revision"))
195 raise util.Abort(_("please specify just one revision"))
196
196
197 if not rev:
197 if not rev:
198 rev = node
198 rev = node
199
199
200 if not rev:
200 if not rev:
201 raise util.Abort(_("please specify a revision to backout"))
201 raise util.Abort(_("please specify a revision to backout"))
202
202
203 date = opts.get('date')
203 date = opts.get('date')
204 if date:
204 if date:
205 opts['date'] = util.parsedate(date)
205 opts['date'] = util.parsedate(date)
206
206
207 cmdutil.bail_if_changed(repo)
207 cmdutil.bail_if_changed(repo)
208 node = repo.lookup(rev)
208 node = repo.lookup(rev)
209
209
210 op1, op2 = repo.dirstate.parents()
210 op1, op2 = repo.dirstate.parents()
211 a = repo.changelog.ancestor(op1, node)
211 a = repo.changelog.ancestor(op1, node)
212 if a != node:
212 if a != node:
213 raise util.Abort(_('cannot back out change on a different branch'))
213 raise util.Abort(_('cannot back out change on a different branch'))
214
214
215 p1, p2 = repo.changelog.parents(node)
215 p1, p2 = repo.changelog.parents(node)
216 if p1 == nullid:
216 if p1 == nullid:
217 raise util.Abort(_('cannot back out a change with no parents'))
217 raise util.Abort(_('cannot back out a change with no parents'))
218 if p2 != nullid:
218 if p2 != nullid:
219 if not opts['parent']:
219 if not opts['parent']:
220 raise util.Abort(_('cannot back out a merge changeset without '
220 raise util.Abort(_('cannot back out a merge changeset without '
221 '--parent'))
221 '--parent'))
222 p = repo.lookup(opts['parent'])
222 p = repo.lookup(opts['parent'])
223 if p not in (p1, p2):
223 if p not in (p1, p2):
224 raise util.Abort(_('%s is not a parent of %s') %
224 raise util.Abort(_('%s is not a parent of %s') %
225 (short(p), short(node)))
225 (short(p), short(node)))
226 parent = p
226 parent = p
227 else:
227 else:
228 if opts['parent']:
228 if opts['parent']:
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
230 parent = p1
230 parent = p1
231
231
232 # the backout should appear on the same branch
232 # the backout should appear on the same branch
233 branch = repo.dirstate.branch()
233 branch = repo.dirstate.branch()
234 hg.clean(repo, node, show_stats=False)
234 hg.clean(repo, node, show_stats=False)
235 repo.dirstate.setbranch(branch)
235 repo.dirstate.setbranch(branch)
236 revert_opts = opts.copy()
236 revert_opts = opts.copy()
237 revert_opts['date'] = None
237 revert_opts['date'] = None
238 revert_opts['all'] = True
238 revert_opts['all'] = True
239 revert_opts['rev'] = hex(parent)
239 revert_opts['rev'] = hex(parent)
240 revert_opts['no_backup'] = None
240 revert_opts['no_backup'] = None
241 revert(ui, repo, **revert_opts)
241 revert(ui, repo, **revert_opts)
242 commit_opts = opts.copy()
242 commit_opts = opts.copy()
243 commit_opts['addremove'] = False
243 commit_opts['addremove'] = False
244 if not commit_opts['message'] and not commit_opts['logfile']:
244 if not commit_opts['message'] and not commit_opts['logfile']:
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
246 commit_opts['force_editor'] = True
246 commit_opts['force_editor'] = True
247 commit(ui, repo, **commit_opts)
247 commit(ui, repo, **commit_opts)
248 def nice(node):
248 def nice(node):
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
250 ui.status(_('changeset %s backs out changeset %s\n') %
250 ui.status(_('changeset %s backs out changeset %s\n') %
251 (nice(repo.changelog.tip()), nice(node)))
251 (nice(repo.changelog.tip()), nice(node)))
252 if op1 != node:
252 if op1 != node:
253 hg.clean(repo, op1, show_stats=False)
253 hg.clean(repo, op1, show_stats=False)
254 if opts['merge']:
254 if opts['merge']:
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
257 else:
257 else:
258 ui.status(_('the backout changeset is a new head - '
258 ui.status(_('the backout changeset is a new head - '
259 'do not forget to merge\n'))
259 'do not forget to merge\n'))
260 ui.status(_('(use "backout --merge" '
260 ui.status(_('(use "backout --merge" '
261 'if you want to auto-merge)\n'))
261 'if you want to auto-merge)\n'))
262
262
263 def bisect(ui, repo, rev=None, extra=None,
263 def bisect(ui, repo, rev=None, extra=None,
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
265 """subdivision search of changesets
265 """subdivision search of changesets
266
266
267 This command helps to find changesets which introduce problems.
267 This command helps to find changesets which introduce problems.
268 To use, mark the earliest changeset you know exhibits the problem
268 To use, mark the earliest changeset you know exhibits the problem
269 as bad, then mark the latest changeset which is free from the
269 as bad, then mark the latest changeset which is free from the
270 problem as good. Bisect will update your working directory to a
270 problem as good. Bisect will update your working directory to a
271 revision for testing. Once you have performed tests, mark the
271 revision for testing. Once you have performed tests, mark the
272 working directory as bad or good and bisect will either update to
272 working directory as bad or good and bisect will either update to
273 another candidate changeset or announce that it has found the bad
273 another candidate changeset or announce that it has found the bad
274 revision.
274 revision.
275 """
275 """
276 # backward compatibility
276 # backward compatibility
277 if rev in "good bad reset init".split():
277 if rev in "good bad reset init".split():
278 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
278 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
279 cmd, rev, extra = rev, extra, None
279 cmd, rev, extra = rev, extra, None
280 if cmd == "good":
280 if cmd == "good":
281 good = True
281 good = True
282 elif cmd == "bad":
282 elif cmd == "bad":
283 bad = True
283 bad = True
284 else:
284 else:
285 reset = True
285 reset = True
286 elif extra or good + bad + skip + reset > 1:
286 elif extra or good + bad + skip + reset > 1:
287 raise util.Abort("Incompatible arguments")
287 raise util.Abort("Incompatible arguments")
288
288
289 if reset:
289 if reset:
290 p = repo.join("bisect.state")
290 p = repo.join("bisect.state")
291 if os.path.exists(p):
291 if os.path.exists(p):
292 os.unlink(p)
292 os.unlink(p)
293 return
293 return
294
294
295 # load state
295 # load state
296 state = {'good': [], 'bad': [], 'skip': []}
296 state = {'good': [], 'bad': [], 'skip': []}
297 if os.path.exists(repo.join("bisect.state")):
297 if os.path.exists(repo.join("bisect.state")):
298 for l in repo.opener("bisect.state"):
298 for l in repo.opener("bisect.state"):
299 kind, node = l[:-1].split()
299 kind, node = l[:-1].split()
300 node = repo.lookup(node)
300 node = repo.lookup(node)
301 if kind not in state:
301 if kind not in state:
302 raise util.Abort(_("unknown bisect kind %s") % kind)
302 raise util.Abort(_("unknown bisect kind %s") % kind)
303 state[kind].append(node)
303 state[kind].append(node)
304
304
305 # update state
305 # update state
306 node = repo.lookup(rev or '.')
306 node = repo.lookup(rev or '.')
307 if good:
307 if good:
308 state['good'].append(node)
308 state['good'].append(node)
309 elif bad:
309 elif bad:
310 state['bad'].append(node)
310 state['bad'].append(node)
311 elif skip:
311 elif skip:
312 state['skip'].append(node)
312 state['skip'].append(node)
313
313
314 # save state
314 # save state
315 f = repo.opener("bisect.state", "w", atomictemp=True)
315 f = repo.opener("bisect.state", "w", atomictemp=True)
316 wlock = repo.wlock()
316 wlock = repo.wlock()
317 try:
317 try:
318 for kind in state:
318 for kind in state:
319 for node in state[kind]:
319 for node in state[kind]:
320 f.write("%s %s\n" % (kind, hex(node)))
320 f.write("%s %s\n" % (kind, hex(node)))
321 f.rename()
321 f.rename()
322 finally:
322 finally:
323 del wlock
323 del wlock
324
324
325 if not state['good'] or not state['bad']:
325 if not state['good'] or not state['bad']:
326 return
326 return
327
327
328 # actually bisect
328 # actually bisect
329 node, changesets, good = hbisect.bisect(repo.changelog, state)
329 node, changesets, good = hbisect.bisect(repo.changelog, state)
330 if changesets == 0:
330 if changesets == 0:
331 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
331 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
332 displayer = cmdutil.show_changeset(ui, repo, {})
332 displayer = cmdutil.show_changeset(ui, repo, {})
333 displayer.show(changenode=node)
333 displayer.show(changenode=node)
334 elif node is not None:
334 elif node is not None:
335 # compute the approximate number of remaining tests
335 # compute the approximate number of remaining tests
336 tests, size = 0, 2
336 tests, size = 0, 2
337 while size <= changesets:
337 while size <= changesets:
338 tests, size = tests + 1, size * 2
338 tests, size = tests + 1, size * 2
339 rev = repo.changelog.rev(node)
339 rev = repo.changelog.rev(node)
340 ui.write(_("Testing changeset %s:%s "
340 ui.write(_("Testing changeset %s:%s "
341 "(%s changesets remaining, ~%s tests)\n")
341 "(%s changesets remaining, ~%s tests)\n")
342 % (rev, short(node), changesets, tests))
342 % (rev, short(node), changesets, tests))
343 if not noupdate:
343 if not noupdate:
344 cmdutil.bail_if_changed(repo)
344 cmdutil.bail_if_changed(repo)
345 return hg.clean(repo, node)
345 return hg.clean(repo, node)
346
346
347 def branch(ui, repo, label=None, **opts):
347 def branch(ui, repo, label=None, **opts):
348 """set or show the current branch name
348 """set or show the current branch name
349
349
350 With no argument, show the current branch name. With one argument,
350 With no argument, show the current branch name. With one argument,
351 set the working directory branch name (the branch does not exist in
351 set the working directory branch name (the branch does not exist in
352 the repository until the next commit).
352 the repository until the next commit).
353
353
354 Unless --force is specified, branch will not let you set a
354 Unless --force is specified, branch will not let you set a
355 branch name that shadows an existing branch.
355 branch name that shadows an existing branch.
356
356
357 Use the command 'hg update' to switch to an existing branch.
357 Use the command 'hg update' to switch to an existing branch.
358 """
358 """
359
359
360 if label:
360 if label:
361 if not opts.get('force') and label in repo.branchtags():
361 if not opts.get('force') and label in repo.branchtags():
362 if label not in [p.branch() for p in repo.workingctx().parents()]:
362 if label not in [p.branch() for p in repo.workingctx().parents()]:
363 raise util.Abort(_('a branch of the same name already exists'
363 raise util.Abort(_('a branch of the same name already exists'
364 ' (use --force to override)'))
364 ' (use --force to override)'))
365 repo.dirstate.setbranch(util.fromlocal(label))
365 repo.dirstate.setbranch(util.fromlocal(label))
366 ui.status(_('marked working directory as branch %s\n') % label)
366 ui.status(_('marked working directory as branch %s\n') % label)
367 else:
367 else:
368 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
368 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
369
369
370 def branches(ui, repo, active=False):
370 def branches(ui, repo, active=False):
371 """list repository named branches
371 """list repository named branches
372
372
373 List the repository's named branches, indicating which ones are
373 List the repository's named branches, indicating which ones are
374 inactive. If active is specified, only show active branches.
374 inactive. If active is specified, only show active branches.
375
375
376 A branch is considered active if it contains unmerged heads.
376 A branch is considered active if it contains unmerged heads.
377
377
378 Use the command 'hg update' to switch to an existing branch.
378 Use the command 'hg update' to switch to an existing branch.
379 """
379 """
380 b = repo.branchtags()
380 b = repo.branchtags()
381 heads = dict.fromkeys(repo.heads(), 1)
381 heads = dict.fromkeys(repo.heads(), 1)
382 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
382 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
383 l.sort()
383 l.sort()
384 l.reverse()
384 l.reverse()
385 for ishead, r, n, t in l:
385 for ishead, r, n, t in l:
386 if active and not ishead:
386 if active and not ishead:
387 # If we're only displaying active branches, abort the loop on
387 # If we're only displaying active branches, abort the loop on
388 # encountering the first inactive head
388 # encountering the first inactive head
389 break
389 break
390 else:
390 else:
391 hexfunc = ui.debugflag and hex or short
391 hexfunc = ui.debugflag and hex or short
392 if ui.quiet:
392 if ui.quiet:
393 ui.write("%s\n" % t)
393 ui.write("%s\n" % t)
394 else:
394 else:
395 spaces = " " * (30 - util.locallen(t))
395 spaces = " " * (30 - util.locallen(t))
396 # The code only gets here if inactive branches are being
396 # The code only gets here if inactive branches are being
397 # displayed or the branch is active.
397 # displayed or the branch is active.
398 isinactive = ((not ishead) and " (inactive)") or ''
398 isinactive = ((not ishead) and " (inactive)") or ''
399 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
399 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
400
400
401 def bundle(ui, repo, fname, dest=None, **opts):
401 def bundle(ui, repo, fname, dest=None, **opts):
402 """create a changegroup file
402 """create a changegroup file
403
403
404 Generate a compressed changegroup file collecting changesets not
404 Generate a compressed changegroup file collecting changesets not
405 found in the other repository.
405 found in the other repository.
406
406
407 If no destination repository is specified the destination is
407 If no destination repository is specified the destination is
408 assumed to have all the nodes specified by one or more --base
408 assumed to have all the nodes specified by one or more --base
409 parameters. To create a bundle containing all changesets, use
409 parameters. To create a bundle containing all changesets, use
410 --all (or --base null). To change the compression method applied,
410 --all (or --base null). To change the compression method applied,
411 use the -t option (by default, bundles are compressed using bz2).
411 use the -t option (by default, bundles are compressed using bz2).
412
412
413 The bundle file can then be transferred using conventional means and
413 The bundle file can then be transferred using conventional means and
414 applied to another repository with the unbundle or pull command.
414 applied to another repository with the unbundle or pull command.
415 This is useful when direct push and pull are not available or when
415 This is useful when direct push and pull are not available or when
416 exporting an entire repository is undesirable.
416 exporting an entire repository is undesirable.
417
417
418 Applying bundles preserves all changeset contents including
418 Applying bundles preserves all changeset contents including
419 permissions, copy/rename information, and revision history.
419 permissions, copy/rename information, and revision history.
420 """
420 """
421 revs = opts.get('rev') or None
421 revs = opts.get('rev') or None
422 if revs:
422 if revs:
423 revs = [repo.lookup(rev) for rev in revs]
423 revs = [repo.lookup(rev) for rev in revs]
424 if opts.get('all'):
424 if opts.get('all'):
425 base = ['null']
425 base = ['null']
426 else:
426 else:
427 base = opts.get('base')
427 base = opts.get('base')
428 if base:
428 if base:
429 if dest:
429 if dest:
430 raise util.Abort(_("--base is incompatible with specifiying "
430 raise util.Abort(_("--base is incompatible with specifiying "
431 "a destination"))
431 "a destination"))
432 base = [repo.lookup(rev) for rev in base]
432 base = [repo.lookup(rev) for rev in base]
433 # create the right base
433 # create the right base
434 # XXX: nodesbetween / changegroup* should be "fixed" instead
434 # XXX: nodesbetween / changegroup* should be "fixed" instead
435 o = []
435 o = []
436 has = {nullid: None}
436 has = {nullid: None}
437 for n in base:
437 for n in base:
438 has.update(repo.changelog.reachable(n))
438 has.update(repo.changelog.reachable(n))
439 if revs:
439 if revs:
440 visit = list(revs)
440 visit = list(revs)
441 else:
441 else:
442 visit = repo.changelog.heads()
442 visit = repo.changelog.heads()
443 seen = {}
443 seen = {}
444 while visit:
444 while visit:
445 n = visit.pop(0)
445 n = visit.pop(0)
446 parents = [p for p in repo.changelog.parents(n) if p not in has]
446 parents = [p for p in repo.changelog.parents(n) if p not in has]
447 if len(parents) == 0:
447 if len(parents) == 0:
448 o.insert(0, n)
448 o.insert(0, n)
449 else:
449 else:
450 for p in parents:
450 for p in parents:
451 if p not in seen:
451 if p not in seen:
452 seen[p] = 1
452 seen[p] = 1
453 visit.append(p)
453 visit.append(p)
454 else:
454 else:
455 cmdutil.setremoteconfig(ui, opts)
455 cmdutil.setremoteconfig(ui, opts)
456 dest, revs, checkout = hg.parseurl(
456 dest, revs, checkout = hg.parseurl(
457 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
457 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
458 other = hg.repository(ui, dest)
458 other = hg.repository(ui, dest)
459 o = repo.findoutgoing(other, force=opts['force'])
459 o = repo.findoutgoing(other, force=opts['force'])
460
460
461 if revs:
461 if revs:
462 cg = repo.changegroupsubset(o, revs, 'bundle')
462 cg = repo.changegroupsubset(o, revs, 'bundle')
463 else:
463 else:
464 cg = repo.changegroup(o, 'bundle')
464 cg = repo.changegroup(o, 'bundle')
465
465
466 bundletype = opts.get('type', 'bzip2').lower()
466 bundletype = opts.get('type', 'bzip2').lower()
467 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
467 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
468 bundletype = btypes.get(bundletype)
468 bundletype = btypes.get(bundletype)
469 if bundletype not in changegroup.bundletypes:
469 if bundletype not in changegroup.bundletypes:
470 raise util.Abort(_('unknown bundle type specified with --type'))
470 raise util.Abort(_('unknown bundle type specified with --type'))
471
471
472 changegroup.writebundle(cg, fname, bundletype)
472 changegroup.writebundle(cg, fname, bundletype)
473
473
474 def cat(ui, repo, file1, *pats, **opts):
474 def cat(ui, repo, file1, *pats, **opts):
475 """output the current or given revision of files
475 """output the current or given revision of files
476
476
477 Print the specified files as they were at the given revision.
477 Print the specified files as they were at the given revision.
478 If no revision is given, the parent of the working directory is used,
478 If no revision is given, the parent of the working directory is used,
479 or tip if no revision is checked out.
479 or tip if no revision is checked out.
480
480
481 Output may be to a file, in which case the name of the file is
481 Output may be to a file, in which case the name of the file is
482 given using a format string. The formatting rules are the same as
482 given using a format string. The formatting rules are the same as
483 for the export command, with the following additions:
483 for the export command, with the following additions:
484
484
485 %s basename of file being printed
485 %s basename of file being printed
486 %d dirname of file being printed, or '.' if in repo root
486 %d dirname of file being printed, or '.' if in repo root
487 %p root-relative path name of file being printed
487 %p root-relative path name of file being printed
488 """
488 """
489 ctx = repo.changectx(opts['rev'])
489 ctx = repo.changectx(opts['rev'])
490 err = 1
490 err = 1
491 m = cmdutil.match(repo, (file1,) + pats, opts)
491 m = cmdutil.match(repo, (file1,) + pats, opts)
492 for abs in repo.walk(m, ctx.node()):
492 for abs in repo.walk(m, ctx.node()):
493 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
493 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
494 data = ctx.filectx(abs).data()
494 data = ctx.filectx(abs).data()
495 if opts.get('decode'):
495 if opts.get('decode'):
496 data = repo.wwritedata(abs, data)
496 data = repo.wwritedata(abs, data)
497 fp.write(data)
497 fp.write(data)
498 err = 0
498 err = 0
499 return err
499 return err
500
500
501 def clone(ui, source, dest=None, **opts):
501 def clone(ui, source, dest=None, **opts):
502 """make a copy of an existing repository
502 """make a copy of an existing repository
503
503
504 Create a copy of an existing repository in a new directory.
504 Create a copy of an existing repository in a new directory.
505
505
506 If no destination directory name is specified, it defaults to the
506 If no destination directory name is specified, it defaults to the
507 basename of the source.
507 basename of the source.
508
508
509 The location of the source is added to the new repository's
509 The location of the source is added to the new repository's
510 .hg/hgrc file, as the default to be used for future pulls.
510 .hg/hgrc file, as the default to be used for future pulls.
511
511
512 For efficiency, hardlinks are used for cloning whenever the source
512 For efficiency, hardlinks are used for cloning whenever the source
513 and destination are on the same filesystem (note this applies only
513 and destination are on the same filesystem (note this applies only
514 to the repository data, not to the checked out files). Some
514 to the repository data, not to the checked out files). Some
515 filesystems, such as AFS, implement hardlinking incorrectly, but
515 filesystems, such as AFS, implement hardlinking incorrectly, but
516 do not report errors. In these cases, use the --pull option to
516 do not report errors. In these cases, use the --pull option to
517 avoid hardlinking.
517 avoid hardlinking.
518
518
519 In some cases, you can clone repositories and checked out files
519 In some cases, you can clone repositories and checked out files
520 using full hardlinks with
520 using full hardlinks with
521
521
522 $ cp -al REPO REPOCLONE
522 $ cp -al REPO REPOCLONE
523
523
524 This is the fastest way to clone, but it is not always safe. The
524 This is the fastest way to clone, but it is not always safe. The
525 operation is not atomic (making sure REPO is not modified during
525 operation is not atomic (making sure REPO is not modified during
526 the operation is up to you) and you have to make sure your editor
526 the operation is up to you) and you have to make sure your editor
527 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
527 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
528 this is not compatible with certain extensions that place their
528 this is not compatible with certain extensions that place their
529 metadata under the .hg directory, such as mq.
529 metadata under the .hg directory, such as mq.
530
530
531 If you use the -r option to clone up to a specific revision, no
531 If you use the -r option to clone up to a specific revision, no
532 subsequent revisions will be present in the cloned repository.
532 subsequent revisions will be present in the cloned repository.
533 This option implies --pull, even on local repositories.
533 This option implies --pull, even on local repositories.
534
534
535 See pull for valid source format details.
535 See pull for valid source format details.
536
536
537 It is possible to specify an ssh:// URL as the destination, but no
537 It is possible to specify an ssh:// URL as the destination, but no
538 .hg/hgrc and working directory will be created on the remote side.
538 .hg/hgrc and working directory will be created on the remote side.
539 Look at the help text for the pull command for important details
539 Look at the help text for the pull command for important details
540 about ssh:// URLs.
540 about ssh:// URLs.
541 """
541 """
542 cmdutil.setremoteconfig(ui, opts)
542 cmdutil.setremoteconfig(ui, opts)
543 hg.clone(ui, source, dest,
543 hg.clone(ui, source, dest,
544 pull=opts['pull'],
544 pull=opts['pull'],
545 stream=opts['uncompressed'],
545 stream=opts['uncompressed'],
546 rev=opts['rev'],
546 rev=opts['rev'],
547 update=not opts['noupdate'])
547 update=not opts['noupdate'])
548
548
549 def commit(ui, repo, *pats, **opts):
549 def commit(ui, repo, *pats, **opts):
550 """commit the specified files or all outstanding changes
550 """commit the specified files or all outstanding changes
551
551
552 Commit changes to the given files into the repository.
552 Commit changes to the given files into the repository.
553
553
554 If a list of files is omitted, all changes reported by "hg status"
554 If a list of files is omitted, all changes reported by "hg status"
555 will be committed.
555 will be committed.
556
556
557 If you are committing the result of a merge, do not provide any
557 If you are committing the result of a merge, do not provide any
558 file names or -I/-X filters.
558 file names or -I/-X filters.
559
559
560 If no commit message is specified, the configured editor is started to
560 If no commit message is specified, the configured editor is started to
561 enter a message.
561 enter a message.
562
562
563 See 'hg help dates' for a list of formats valid for -d/--date.
563 See 'hg help dates' for a list of formats valid for -d/--date.
564 """
564 """
565 def commitfunc(ui, repo, files, message, match, opts):
565 def commitfunc(ui, repo, files, message, match, opts):
566 return repo.commit(files, message, opts['user'], opts['date'], match,
566 return repo.commit(files, message, opts['user'], opts['date'], match,
567 force_editor=opts.get('force_editor'))
567 force_editor=opts.get('force_editor'))
568
568
569 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
569 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
570 if not node:
570 if not node:
571 return
571 return
572 cl = repo.changelog
572 cl = repo.changelog
573 rev = cl.rev(node)
573 rev = cl.rev(node)
574 parents = cl.parentrevs(rev)
574 parents = cl.parentrevs(rev)
575 if rev - 1 in parents:
575 if rev - 1 in parents:
576 # one of the parents was the old tip
576 # one of the parents was the old tip
577 return
577 return
578 if (parents == (nullrev, nullrev) or
578 if (parents == (nullrev, nullrev) or
579 len(cl.heads(cl.node(parents[0]))) > 1 and
579 len(cl.heads(cl.node(parents[0]))) > 1 and
580 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
580 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
581 ui.status(_('created new head\n'))
581 ui.status(_('created new head\n'))
582
582
583 def copy(ui, repo, *pats, **opts):
583 def copy(ui, repo, *pats, **opts):
584 """mark files as copied for the next commit
584 """mark files as copied for the next commit
585
585
586 Mark dest as having copies of source files. If dest is a
586 Mark dest as having copies of source files. If dest is a
587 directory, copies are put in that directory. If dest is a file,
587 directory, copies are put in that directory. If dest is a file,
588 there can only be one source.
588 there can only be one source.
589
589
590 By default, this command copies the contents of files as they
590 By default, this command copies the contents of files as they
591 stand in the working directory. If invoked with --after, the
591 stand in the working directory. If invoked with --after, the
592 operation is recorded, but no copying is performed.
592 operation is recorded, but no copying is performed.
593
593
594 This command takes effect in the next commit. To undo a copy
594 This command takes effect in the next commit. To undo a copy
595 before that, see hg revert.
595 before that, see hg revert.
596 """
596 """
597 wlock = repo.wlock(False)
597 wlock = repo.wlock(False)
598 try:
598 try:
599 return cmdutil.copy(ui, repo, pats, opts)
599 return cmdutil.copy(ui, repo, pats, opts)
600 finally:
600 finally:
601 del wlock
601 del wlock
602
602
603 def debugancestor(ui, repo, *args):
603 def debugancestor(ui, repo, *args):
604 """find the ancestor revision of two revisions in a given index"""
604 """find the ancestor revision of two revisions in a given index"""
605 if len(args) == 3:
605 if len(args) == 3:
606 index, rev1, rev2 = args
606 index, rev1, rev2 = args
607 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
607 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
608 lookup = r.lookup
608 lookup = r.lookup
609 elif len(args) == 2:
609 elif len(args) == 2:
610 if not repo:
610 if not repo:
611 raise util.Abort(_("There is no Mercurial repository here "
611 raise util.Abort(_("There is no Mercurial repository here "
612 "(.hg not found)"))
612 "(.hg not found)"))
613 rev1, rev2 = args
613 rev1, rev2 = args
614 r = repo.changelog
614 r = repo.changelog
615 lookup = repo.lookup
615 lookup = repo.lookup
616 else:
616 else:
617 raise util.Abort(_('either two or three arguments required'))
617 raise util.Abort(_('either two or three arguments required'))
618 a = r.ancestor(lookup(rev1), lookup(rev2))
618 a = r.ancestor(lookup(rev1), lookup(rev2))
619 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
619 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
620
620
621 def debugcomplete(ui, cmd='', **opts):
621 def debugcomplete(ui, cmd='', **opts):
622 """returns the completion list associated with the given command"""
622 """returns the completion list associated with the given command"""
623
623
624 if opts['options']:
624 if opts['options']:
625 options = []
625 options = []
626 otables = [globalopts]
626 otables = [globalopts]
627 if cmd:
627 if cmd:
628 aliases, entry = cmdutil.findcmd(ui, cmd, table)
628 aliases, entry = cmdutil.findcmd(ui, cmd, table)
629 otables.append(entry[1])
629 otables.append(entry[1])
630 for t in otables:
630 for t in otables:
631 for o in t:
631 for o in t:
632 if o[0]:
632 if o[0]:
633 options.append('-%s' % o[0])
633 options.append('-%s' % o[0])
634 options.append('--%s' % o[1])
634 options.append('--%s' % o[1])
635 ui.write("%s\n" % "\n".join(options))
635 ui.write("%s\n" % "\n".join(options))
636 return
636 return
637
637
638 clist = cmdutil.findpossible(ui, cmd, table).keys()
638 clist = cmdutil.findpossible(ui, cmd, table).keys()
639 clist.sort()
639 clist.sort()
640 ui.write("%s\n" % "\n".join(clist))
640 ui.write("%s\n" % "\n".join(clist))
641
641
642 def debugfsinfo(ui, path = "."):
642 def debugfsinfo(ui, path = "."):
643 file('.debugfsinfo', 'w').write('')
643 file('.debugfsinfo', 'w').write('')
644 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
644 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
645 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
645 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
646 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
646 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
647 and 'yes' or 'no'))
647 and 'yes' or 'no'))
648 os.unlink('.debugfsinfo')
648 os.unlink('.debugfsinfo')
649
649
650 def debugrebuildstate(ui, repo, rev=""):
650 def debugrebuildstate(ui, repo, rev=""):
651 """rebuild the dirstate as it would look like for the given revision"""
651 """rebuild the dirstate as it would look like for the given revision"""
652 if rev == "":
652 if rev == "":
653 rev = repo.changelog.tip()
653 rev = repo.changelog.tip()
654 ctx = repo.changectx(rev)
654 ctx = repo.changectx(rev)
655 files = ctx.manifest()
655 files = ctx.manifest()
656 wlock = repo.wlock()
656 wlock = repo.wlock()
657 try:
657 try:
658 repo.dirstate.rebuild(rev, files)
658 repo.dirstate.rebuild(rev, files)
659 finally:
659 finally:
660 del wlock
660 del wlock
661
661
662 def debugcheckstate(ui, repo):
662 def debugcheckstate(ui, repo):
663 """validate the correctness of the current dirstate"""
663 """validate the correctness of the current dirstate"""
664 parent1, parent2 = repo.dirstate.parents()
664 parent1, parent2 = repo.dirstate.parents()
665 m1 = repo.changectx(parent1).manifest()
665 m1 = repo.changectx(parent1).manifest()
666 m2 = repo.changectx(parent2).manifest()
666 m2 = repo.changectx(parent2).manifest()
667 errors = 0
667 errors = 0
668 for f in repo.dirstate:
668 for f in repo.dirstate:
669 state = repo.dirstate[f]
669 state = repo.dirstate[f]
670 if state in "nr" and f not in m1:
670 if state in "nr" and f not in m1:
671 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
671 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
672 errors += 1
672 errors += 1
673 if state in "a" and f in m1:
673 if state in "a" and f in m1:
674 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
674 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
675 errors += 1
675 errors += 1
676 if state in "m" and f not in m1 and f not in m2:
676 if state in "m" and f not in m1 and f not in m2:
677 ui.warn(_("%s in state %s, but not in either manifest\n") %
677 ui.warn(_("%s in state %s, but not in either manifest\n") %
678 (f, state))
678 (f, state))
679 errors += 1
679 errors += 1
680 for f in m1:
680 for f in m1:
681 state = repo.dirstate[f]
681 state = repo.dirstate[f]
682 if state not in "nrm":
682 if state not in "nrm":
683 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
683 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
684 errors += 1
684 errors += 1
685 if errors:
685 if errors:
686 error = _(".hg/dirstate inconsistent with current parent's manifest")
686 error = _(".hg/dirstate inconsistent with current parent's manifest")
687 raise util.Abort(error)
687 raise util.Abort(error)
688
688
689 def showconfig(ui, repo, *values, **opts):
689 def showconfig(ui, repo, *values, **opts):
690 """show combined config settings from all hgrc files
690 """show combined config settings from all hgrc files
691
691
692 With no args, print names and values of all config items.
692 With no args, print names and values of all config items.
693
693
694 With one arg of the form section.name, print just the value of
694 With one arg of the form section.name, print just the value of
695 that config item.
695 that config item.
696
696
697 With multiple args, print names and values of all config items
697 With multiple args, print names and values of all config items
698 with matching section names."""
698 with matching section names."""
699
699
700 untrusted = bool(opts.get('untrusted'))
700 untrusted = bool(opts.get('untrusted'))
701 if values:
701 if values:
702 if len([v for v in values if '.' in v]) > 1:
702 if len([v for v in values if '.' in v]) > 1:
703 raise util.Abort(_('only one config item permitted'))
703 raise util.Abort(_('only one config item permitted'))
704 for section, name, value in ui.walkconfig(untrusted=untrusted):
704 for section, name, value in ui.walkconfig(untrusted=untrusted):
705 sectname = section + '.' + name
705 sectname = section + '.' + name
706 if values:
706 if values:
707 for v in values:
707 for v in values:
708 if v == section:
708 if v == section:
709 ui.write('%s=%s\n' % (sectname, value))
709 ui.write('%s=%s\n' % (sectname, value))
710 elif v == sectname:
710 elif v == sectname:
711 ui.write(value, '\n')
711 ui.write(value, '\n')
712 else:
712 else:
713 ui.write('%s=%s\n' % (sectname, value))
713 ui.write('%s=%s\n' % (sectname, value))
714
714
715 def debugsetparents(ui, repo, rev1, rev2=None):
715 def debugsetparents(ui, repo, rev1, rev2=None):
716 """manually set the parents of the current working directory
716 """manually set the parents of the current working directory
717
717
718 This is useful for writing repository conversion tools, but should
718 This is useful for writing repository conversion tools, but should
719 be used with care.
719 be used with care.
720 """
720 """
721
721
722 if not rev2:
722 if not rev2:
723 rev2 = hex(nullid)
723 rev2 = hex(nullid)
724
724
725 wlock = repo.wlock()
725 wlock = repo.wlock()
726 try:
726 try:
727 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
727 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
728 finally:
728 finally:
729 del wlock
729 del wlock
730
730
731 def debugstate(ui, repo, nodates=None):
731 def debugstate(ui, repo, nodates=None):
732 """show the contents of the current dirstate"""
732 """show the contents of the current dirstate"""
733 k = repo.dirstate._map.items()
733 k = repo.dirstate._map.items()
734 k.sort()
734 k.sort()
735 timestr = ""
735 timestr = ""
736 showdate = not nodates
736 showdate = not nodates
737 for file_, ent in k:
737 for file_, ent in k:
738 if showdate:
738 if showdate:
739 if ent[3] == -1:
739 if ent[3] == -1:
740 # Pad or slice to locale representation
740 # Pad or slice to locale representation
741 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
741 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
742 timestr = 'unset'
742 timestr = 'unset'
743 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
743 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
744 else:
744 else:
745 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
745 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
746 if ent[1] & 020000:
746 if ent[1] & 020000:
747 mode = 'lnk'
747 mode = 'lnk'
748 else:
748 else:
749 mode = '%3o' % (ent[1] & 0777)
749 mode = '%3o' % (ent[1] & 0777)
750 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
750 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
751 for f in repo.dirstate.copies():
751 for f in repo.dirstate.copies():
752 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
752 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
753
753
754 def debugdata(ui, file_, rev):
754 def debugdata(ui, file_, rev):
755 """dump the contents of a data file revision"""
755 """dump the contents of a data file revision"""
756 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
756 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
757 try:
757 try:
758 ui.write(r.revision(r.lookup(rev)))
758 ui.write(r.revision(r.lookup(rev)))
759 except KeyError:
759 except KeyError:
760 raise util.Abort(_('invalid revision identifier %s') % rev)
760 raise util.Abort(_('invalid revision identifier %s') % rev)
761
761
762 def debugdate(ui, date, range=None, **opts):
762 def debugdate(ui, date, range=None, **opts):
763 """parse and display a date"""
763 """parse and display a date"""
764 if opts["extended"]:
764 if opts["extended"]:
765 d = util.parsedate(date, util.extendeddateformats)
765 d = util.parsedate(date, util.extendeddateformats)
766 else:
766 else:
767 d = util.parsedate(date)
767 d = util.parsedate(date)
768 ui.write("internal: %s %s\n" % d)
768 ui.write("internal: %s %s\n" % d)
769 ui.write("standard: %s\n" % util.datestr(d))
769 ui.write("standard: %s\n" % util.datestr(d))
770 if range:
770 if range:
771 m = util.matchdate(range)
771 m = util.matchdate(range)
772 ui.write("match: %s\n" % m(d[0]))
772 ui.write("match: %s\n" % m(d[0]))
773
773
774 def debugindex(ui, file_):
774 def debugindex(ui, file_):
775 """dump the contents of an index file"""
775 """dump the contents of an index file"""
776 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
776 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
777 ui.write(" rev offset length base linkrev" +
777 ui.write(" rev offset length base linkrev" +
778 " nodeid p1 p2\n")
778 " nodeid p1 p2\n")
779 for i in xrange(r.count()):
779 for i in xrange(r.count()):
780 node = r.node(i)
780 node = r.node(i)
781 try:
781 try:
782 pp = r.parents(node)
782 pp = r.parents(node)
783 except:
783 except:
784 pp = [nullid, nullid]
784 pp = [nullid, nullid]
785 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
785 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
786 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
786 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
787 short(node), short(pp[0]), short(pp[1])))
787 short(node), short(pp[0]), short(pp[1])))
788
788
789 def debugindexdot(ui, file_):
789 def debugindexdot(ui, file_):
790 """dump an index DAG as a .dot file"""
790 """dump an index DAG as a .dot file"""
791 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
791 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
792 ui.write("digraph G {\n")
792 ui.write("digraph G {\n")
793 for i in xrange(r.count()):
793 for i in xrange(r.count()):
794 node = r.node(i)
794 node = r.node(i)
795 pp = r.parents(node)
795 pp = r.parents(node)
796 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
796 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
797 if pp[1] != nullid:
797 if pp[1] != nullid:
798 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
798 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
799 ui.write("}\n")
799 ui.write("}\n")
800
800
801 def debuginstall(ui):
801 def debuginstall(ui):
802 '''test Mercurial installation'''
802 '''test Mercurial installation'''
803
803
804 def writetemp(contents):
804 def writetemp(contents):
805 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
805 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
806 f = os.fdopen(fd, "wb")
806 f = os.fdopen(fd, "wb")
807 f.write(contents)
807 f.write(contents)
808 f.close()
808 f.close()
809 return name
809 return name
810
810
811 problems = 0
811 problems = 0
812
812
813 # encoding
813 # encoding
814 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
814 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
815 try:
815 try:
816 util.fromlocal("test")
816 util.fromlocal("test")
817 except util.Abort, inst:
817 except util.Abort, inst:
818 ui.write(" %s\n" % inst)
818 ui.write(" %s\n" % inst)
819 ui.write(_(" (check that your locale is properly set)\n"))
819 ui.write(_(" (check that your locale is properly set)\n"))
820 problems += 1
820 problems += 1
821
821
822 # compiled modules
822 # compiled modules
823 ui.status(_("Checking extensions...\n"))
823 ui.status(_("Checking extensions...\n"))
824 try:
824 try:
825 import bdiff, mpatch, base85
825 import bdiff, mpatch, base85
826 except Exception, inst:
826 except Exception, inst:
827 ui.write(" %s\n" % inst)
827 ui.write(" %s\n" % inst)
828 ui.write(_(" One or more extensions could not be found"))
828 ui.write(_(" One or more extensions could not be found"))
829 ui.write(_(" (check that you compiled the extensions)\n"))
829 ui.write(_(" (check that you compiled the extensions)\n"))
830 problems += 1
830 problems += 1
831
831
832 # templates
832 # templates
833 ui.status(_("Checking templates...\n"))
833 ui.status(_("Checking templates...\n"))
834 try:
834 try:
835 import templater
835 import templater
836 t = templater.templater(templater.templatepath("map-cmdline.default"))
836 t = templater.templater(templater.templatepath("map-cmdline.default"))
837 except Exception, inst:
837 except Exception, inst:
838 ui.write(" %s\n" % inst)
838 ui.write(" %s\n" % inst)
839 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
839 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
840 problems += 1
840 problems += 1
841
841
842 # patch
842 # patch
843 ui.status(_("Checking patch...\n"))
843 ui.status(_("Checking patch...\n"))
844 patchproblems = 0
844 patchproblems = 0
845 a = "1\n2\n3\n4\n"
845 a = "1\n2\n3\n4\n"
846 b = "1\n2\n3\ninsert\n4\n"
846 b = "1\n2\n3\ninsert\n4\n"
847 fa = writetemp(a)
847 fa = writetemp(a)
848 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
848 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
849 os.path.basename(fa))
849 os.path.basename(fa))
850 fd = writetemp(d)
850 fd = writetemp(d)
851
851
852 files = {}
852 files = {}
853 try:
853 try:
854 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
854 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
855 except util.Abort, e:
855 except util.Abort, e:
856 ui.write(_(" patch call failed:\n"))
856 ui.write(_(" patch call failed:\n"))
857 ui.write(" " + str(e) + "\n")
857 ui.write(" " + str(e) + "\n")
858 patchproblems += 1
858 patchproblems += 1
859 else:
859 else:
860 if list(files) != [os.path.basename(fa)]:
860 if list(files) != [os.path.basename(fa)]:
861 ui.write(_(" unexpected patch output!\n"))
861 ui.write(_(" unexpected patch output!\n"))
862 patchproblems += 1
862 patchproblems += 1
863 a = file(fa).read()
863 a = file(fa).read()
864 if a != b:
864 if a != b:
865 ui.write(_(" patch test failed!\n"))
865 ui.write(_(" patch test failed!\n"))
866 patchproblems += 1
866 patchproblems += 1
867
867
868 if patchproblems:
868 if patchproblems:
869 if ui.config('ui', 'patch'):
869 if ui.config('ui', 'patch'):
870 ui.write(_(" (Current patch tool may be incompatible with patch,"
870 ui.write(_(" (Current patch tool may be incompatible with patch,"
871 " or misconfigured. Please check your .hgrc file)\n"))
871 " or misconfigured. Please check your .hgrc file)\n"))
872 else:
872 else:
873 ui.write(_(" Internal patcher failure, please report this error"
873 ui.write(_(" Internal patcher failure, please report this error"
874 " to http://www.selenic.com/mercurial/bts\n"))
874 " to http://www.selenic.com/mercurial/bts\n"))
875 problems += patchproblems
875 problems += patchproblems
876
876
877 os.unlink(fa)
877 os.unlink(fa)
878 os.unlink(fd)
878 os.unlink(fd)
879
879
880 # editor
880 # editor
881 ui.status(_("Checking commit editor...\n"))
881 ui.status(_("Checking commit editor...\n"))
882 editor = ui.geteditor()
882 editor = ui.geteditor()
883 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
883 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
884 if not cmdpath:
884 if not cmdpath:
885 if editor == 'vi':
885 if editor == 'vi':
886 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
886 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
887 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
887 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
888 else:
888 else:
889 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
889 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
890 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
890 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
891 problems += 1
891 problems += 1
892
892
893 # check username
893 # check username
894 ui.status(_("Checking username...\n"))
894 ui.status(_("Checking username...\n"))
895 user = os.environ.get("HGUSER")
895 user = os.environ.get("HGUSER")
896 if user is None:
896 if user is None:
897 user = ui.config("ui", "username")
897 user = ui.config("ui", "username")
898 if user is None:
898 if user is None:
899 user = os.environ.get("EMAIL")
899 user = os.environ.get("EMAIL")
900 if not user:
900 if not user:
901 ui.warn(" ")
901 ui.warn(" ")
902 ui.username()
902 ui.username()
903 ui.write(_(" (specify a username in your .hgrc file)\n"))
903 ui.write(_(" (specify a username in your .hgrc file)\n"))
904
904
905 if not problems:
905 if not problems:
906 ui.status(_("No problems detected\n"))
906 ui.status(_("No problems detected\n"))
907 else:
907 else:
908 ui.write(_("%s problems detected,"
908 ui.write(_("%s problems detected,"
909 " please check your install!\n") % problems)
909 " please check your install!\n") % problems)
910
910
911 return problems
911 return problems
912
912
913 def debugrename(ui, repo, file1, *pats, **opts):
913 def debugrename(ui, repo, file1, *pats, **opts):
914 """dump rename information"""
914 """dump rename information"""
915
915
916 ctx = repo.changectx(opts.get('rev', 'tip'))
916 ctx = repo.changectx(opts.get('rev', 'tip'))
917 m = cmdutil.match(repo, (file1,) + pats, opts)
917 m = cmdutil.match(repo, (file1,) + pats, opts)
918 for abs in repo.walk(m, ctx.node()):
918 for abs in repo.walk(m, ctx.node()):
919 fctx = ctx.filectx(abs)
919 fctx = ctx.filectx(abs)
920 o = fctx.filelog().renamed(fctx.filenode())
920 o = fctx.filelog().renamed(fctx.filenode())
921 rel = m.rel(abs)
921 rel = m.rel(abs)
922 if o:
922 if o:
923 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
923 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
924 else:
924 else:
925 ui.write(_("%s not renamed\n") % rel)
925 ui.write(_("%s not renamed\n") % rel)
926
926
927 def debugwalk(ui, repo, *pats, **opts):
927 def debugwalk(ui, repo, *pats, **opts):
928 """show how files match on given patterns"""
928 """show how files match on given patterns"""
929 m = cmdutil.match(repo, pats, opts)
929 m = cmdutil.match(repo, pats, opts)
930 items = list(repo.walk(m))
930 items = list(repo.walk(m))
931 if not items:
931 if not items:
932 return
932 return
933 fmt = 'f %%-%ds %%-%ds %%s' % (
933 fmt = 'f %%-%ds %%-%ds %%s' % (
934 max([len(abs) for abs in items]),
934 max([len(abs) for abs in items]),
935 max([len(m.rel(abs)) for abs in items]))
935 max([len(m.rel(abs)) for abs in items]))
936 for abs in items:
936 for abs in items:
937 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
937 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
938 ui.write("%s\n" % line.rstrip())
938 ui.write("%s\n" % line.rstrip())
939
939
940 def diff(ui, repo, *pats, **opts):
940 def diff(ui, repo, *pats, **opts):
941 """diff repository (or selected files)
941 """diff repository (or selected files)
942
942
943 Show differences between revisions for the specified files.
943 Show differences between revisions for the specified files.
944
944
945 Differences between files are shown using the unified diff format.
945 Differences between files are shown using the unified diff format.
946
946
947 NOTE: diff may generate unexpected results for merges, as it will
947 NOTE: diff may generate unexpected results for merges, as it will
948 default to comparing against the working directory's first parent
948 default to comparing against the working directory's first parent
949 changeset if no revisions are specified.
949 changeset if no revisions are specified.
950
950
951 When two revision arguments are given, then changes are shown
951 When two revision arguments are given, then changes are shown
952 between those revisions. If only one revision is specified then
952 between those revisions. If only one revision is specified then
953 that revision is compared to the working directory, and, when no
953 that revision is compared to the working directory, and, when no
954 revisions are specified, the working directory files are compared
954 revisions are specified, the working directory files are compared
955 to its parent.
955 to its parent.
956
956
957 Without the -a option, diff will avoid generating diffs of files
957 Without the -a option, diff will avoid generating diffs of files
958 it detects as binary. With -a, diff will generate a diff anyway,
958 it detects as binary. With -a, diff will generate a diff anyway,
959 probably with undesirable results.
959 probably with undesirable results.
960 """
960 """
961 node1, node2 = cmdutil.revpair(repo, opts['rev'])
961 node1, node2 = cmdutil.revpair(repo, opts['rev'])
962
962
963 m = cmdutil.match(repo, pats, opts)
963 m = cmdutil.match(repo, pats, opts)
964 patch.diff(repo, node1, node2, m.files(), match=m,
964 patch.diff(repo, node1, node2, m.files(), match=m,
965 opts=patch.diffopts(ui, opts))
965 opts=patch.diffopts(ui, opts))
966
966
967 def export(ui, repo, *changesets, **opts):
967 def export(ui, repo, *changesets, **opts):
968 """dump the header and diffs for one or more changesets
968 """dump the header and diffs for one or more changesets
969
969
970 Print the changeset header and diffs for one or more revisions.
970 Print the changeset header and diffs for one or more revisions.
971
971
972 The information shown in the changeset header is: author,
972 The information shown in the changeset header is: author,
973 changeset hash, parent(s) and commit comment.
973 changeset hash, parent(s) and commit comment.
974
974
975 NOTE: export may generate unexpected diff output for merge changesets,
975 NOTE: export may generate unexpected diff output for merge changesets,
976 as it will compare the merge changeset against its first parent only.
976 as it will compare the merge changeset against its first parent only.
977
977
978 Output may be to a file, in which case the name of the file is
978 Output may be to a file, in which case the name of the file is
979 given using a format string. The formatting rules are as follows:
979 given using a format string. The formatting rules are as follows:
980
980
981 %% literal "%" character
981 %% literal "%" character
982 %H changeset hash (40 bytes of hexadecimal)
982 %H changeset hash (40 bytes of hexadecimal)
983 %N number of patches being generated
983 %N number of patches being generated
984 %R changeset revision number
984 %R changeset revision number
985 %b basename of the exporting repository
985 %b basename of the exporting repository
986 %h short-form changeset hash (12 bytes of hexadecimal)
986 %h short-form changeset hash (12 bytes of hexadecimal)
987 %n zero-padded sequence number, starting at 1
987 %n zero-padded sequence number, starting at 1
988 %r zero-padded changeset revision number
988 %r zero-padded changeset revision number
989
989
990 Without the -a option, export will avoid generating diffs of files
990 Without the -a option, export will avoid generating diffs of files
991 it detects as binary. With -a, export will generate a diff anyway,
991 it detects as binary. With -a, export will generate a diff anyway,
992 probably with undesirable results.
992 probably with undesirable results.
993
993
994 With the --switch-parent option, the diff will be against the second
994 With the --switch-parent option, the diff will be against the second
995 parent. It can be useful to review a merge.
995 parent. It can be useful to review a merge.
996 """
996 """
997 if not changesets:
997 if not changesets:
998 raise util.Abort(_("export requires at least one changeset"))
998 raise util.Abort(_("export requires at least one changeset"))
999 revs = cmdutil.revrange(repo, changesets)
999 revs = cmdutil.revrange(repo, changesets)
1000 if len(revs) > 1:
1000 if len(revs) > 1:
1001 ui.note(_('exporting patches:\n'))
1001 ui.note(_('exporting patches:\n'))
1002 else:
1002 else:
1003 ui.note(_('exporting patch:\n'))
1003 ui.note(_('exporting patch:\n'))
1004 patch.export(repo, revs, template=opts['output'],
1004 patch.export(repo, revs, template=opts['output'],
1005 switch_parent=opts['switch_parent'],
1005 switch_parent=opts['switch_parent'],
1006 opts=patch.diffopts(ui, opts))
1006 opts=patch.diffopts(ui, opts))
1007
1007
1008 def grep(ui, repo, pattern, *pats, **opts):
1008 def grep(ui, repo, pattern, *pats, **opts):
1009 """search for a pattern in specified files and revisions
1009 """search for a pattern in specified files and revisions
1010
1010
1011 Search revisions of files for a regular expression.
1011 Search revisions of files for a regular expression.
1012
1012
1013 This command behaves differently than Unix grep. It only accepts
1013 This command behaves differently than Unix grep. It only accepts
1014 Python/Perl regexps. It searches repository history, not the
1014 Python/Perl regexps. It searches repository history, not the
1015 working directory. It always prints the revision number in which
1015 working directory. It always prints the revision number in which
1016 a match appears.
1016 a match appears.
1017
1017
1018 By default, grep only prints output for the first revision of a
1018 By default, grep only prints output for the first revision of a
1019 file in which it finds a match. To get it to print every revision
1019 file in which it finds a match. To get it to print every revision
1020 that contains a change in match status ("-" for a match that
1020 that contains a change in match status ("-" for a match that
1021 becomes a non-match, or "+" for a non-match that becomes a match),
1021 becomes a non-match, or "+" for a non-match that becomes a match),
1022 use the --all flag.
1022 use the --all flag.
1023 """
1023 """
1024 reflags = 0
1024 reflags = 0
1025 if opts['ignore_case']:
1025 if opts['ignore_case']:
1026 reflags |= re.I
1026 reflags |= re.I
1027 try:
1027 try:
1028 regexp = re.compile(pattern, reflags)
1028 regexp = re.compile(pattern, reflags)
1029 except Exception, inst:
1029 except Exception, inst:
1030 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1030 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1031 return None
1031 return None
1032 sep, eol = ':', '\n'
1032 sep, eol = ':', '\n'
1033 if opts['print0']:
1033 if opts['print0']:
1034 sep = eol = '\0'
1034 sep = eol = '\0'
1035
1035
1036 fcache = {}
1036 fcache = {}
1037 def getfile(fn):
1037 def getfile(fn):
1038 if fn not in fcache:
1038 if fn not in fcache:
1039 fcache[fn] = repo.file(fn)
1039 fcache[fn] = repo.file(fn)
1040 return fcache[fn]
1040 return fcache[fn]
1041
1041
1042 def matchlines(body):
1042 def matchlines(body):
1043 begin = 0
1043 begin = 0
1044 linenum = 0
1044 linenum = 0
1045 while True:
1045 while True:
1046 match = regexp.search(body, begin)
1046 match = regexp.search(body, begin)
1047 if not match:
1047 if not match:
1048 break
1048 break
1049 mstart, mend = match.span()
1049 mstart, mend = match.span()
1050 linenum += body.count('\n', begin, mstart) + 1
1050 linenum += body.count('\n', begin, mstart) + 1
1051 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1051 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1052 lend = body.find('\n', mend)
1052 lend = body.find('\n', mend)
1053 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1053 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1054 begin = lend + 1
1054 begin = lend + 1
1055
1055
1056 class linestate(object):
1056 class linestate(object):
1057 def __init__(self, line, linenum, colstart, colend):
1057 def __init__(self, line, linenum, colstart, colend):
1058 self.line = line
1058 self.line = line
1059 self.linenum = linenum
1059 self.linenum = linenum
1060 self.colstart = colstart
1060 self.colstart = colstart
1061 self.colend = colend
1061 self.colend = colend
1062
1062
1063 def __hash__(self):
1063 def __hash__(self):
1064 return hash((self.linenum, self.line))
1064 return hash((self.linenum, self.line))
1065
1065
1066 def __eq__(self, other):
1066 def __eq__(self, other):
1067 return self.line == other.line
1067 return self.line == other.line
1068
1068
1069 matches = {}
1069 matches = {}
1070 copies = {}
1070 copies = {}
1071 def grepbody(fn, rev, body):
1071 def grepbody(fn, rev, body):
1072 matches[rev].setdefault(fn, [])
1072 matches[rev].setdefault(fn, [])
1073 m = matches[rev][fn]
1073 m = matches[rev][fn]
1074 for lnum, cstart, cend, line in matchlines(body):
1074 for lnum, cstart, cend, line in matchlines(body):
1075 s = linestate(line, lnum, cstart, cend)
1075 s = linestate(line, lnum, cstart, cend)
1076 m.append(s)
1076 m.append(s)
1077
1077
1078 def difflinestates(a, b):
1078 def difflinestates(a, b):
1079 sm = difflib.SequenceMatcher(None, a, b)
1079 sm = difflib.SequenceMatcher(None, a, b)
1080 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1080 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1081 if tag == 'insert':
1081 if tag == 'insert':
1082 for i in xrange(blo, bhi):
1082 for i in xrange(blo, bhi):
1083 yield ('+', b[i])
1083 yield ('+', b[i])
1084 elif tag == 'delete':
1084 elif tag == 'delete':
1085 for i in xrange(alo, ahi):
1085 for i in xrange(alo, ahi):
1086 yield ('-', a[i])
1086 yield ('-', a[i])
1087 elif tag == 'replace':
1087 elif tag == 'replace':
1088 for i in xrange(alo, ahi):
1088 for i in xrange(alo, ahi):
1089 yield ('-', a[i])
1089 yield ('-', a[i])
1090 for i in xrange(blo, bhi):
1090 for i in xrange(blo, bhi):
1091 yield ('+', b[i])
1091 yield ('+', b[i])
1092
1092
1093 prev = {}
1093 prev = {}
1094 def display(fn, rev, states, prevstates):
1094 def display(fn, rev, states, prevstates):
1095 datefunc = ui.quiet and util.shortdate or util.datestr
1095 datefunc = ui.quiet and util.shortdate or util.datestr
1096 found = False
1096 found = False
1097 filerevmatches = {}
1097 filerevmatches = {}
1098 r = prev.get(fn, -1)
1098 r = prev.get(fn, -1)
1099 if opts['all']:
1099 if opts['all']:
1100 iter = difflinestates(states, prevstates)
1100 iter = difflinestates(states, prevstates)
1101 else:
1101 else:
1102 iter = [('', l) for l in prevstates]
1102 iter = [('', l) for l in prevstates]
1103 for change, l in iter:
1103 for change, l in iter:
1104 cols = [fn, str(r)]
1104 cols = [fn, str(r)]
1105 if opts['line_number']:
1105 if opts['line_number']:
1106 cols.append(str(l.linenum))
1106 cols.append(str(l.linenum))
1107 if opts['all']:
1107 if opts['all']:
1108 cols.append(change)
1108 cols.append(change)
1109 if opts['user']:
1109 if opts['user']:
1110 cols.append(ui.shortuser(get(r)[1]))
1110 cols.append(ui.shortuser(get(r)[1]))
1111 if opts.get('date'):
1111 if opts.get('date'):
1112 cols.append(datefunc(get(r)[2]))
1112 cols.append(datefunc(get(r)[2]))
1113 if opts['files_with_matches']:
1113 if opts['files_with_matches']:
1114 c = (fn, r)
1114 c = (fn, r)
1115 if c in filerevmatches:
1115 if c in filerevmatches:
1116 continue
1116 continue
1117 filerevmatches[c] = 1
1117 filerevmatches[c] = 1
1118 else:
1118 else:
1119 cols.append(l.line)
1119 cols.append(l.line)
1120 ui.write(sep.join(cols), eol)
1120 ui.write(sep.join(cols), eol)
1121 found = True
1121 found = True
1122 return found
1122 return found
1123
1123
1124 fstate = {}
1124 fstate = {}
1125 skip = {}
1125 skip = {}
1126 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1126 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1127 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1127 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1128 found = False
1128 found = False
1129 follow = opts.get('follow')
1129 follow = opts.get('follow')
1130 for st, rev, fns in changeiter:
1130 for st, rev, fns in changeiter:
1131 if st == 'window':
1131 if st == 'window':
1132 matches.clear()
1132 matches.clear()
1133 elif st == 'add':
1133 elif st == 'add':
1134 ctx = repo.changectx(rev)
1134 ctx = repo.changectx(rev)
1135 matches[rev] = {}
1135 matches[rev] = {}
1136 for fn in fns:
1136 for fn in fns:
1137 if fn in skip:
1137 if fn in skip:
1138 continue
1138 continue
1139 try:
1139 try:
1140 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1140 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1141 fstate.setdefault(fn, [])
1141 fstate.setdefault(fn, [])
1142 if follow:
1142 if follow:
1143 copied = getfile(fn).renamed(ctx.filenode(fn))
1143 copied = getfile(fn).renamed(ctx.filenode(fn))
1144 if copied:
1144 if copied:
1145 copies.setdefault(rev, {})[fn] = copied[0]
1145 copies.setdefault(rev, {})[fn] = copied[0]
1146 except revlog.LookupError:
1146 except revlog.LookupError:
1147 pass
1147 pass
1148 elif st == 'iter':
1148 elif st == 'iter':
1149 states = matches[rev].items()
1149 states = matches[rev].items()
1150 states.sort()
1150 states.sort()
1151 for fn, m in states:
1151 for fn, m in states:
1152 copy = copies.get(rev, {}).get(fn)
1152 copy = copies.get(rev, {}).get(fn)
1153 if fn in skip:
1153 if fn in skip:
1154 if copy:
1154 if copy:
1155 skip[copy] = True
1155 skip[copy] = True
1156 continue
1156 continue
1157 if fn in prev or fstate[fn]:
1157 if fn in prev or fstate[fn]:
1158 r = display(fn, rev, m, fstate[fn])
1158 r = display(fn, rev, m, fstate[fn])
1159 found = found or r
1159 found = found or r
1160 if r and not opts['all']:
1160 if r and not opts['all']:
1161 skip[fn] = True
1161 skip[fn] = True
1162 if copy:
1162 if copy:
1163 skip[copy] = True
1163 skip[copy] = True
1164 fstate[fn] = m
1164 fstate[fn] = m
1165 if copy:
1165 if copy:
1166 fstate[copy] = m
1166 fstate[copy] = m
1167 prev[fn] = rev
1167 prev[fn] = rev
1168
1168
1169 fstate = fstate.items()
1169 fstate = fstate.items()
1170 fstate.sort()
1170 fstate.sort()
1171 for fn, state in fstate:
1171 for fn, state in fstate:
1172 if fn in skip:
1172 if fn in skip:
1173 continue
1173 continue
1174 if fn not in copies.get(prev[fn], {}):
1174 if fn not in copies.get(prev[fn], {}):
1175 found = display(fn, rev, {}, state) or found
1175 found = display(fn, rev, {}, state) or found
1176 return (not found and 1) or 0
1176 return (not found and 1) or 0
1177
1177
1178 def heads(ui, repo, *branchrevs, **opts):
1178 def heads(ui, repo, *branchrevs, **opts):
1179 """show current repository heads or show branch heads
1179 """show current repository heads or show branch heads
1180
1180
1181 With no arguments, show all repository head changesets.
1181 With no arguments, show all repository head changesets.
1182
1182
1183 If branch or revisions names are given this will show the heads of
1183 If branch or revisions names are given this will show the heads of
1184 the specified branches or the branches those revisions are tagged
1184 the specified branches or the branches those revisions are tagged
1185 with.
1185 with.
1186
1186
1187 Repository "heads" are changesets that don't have child
1187 Repository "heads" are changesets that don't have child
1188 changesets. They are where development generally takes place and
1188 changesets. They are where development generally takes place and
1189 are the usual targets for update and merge operations.
1189 are the usual targets for update and merge operations.
1190
1190
1191 Branch heads are changesets that have a given branch tag, but have
1191 Branch heads are changesets that have a given branch tag, but have
1192 no child changesets with that tag. They are usually where
1192 no child changesets with that tag. They are usually where
1193 development on the given branch takes place.
1193 development on the given branch takes place.
1194 """
1194 """
1195 if opts['rev']:
1195 if opts['rev']:
1196 start = repo.lookup(opts['rev'])
1196 start = repo.lookup(opts['rev'])
1197 else:
1197 else:
1198 start = None
1198 start = None
1199 if not branchrevs:
1199 if not branchrevs:
1200 # Assume we're looking repo-wide heads if no revs were specified.
1200 # Assume we're looking repo-wide heads if no revs were specified.
1201 heads = repo.heads(start)
1201 heads = repo.heads(start)
1202 else:
1202 else:
1203 heads = []
1203 heads = []
1204 visitedset = util.set()
1204 visitedset = util.set()
1205 for branchrev in branchrevs:
1205 for branchrev in branchrevs:
1206 branch = repo.changectx(branchrev).branch()
1206 branch = repo.changectx(branchrev).branch()
1207 if branch in visitedset:
1207 if branch in visitedset:
1208 continue
1208 continue
1209 visitedset.add(branch)
1209 visitedset.add(branch)
1210 bheads = repo.branchheads(branch, start)
1210 bheads = repo.branchheads(branch, start)
1211 if not bheads:
1211 if not bheads:
1212 if branch != branchrev:
1212 if branch != branchrev:
1213 ui.warn(_("no changes on branch %s containing %s are "
1213 ui.warn(_("no changes on branch %s containing %s are "
1214 "reachable from %s\n")
1214 "reachable from %s\n")
1215 % (branch, branchrev, opts['rev']))
1215 % (branch, branchrev, opts['rev']))
1216 else:
1216 else:
1217 ui.warn(_("no changes on branch %s are reachable from %s\n")
1217 ui.warn(_("no changes on branch %s are reachable from %s\n")
1218 % (branch, opts['rev']))
1218 % (branch, opts['rev']))
1219 heads.extend(bheads)
1219 heads.extend(bheads)
1220 if not heads:
1220 if not heads:
1221 return 1
1221 return 1
1222 displayer = cmdutil.show_changeset(ui, repo, opts)
1222 displayer = cmdutil.show_changeset(ui, repo, opts)
1223 for n in heads:
1223 for n in heads:
1224 displayer.show(changenode=n)
1224 displayer.show(changenode=n)
1225
1225
1226 def help_(ui, name=None, with_version=False):
1226 def help_(ui, name=None, with_version=False):
1227 """show help for a command, extension, or list of commands
1227 """show help for a command, extension, or list of commands
1228
1228
1229 With no arguments, print a list of commands and short help.
1229 With no arguments, print a list of commands and short help.
1230
1230
1231 Given a command name, print help for that command.
1231 Given a command name, print help for that command.
1232
1232
1233 Given an extension name, print help for that extension, and the
1233 Given an extension name, print help for that extension, and the
1234 commands it provides."""
1234 commands it provides."""
1235 option_lists = []
1235 option_lists = []
1236
1236
1237 def addglobalopts(aliases):
1237 def addglobalopts(aliases):
1238 if ui.verbose:
1238 if ui.verbose:
1239 option_lists.append((_("global options:"), globalopts))
1239 option_lists.append((_("global options:"), globalopts))
1240 if name == 'shortlist':
1240 if name == 'shortlist':
1241 option_lists.append((_('use "hg help" for the full list '
1241 option_lists.append((_('use "hg help" for the full list '
1242 'of commands'), ()))
1242 'of commands'), ()))
1243 else:
1243 else:
1244 if name == 'shortlist':
1244 if name == 'shortlist':
1245 msg = _('use "hg help" for the full list of commands '
1245 msg = _('use "hg help" for the full list of commands '
1246 'or "hg -v" for details')
1246 'or "hg -v" for details')
1247 elif aliases:
1247 elif aliases:
1248 msg = _('use "hg -v help%s" to show aliases and '
1248 msg = _('use "hg -v help%s" to show aliases and '
1249 'global options') % (name and " " + name or "")
1249 'global options') % (name and " " + name or "")
1250 else:
1250 else:
1251 msg = _('use "hg -v help %s" to show global options') % name
1251 msg = _('use "hg -v help %s" to show global options') % name
1252 option_lists.append((msg, ()))
1252 option_lists.append((msg, ()))
1253
1253
1254 def helpcmd(name):
1254 def helpcmd(name):
1255 if with_version:
1255 if with_version:
1256 version_(ui)
1256 version_(ui)
1257 ui.write('\n')
1257 ui.write('\n')
1258 aliases, i = cmdutil.findcmd(ui, name, table)
1258 aliases, i = cmdutil.findcmd(ui, name, table)
1259 # synopsis
1259 # synopsis
1260 ui.write("%s\n" % i[2])
1260 ui.write("%s\n" % i[2])
1261
1261
1262 # aliases
1262 # aliases
1263 if not ui.quiet and len(aliases) > 1:
1263 if not ui.quiet and len(aliases) > 1:
1264 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1264 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1265
1265
1266 # description
1266 # description
1267 doc = i[0].__doc__
1267 doc = i[0].__doc__
1268 if not doc:
1268 if not doc:
1269 doc = _("(No help text available)")
1269 doc = _("(No help text available)")
1270 if ui.quiet:
1270 if ui.quiet:
1271 doc = doc.splitlines(0)[0]
1271 doc = doc.splitlines(0)[0]
1272 ui.write("\n%s\n" % doc.rstrip())
1272 ui.write("\n%s\n" % doc.rstrip())
1273
1273
1274 if not ui.quiet:
1274 if not ui.quiet:
1275 # options
1275 # options
1276 if i[1]:
1276 if i[1]:
1277 option_lists.append((_("options:\n"), i[1]))
1277 option_lists.append((_("options:\n"), i[1]))
1278
1278
1279 addglobalopts(False)
1279 addglobalopts(False)
1280
1280
1281 def helplist(header, select=None):
1281 def helplist(header, select=None):
1282 h = {}
1282 h = {}
1283 cmds = {}
1283 cmds = {}
1284 for c, e in table.items():
1284 for c, e in table.items():
1285 f = c.split("|", 1)[0]
1285 f = c.split("|", 1)[0]
1286 if select and not select(f):
1286 if select and not select(f):
1287 continue
1287 continue
1288 if name == "shortlist" and not f.startswith("^"):
1288 if name == "shortlist" and not f.startswith("^"):
1289 continue
1289 continue
1290 f = f.lstrip("^")
1290 f = f.lstrip("^")
1291 if not ui.debugflag and f.startswith("debug"):
1291 if not ui.debugflag and f.startswith("debug"):
1292 continue
1292 continue
1293 doc = e[0].__doc__
1293 doc = e[0].__doc__
1294 if not doc:
1294 if not doc:
1295 doc = _("(No help text available)")
1295 doc = _("(No help text available)")
1296 h[f] = doc.splitlines(0)[0].rstrip()
1296 h[f] = doc.splitlines(0)[0].rstrip()
1297 cmds[f] = c.lstrip("^")
1297 cmds[f] = c.lstrip("^")
1298
1298
1299 if not h:
1299 if not h:
1300 ui.status(_('no commands defined\n'))
1300 ui.status(_('no commands defined\n'))
1301 return
1301 return
1302
1302
1303 ui.status(header)
1303 ui.status(header)
1304 fns = h.keys()
1304 fns = h.keys()
1305 fns.sort()
1305 fns.sort()
1306 m = max(map(len, fns))
1306 m = max(map(len, fns))
1307 for f in fns:
1307 for f in fns:
1308 if ui.verbose:
1308 if ui.verbose:
1309 commands = cmds[f].replace("|",", ")
1309 commands = cmds[f].replace("|",", ")
1310 ui.write(" %s:\n %s\n"%(commands, h[f]))
1310 ui.write(" %s:\n %s\n"%(commands, h[f]))
1311 else:
1311 else:
1312 ui.write(' %-*s %s\n' % (m, f, h[f]))
1312 ui.write(' %-*s %s\n' % (m, f, h[f]))
1313
1313
1314 if not ui.quiet:
1314 if not ui.quiet:
1315 addglobalopts(True)
1315 addglobalopts(True)
1316
1316
1317 def helptopic(name):
1317 def helptopic(name):
1318 v = None
1318 v = None
1319 for i in help.helptable:
1319 for i in help.helptable:
1320 l = i.split('|')
1320 l = i.split('|')
1321 if name in l:
1321 if name in l:
1322 v = i
1322 v = i
1323 header = l[-1]
1323 header = l[-1]
1324 if not v:
1324 if not v:
1325 raise cmdutil.UnknownCommand(name)
1325 raise cmdutil.UnknownCommand(name)
1326
1326
1327 # description
1327 # description
1328 doc = help.helptable[v]
1328 doc = help.helptable[v]
1329 if not doc:
1329 if not doc:
1330 doc = _("(No help text available)")
1330 doc = _("(No help text available)")
1331 if callable(doc):
1331 if callable(doc):
1332 doc = doc()
1332 doc = doc()
1333
1333
1334 ui.write("%s\n" % header)
1334 ui.write("%s\n" % header)
1335 ui.write("%s\n" % doc.rstrip())
1335 ui.write("%s\n" % doc.rstrip())
1336
1336
1337 def helpext(name):
1337 def helpext(name):
1338 try:
1338 try:
1339 mod = extensions.find(name)
1339 mod = extensions.find(name)
1340 except KeyError:
1340 except KeyError:
1341 raise cmdutil.UnknownCommand(name)
1341 raise cmdutil.UnknownCommand(name)
1342
1342
1343 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1343 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1344 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1344 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1345 for d in doc[1:]:
1345 for d in doc[1:]:
1346 ui.write(d, '\n')
1346 ui.write(d, '\n')
1347
1347
1348 ui.status('\n')
1348 ui.status('\n')
1349
1349
1350 try:
1350 try:
1351 ct = mod.cmdtable
1351 ct = mod.cmdtable
1352 except AttributeError:
1352 except AttributeError:
1353 ct = {}
1353 ct = {}
1354
1354
1355 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1355 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1356 helplist(_('list of commands:\n\n'), modcmds.has_key)
1356 helplist(_('list of commands:\n\n'), modcmds.has_key)
1357
1357
1358 if name and name != 'shortlist':
1358 if name and name != 'shortlist':
1359 i = None
1359 i = None
1360 for f in (helpcmd, helptopic, helpext):
1360 for f in (helpcmd, helptopic, helpext):
1361 try:
1361 try:
1362 f(name)
1362 f(name)
1363 i = None
1363 i = None
1364 break
1364 break
1365 except cmdutil.UnknownCommand, inst:
1365 except cmdutil.UnknownCommand, inst:
1366 i = inst
1366 i = inst
1367 if i:
1367 if i:
1368 raise i
1368 raise i
1369
1369
1370 else:
1370 else:
1371 # program name
1371 # program name
1372 if ui.verbose or with_version:
1372 if ui.verbose or with_version:
1373 version_(ui)
1373 version_(ui)
1374 else:
1374 else:
1375 ui.status(_("Mercurial Distributed SCM\n"))
1375 ui.status(_("Mercurial Distributed SCM\n"))
1376 ui.status('\n')
1376 ui.status('\n')
1377
1377
1378 # list of commands
1378 # list of commands
1379 if name == "shortlist":
1379 if name == "shortlist":
1380 header = _('basic commands:\n\n')
1380 header = _('basic commands:\n\n')
1381 else:
1381 else:
1382 header = _('list of commands:\n\n')
1382 header = _('list of commands:\n\n')
1383
1383
1384 helplist(header)
1384 helplist(header)
1385
1385
1386 # list all option lists
1386 # list all option lists
1387 opt_output = []
1387 opt_output = []
1388 for title, options in option_lists:
1388 for title, options in option_lists:
1389 opt_output.append(("\n%s" % title, None))
1389 opt_output.append(("\n%s" % title, None))
1390 for shortopt, longopt, default, desc in options:
1390 for shortopt, longopt, default, desc in options:
1391 if "DEPRECATED" in desc and not ui.verbose: continue
1391 if "DEPRECATED" in desc and not ui.verbose: continue
1392 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1392 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1393 longopt and " --%s" % longopt),
1393 longopt and " --%s" % longopt),
1394 "%s%s" % (desc,
1394 "%s%s" % (desc,
1395 default
1395 default
1396 and _(" (default: %s)") % default
1396 and _(" (default: %s)") % default
1397 or "")))
1397 or "")))
1398
1398
1399 if opt_output:
1399 if opt_output:
1400 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1400 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1401 for first, second in opt_output:
1401 for first, second in opt_output:
1402 if second:
1402 if second:
1403 ui.write(" %-*s %s\n" % (opts_len, first, second))
1403 ui.write(" %-*s %s\n" % (opts_len, first, second))
1404 else:
1404 else:
1405 ui.write("%s\n" % first)
1405 ui.write("%s\n" % first)
1406
1406
1407 def identify(ui, repo, source=None,
1407 def identify(ui, repo, source=None,
1408 rev=None, num=None, id=None, branch=None, tags=None):
1408 rev=None, num=None, id=None, branch=None, tags=None):
1409 """identify the working copy or specified revision
1409 """identify the working copy or specified revision
1410
1410
1411 With no revision, print a summary of the current state of the repo.
1411 With no revision, print a summary of the current state of the repo.
1412
1412
1413 With a path, do a lookup in another repository.
1413 With a path, do a lookup in another repository.
1414
1414
1415 This summary identifies the repository state using one or two parent
1415 This summary identifies the repository state using one or two parent
1416 hash identifiers, followed by a "+" if there are uncommitted changes
1416 hash identifiers, followed by a "+" if there are uncommitted changes
1417 in the working directory, a list of tags for this revision and a branch
1417 in the working directory, a list of tags for this revision and a branch
1418 name for non-default branches.
1418 name for non-default branches.
1419 """
1419 """
1420
1420
1421 if not repo and not source:
1421 if not repo and not source:
1422 raise util.Abort(_("There is no Mercurial repository here "
1422 raise util.Abort(_("There is no Mercurial repository here "
1423 "(.hg not found)"))
1423 "(.hg not found)"))
1424
1424
1425 hexfunc = ui.debugflag and hex or short
1425 hexfunc = ui.debugflag and hex or short
1426 default = not (num or id or branch or tags)
1426 default = not (num or id or branch or tags)
1427 output = []
1427 output = []
1428
1428
1429 if source:
1429 if source:
1430 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1430 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1431 srepo = hg.repository(ui, source)
1431 srepo = hg.repository(ui, source)
1432 if not rev and revs:
1432 if not rev and revs:
1433 rev = revs[0]
1433 rev = revs[0]
1434 if not rev:
1434 if not rev:
1435 rev = "tip"
1435 rev = "tip"
1436 if num or branch or tags:
1436 if num or branch or tags:
1437 raise util.Abort(
1437 raise util.Abort(
1438 "can't query remote revision number, branch, or tags")
1438 "can't query remote revision number, branch, or tags")
1439 output = [hexfunc(srepo.lookup(rev))]
1439 output = [hexfunc(srepo.lookup(rev))]
1440 elif not rev:
1440 elif not rev:
1441 ctx = repo.workingctx()
1441 ctx = repo.workingctx()
1442 parents = ctx.parents()
1442 parents = ctx.parents()
1443 changed = False
1443 changed = False
1444 if default or id or num:
1444 if default or id or num:
1445 changed = ctx.files() + ctx.deleted()
1445 changed = ctx.files() + ctx.deleted()
1446 if default or id:
1446 if default or id:
1447 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1447 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1448 (changed) and "+" or "")]
1448 (changed) and "+" or "")]
1449 if num:
1449 if num:
1450 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1450 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1451 (changed) and "+" or ""))
1451 (changed) and "+" or ""))
1452 else:
1452 else:
1453 ctx = repo.changectx(rev)
1453 ctx = repo.changectx(rev)
1454 if default or id:
1454 if default or id:
1455 output = [hexfunc(ctx.node())]
1455 output = [hexfunc(ctx.node())]
1456 if num:
1456 if num:
1457 output.append(str(ctx.rev()))
1457 output.append(str(ctx.rev()))
1458
1458
1459 if not source and default and not ui.quiet:
1459 if not source and default and not ui.quiet:
1460 b = util.tolocal(ctx.branch())
1460 b = util.tolocal(ctx.branch())
1461 if b != 'default':
1461 if b != 'default':
1462 output.append("(%s)" % b)
1462 output.append("(%s)" % b)
1463
1463
1464 # multiple tags for a single parent separated by '/'
1464 # multiple tags for a single parent separated by '/'
1465 t = "/".join(ctx.tags())
1465 t = "/".join(ctx.tags())
1466 if t:
1466 if t:
1467 output.append(t)
1467 output.append(t)
1468
1468
1469 if branch:
1469 if branch:
1470 output.append(util.tolocal(ctx.branch()))
1470 output.append(util.tolocal(ctx.branch()))
1471
1471
1472 if tags:
1472 if tags:
1473 output.extend(ctx.tags())
1473 output.extend(ctx.tags())
1474
1474
1475 ui.write("%s\n" % ' '.join(output))
1475 ui.write("%s\n" % ' '.join(output))
1476
1476
1477 def import_(ui, repo, patch1, *patches, **opts):
1477 def import_(ui, repo, patch1, *patches, **opts):
1478 """import an ordered set of patches
1478 """import an ordered set of patches
1479
1479
1480 Import a list of patches and commit them individually.
1480 Import a list of patches and commit them individually.
1481
1481
1482 If there are outstanding changes in the working directory, import
1482 If there are outstanding changes in the working directory, import
1483 will abort unless given the -f flag.
1483 will abort unless given the -f flag.
1484
1484
1485 You can import a patch straight from a mail message. Even patches
1485 You can import a patch straight from a mail message. Even patches
1486 as attachments work (body part must be type text/plain or
1486 as attachments work (body part must be type text/plain or
1487 text/x-patch to be used). From and Subject headers of email
1487 text/x-patch to be used). From and Subject headers of email
1488 message are used as default committer and commit message. All
1488 message are used as default committer and commit message. All
1489 text/plain body parts before first diff are added to commit
1489 text/plain body parts before first diff are added to commit
1490 message.
1490 message.
1491
1491
1492 If the imported patch was generated by hg export, user and description
1492 If the imported patch was generated by hg export, user and description
1493 from patch override values from message headers and body. Values
1493 from patch override values from message headers and body. Values
1494 given on command line with -m and -u override these.
1494 given on command line with -m and -u override these.
1495
1495
1496 If --exact is specified, import will set the working directory
1496 If --exact is specified, import will set the working directory
1497 to the parent of each patch before applying it, and will abort
1497 to the parent of each patch before applying it, and will abort
1498 if the resulting changeset has a different ID than the one
1498 if the resulting changeset has a different ID than the one
1499 recorded in the patch. This may happen due to character set
1499 recorded in the patch. This may happen due to character set
1500 problems or other deficiencies in the text patch format.
1500 problems or other deficiencies in the text patch format.
1501
1501
1502 To read a patch from standard input, use patch name "-".
1502 To read a patch from standard input, use patch name "-".
1503 See 'hg help dates' for a list of formats valid for -d/--date.
1503 See 'hg help dates' for a list of formats valid for -d/--date.
1504 """
1504 """
1505 patches = (patch1,) + patches
1505 patches = (patch1,) + patches
1506
1506
1507 date = opts.get('date')
1507 date = opts.get('date')
1508 if date:
1508 if date:
1509 opts['date'] = util.parsedate(date)
1509 opts['date'] = util.parsedate(date)
1510
1510
1511 if opts.get('exact') or not opts['force']:
1511 if opts.get('exact') or not opts['force']:
1512 cmdutil.bail_if_changed(repo)
1512 cmdutil.bail_if_changed(repo)
1513
1513
1514 d = opts["base"]
1514 d = opts["base"]
1515 strip = opts["strip"]
1515 strip = opts["strip"]
1516 wlock = lock = None
1516 wlock = lock = None
1517 try:
1517 try:
1518 wlock = repo.wlock()
1518 wlock = repo.wlock()
1519 lock = repo.lock()
1519 lock = repo.lock()
1520 for p in patches:
1520 for p in patches:
1521 pf = os.path.join(d, p)
1521 pf = os.path.join(d, p)
1522
1522
1523 if pf == '-':
1523 if pf == '-':
1524 ui.status(_("applying patch from stdin\n"))
1524 ui.status(_("applying patch from stdin\n"))
1525 data = patch.extract(ui, sys.stdin)
1525 data = patch.extract(ui, sys.stdin)
1526 else:
1526 else:
1527 ui.status(_("applying %s\n") % p)
1527 ui.status(_("applying %s\n") % p)
1528 if os.path.exists(pf):
1528 if os.path.exists(pf):
1529 data = patch.extract(ui, file(pf, 'rb'))
1529 data = patch.extract(ui, file(pf, 'rb'))
1530 else:
1530 else:
1531 data = patch.extract(ui, urllib.urlopen(pf))
1531 data = patch.extract(ui, urllib.urlopen(pf))
1532 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1532 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1533
1533
1534 if tmpname is None:
1534 if tmpname is None:
1535 raise util.Abort(_('no diffs found'))
1535 raise util.Abort(_('no diffs found'))
1536
1536
1537 try:
1537 try:
1538 cmdline_message = cmdutil.logmessage(opts)
1538 cmdline_message = cmdutil.logmessage(opts)
1539 if cmdline_message:
1539 if cmdline_message:
1540 # pickup the cmdline msg
1540 # pickup the cmdline msg
1541 message = cmdline_message
1541 message = cmdline_message
1542 elif message:
1542 elif message:
1543 # pickup the patch msg
1543 # pickup the patch msg
1544 message = message.strip()
1544 message = message.strip()
1545 else:
1545 else:
1546 # launch the editor
1546 # launch the editor
1547 message = None
1547 message = None
1548 ui.debug(_('message:\n%s\n') % message)
1548 ui.debug(_('message:\n%s\n') % message)
1549
1549
1550 wp = repo.workingctx().parents()
1550 wp = repo.workingctx().parents()
1551 if opts.get('exact'):
1551 if opts.get('exact'):
1552 if not nodeid or not p1:
1552 if not nodeid or not p1:
1553 raise util.Abort(_('not a mercurial patch'))
1553 raise util.Abort(_('not a mercurial patch'))
1554 p1 = repo.lookup(p1)
1554 p1 = repo.lookup(p1)
1555 p2 = repo.lookup(p2 or hex(nullid))
1555 p2 = repo.lookup(p2 or hex(nullid))
1556
1556
1557 if p1 != wp[0].node():
1557 if p1 != wp[0].node():
1558 hg.clean(repo, p1)
1558 hg.clean(repo, p1)
1559 repo.dirstate.setparents(p1, p2)
1559 repo.dirstate.setparents(p1, p2)
1560 elif p2:
1560 elif p2:
1561 try:
1561 try:
1562 p1 = repo.lookup(p1)
1562 p1 = repo.lookup(p1)
1563 p2 = repo.lookup(p2)
1563 p2 = repo.lookup(p2)
1564 if p1 == wp[0].node():
1564 if p1 == wp[0].node():
1565 repo.dirstate.setparents(p1, p2)
1565 repo.dirstate.setparents(p1, p2)
1566 except RepoError:
1566 except RepoError:
1567 pass
1567 pass
1568 if opts.get('exact') or opts.get('import_branch'):
1568 if opts.get('exact') or opts.get('import_branch'):
1569 repo.dirstate.setbranch(branch or 'default')
1569 repo.dirstate.setbranch(branch or 'default')
1570
1570
1571 files = {}
1571 files = {}
1572 try:
1572 try:
1573 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1573 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1574 files=files)
1574 files=files)
1575 finally:
1575 finally:
1576 files = patch.updatedir(ui, repo, files)
1576 files = patch.updatedir(ui, repo, files)
1577 if not opts.get('no_commit'):
1577 if not opts.get('no_commit'):
1578 n = repo.commit(files, message, opts.get('user') or user,
1578 n = repo.commit(files, message, opts.get('user') or user,
1579 opts.get('date') or date)
1579 opts.get('date') or date)
1580 if opts.get('exact'):
1580 if opts.get('exact'):
1581 if hex(n) != nodeid:
1581 if hex(n) != nodeid:
1582 repo.rollback()
1582 repo.rollback()
1583 raise util.Abort(_('patch is damaged'
1583 raise util.Abort(_('patch is damaged'
1584 ' or loses information'))
1584 ' or loses information'))
1585 # Force a dirstate write so that the next transaction
1585 # Force a dirstate write so that the next transaction
1586 # backups an up-do-date file.
1586 # backups an up-do-date file.
1587 repo.dirstate.write()
1587 repo.dirstate.write()
1588 finally:
1588 finally:
1589 os.unlink(tmpname)
1589 os.unlink(tmpname)
1590 finally:
1590 finally:
1591 del lock, wlock
1591 del lock, wlock
1592
1592
1593 def incoming(ui, repo, source="default", **opts):
1593 def incoming(ui, repo, source="default", **opts):
1594 """show new changesets found in source
1594 """show new changesets found in source
1595
1595
1596 Show new changesets found in the specified path/URL or the default
1596 Show new changesets found in the specified path/URL or the default
1597 pull location. These are the changesets that would be pulled if a pull
1597 pull location. These are the changesets that would be pulled if a pull
1598 was requested.
1598 was requested.
1599
1599
1600 For remote repository, using --bundle avoids downloading the changesets
1600 For remote repository, using --bundle avoids downloading the changesets
1601 twice if the incoming is followed by a pull.
1601 twice if the incoming is followed by a pull.
1602
1602
1603 See pull for valid source format details.
1603 See pull for valid source format details.
1604 """
1604 """
1605 limit = cmdutil.loglimit(opts)
1605 limit = cmdutil.loglimit(opts)
1606 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1606 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1607 cmdutil.setremoteconfig(ui, opts)
1607 cmdutil.setremoteconfig(ui, opts)
1608
1608
1609 other = hg.repository(ui, source)
1609 other = hg.repository(ui, source)
1610 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1610 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1611 if revs:
1611 if revs:
1612 revs = [other.lookup(rev) for rev in revs]
1612 revs = [other.lookup(rev) for rev in revs]
1613 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1613 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1614 if not incoming:
1614 if not incoming:
1615 try:
1615 try:
1616 os.unlink(opts["bundle"])
1616 os.unlink(opts["bundle"])
1617 except:
1617 except:
1618 pass
1618 pass
1619 ui.status(_("no changes found\n"))
1619 ui.status(_("no changes found\n"))
1620 return 1
1620 return 1
1621
1621
1622 cleanup = None
1622 cleanup = None
1623 try:
1623 try:
1624 fname = opts["bundle"]
1624 fname = opts["bundle"]
1625 if fname or not other.local():
1625 if fname or not other.local():
1626 # create a bundle (uncompressed if other repo is not local)
1626 # create a bundle (uncompressed if other repo is not local)
1627 if revs is None:
1627 if revs is None:
1628 cg = other.changegroup(incoming, "incoming")
1628 cg = other.changegroup(incoming, "incoming")
1629 else:
1629 else:
1630 cg = other.changegroupsubset(incoming, revs, 'incoming')
1630 cg = other.changegroupsubset(incoming, revs, 'incoming')
1631 bundletype = other.local() and "HG10BZ" or "HG10UN"
1631 bundletype = other.local() and "HG10BZ" or "HG10UN"
1632 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1632 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1633 # keep written bundle?
1633 # keep written bundle?
1634 if opts["bundle"]:
1634 if opts["bundle"]:
1635 cleanup = None
1635 cleanup = None
1636 if not other.local():
1636 if not other.local():
1637 # use the created uncompressed bundlerepo
1637 # use the created uncompressed bundlerepo
1638 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1638 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1639
1639
1640 o = other.changelog.nodesbetween(incoming, revs)[0]
1640 o = other.changelog.nodesbetween(incoming, revs)[0]
1641 if opts['newest_first']:
1641 if opts['newest_first']:
1642 o.reverse()
1642 o.reverse()
1643 displayer = cmdutil.show_changeset(ui, other, opts)
1643 displayer = cmdutil.show_changeset(ui, other, opts)
1644 count = 0
1644 count = 0
1645 for n in o:
1645 for n in o:
1646 if count >= limit:
1646 if count >= limit:
1647 break
1647 break
1648 parents = [p for p in other.changelog.parents(n) if p != nullid]
1648 parents = [p for p in other.changelog.parents(n) if p != nullid]
1649 if opts['no_merges'] and len(parents) == 2:
1649 if opts['no_merges'] and len(parents) == 2:
1650 continue
1650 continue
1651 count += 1
1651 count += 1
1652 displayer.show(changenode=n)
1652 displayer.show(changenode=n)
1653 finally:
1653 finally:
1654 if hasattr(other, 'close'):
1654 if hasattr(other, 'close'):
1655 other.close()
1655 other.close()
1656 if cleanup:
1656 if cleanup:
1657 os.unlink(cleanup)
1657 os.unlink(cleanup)
1658
1658
1659 def init(ui, dest=".", **opts):
1659 def init(ui, dest=".", **opts):
1660 """create a new repository in the given directory
1660 """create a new repository in the given directory
1661
1661
1662 Initialize a new repository in the given directory. If the given
1662 Initialize a new repository in the given directory. If the given
1663 directory does not exist, it is created.
1663 directory does not exist, it is created.
1664
1664
1665 If no directory is given, the current directory is used.
1665 If no directory is given, the current directory is used.
1666
1666
1667 It is possible to specify an ssh:// URL as the destination.
1667 It is possible to specify an ssh:// URL as the destination.
1668 Look at the help text for the pull command for important details
1668 Look at the help text for the pull command for important details
1669 about ssh:// URLs.
1669 about ssh:// URLs.
1670 """
1670 """
1671 cmdutil.setremoteconfig(ui, opts)
1671 cmdutil.setremoteconfig(ui, opts)
1672 hg.repository(ui, dest, create=1)
1672 hg.repository(ui, dest, create=1)
1673
1673
1674 def locate(ui, repo, *pats, **opts):
1674 def locate(ui, repo, *pats, **opts):
1675 """locate files matching specific patterns
1675 """locate files matching specific patterns
1676
1676
1677 Print all files under Mercurial control whose names match the
1677 Print all files under Mercurial control whose names match the
1678 given patterns.
1678 given patterns.
1679
1679
1680 This command searches the entire repository by default. To search
1680 This command searches the entire repository by default. To search
1681 just the current directory and its subdirectories, use
1681 just the current directory and its subdirectories, use
1682 "--include .".
1682 "--include .".
1683
1683
1684 If no patterns are given to match, this command prints all file
1684 If no patterns are given to match, this command prints all file
1685 names.
1685 names.
1686
1686
1687 If you want to feed the output of this command into the "xargs"
1687 If you want to feed the output of this command into the "xargs"
1688 command, use the "-0" option to both this command and "xargs".
1688 command, use the "-0" option to both this command and "xargs".
1689 This will avoid the problem of "xargs" treating single filenames
1689 This will avoid the problem of "xargs" treating single filenames
1690 that contain white space as multiple filenames.
1690 that contain white space as multiple filenames.
1691 """
1691 """
1692 end = opts['print0'] and '\0' or '\n'
1692 end = opts['print0'] and '\0' or '\n'
1693 rev = opts['rev']
1693 rev = opts['rev']
1694 if rev:
1694 if rev:
1695 node = repo.lookup(rev)
1695 node = repo.lookup(rev)
1696 else:
1696 else:
1697 node = None
1697 node = None
1698
1698
1699 ret = 1
1699 ret = 1
1700 m = cmdutil.match(repo, pats, opts, default='relglob')
1700 m = cmdutil.match(repo, pats, opts, default='relglob')
1701 m.bad = lambda x,y: False
1701 m.bad = lambda x,y: False
1702 for abs in repo.walk(m, node):
1702 for abs in repo.walk(m, node):
1703 if not node and abs not in repo.dirstate:
1703 if not node and abs not in repo.dirstate:
1704 continue
1704 continue
1705 if opts['fullpath']:
1705 if opts['fullpath']:
1706 ui.write(os.path.join(repo.root, abs), end)
1706 ui.write(os.path.join(repo.root, abs), end)
1707 else:
1707 else:
1708 ui.write(((pats and m.rel(abs)) or abs), end)
1708 ui.write(((pats and m.rel(abs)) or abs), end)
1709 ret = 0
1709 ret = 0
1710
1710
1711 return ret
1711 return ret
1712
1712
1713 def log(ui, repo, *pats, **opts):
1713 def log(ui, repo, *pats, **opts):
1714 """show revision history of entire repository or files
1714 """show revision history of entire repository or files
1715
1715
1716 Print the revision history of the specified files or the entire
1716 Print the revision history of the specified files or the entire
1717 project.
1717 project.
1718
1718
1719 File history is shown without following rename or copy history of
1719 File history is shown without following rename or copy history of
1720 files. Use -f/--follow with a file name to follow history across
1720 files. Use -f/--follow with a file name to follow history across
1721 renames and copies. --follow without a file name will only show
1721 renames and copies. --follow without a file name will only show
1722 ancestors or descendants of the starting revision. --follow-first
1722 ancestors or descendants of the starting revision. --follow-first
1723 only follows the first parent of merge revisions.
1723 only follows the first parent of merge revisions.
1724
1724
1725 If no revision range is specified, the default is tip:0 unless
1725 If no revision range is specified, the default is tip:0 unless
1726 --follow is set, in which case the working directory parent is
1726 --follow is set, in which case the working directory parent is
1727 used as the starting revision.
1727 used as the starting revision.
1728
1728
1729 See 'hg help dates' for a list of formats valid for -d/--date.
1729 See 'hg help dates' for a list of formats valid for -d/--date.
1730
1730
1731 By default this command outputs: changeset id and hash, tags,
1731 By default this command outputs: changeset id and hash, tags,
1732 non-trivial parents, user, date and time, and a summary for each
1732 non-trivial parents, user, date and time, and a summary for each
1733 commit. When the -v/--verbose switch is used, the list of changed
1733 commit. When the -v/--verbose switch is used, the list of changed
1734 files and full commit message is shown.
1734 files and full commit message is shown.
1735
1735
1736 NOTE: log -p may generate unexpected diff output for merge
1736 NOTE: log -p may generate unexpected diff output for merge
1737 changesets, as it will compare the merge changeset against its
1737 changesets, as it will compare the merge changeset against its
1738 first parent only. Also, the files: list will only reflect files
1738 first parent only. Also, the files: list will only reflect files
1739 that are different from BOTH parents.
1739 that are different from BOTH parents.
1740
1740
1741 """
1741 """
1742
1742
1743 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1743 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1744 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1744 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1745
1745
1746 limit = cmdutil.loglimit(opts)
1746 limit = cmdutil.loglimit(opts)
1747 count = 0
1747 count = 0
1748
1748
1749 if opts['copies'] and opts['rev']:
1749 if opts['copies'] and opts['rev']:
1750 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1750 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1751 else:
1751 else:
1752 endrev = repo.changelog.count()
1752 endrev = repo.changelog.count()
1753 rcache = {}
1753 rcache = {}
1754 ncache = {}
1754 ncache = {}
1755 def getrenamed(fn, rev):
1755 def getrenamed(fn, rev):
1756 '''looks up all renames for a file (up to endrev) the first
1756 '''looks up all renames for a file (up to endrev) the first
1757 time the file is given. It indexes on the changerev and only
1757 time the file is given. It indexes on the changerev and only
1758 parses the manifest if linkrev != changerev.
1758 parses the manifest if linkrev != changerev.
1759 Returns rename info for fn at changerev rev.'''
1759 Returns rename info for fn at changerev rev.'''
1760 if fn not in rcache:
1760 if fn not in rcache:
1761 rcache[fn] = {}
1761 rcache[fn] = {}
1762 ncache[fn] = {}
1762 ncache[fn] = {}
1763 fl = repo.file(fn)
1763 fl = repo.file(fn)
1764 for i in xrange(fl.count()):
1764 for i in xrange(fl.count()):
1765 node = fl.node(i)
1765 node = fl.node(i)
1766 lr = fl.linkrev(node)
1766 lr = fl.linkrev(node)
1767 renamed = fl.renamed(node)
1767 renamed = fl.renamed(node)
1768 rcache[fn][lr] = renamed
1768 rcache[fn][lr] = renamed
1769 if renamed:
1769 if renamed:
1770 ncache[fn][node] = renamed
1770 ncache[fn][node] = renamed
1771 if lr >= endrev:
1771 if lr >= endrev:
1772 break
1772 break
1773 if rev in rcache[fn]:
1773 if rev in rcache[fn]:
1774 return rcache[fn][rev]
1774 return rcache[fn][rev]
1775
1775
1776 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1776 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1777 # filectx logic.
1777 # filectx logic.
1778
1778
1779 try:
1779 try:
1780 return repo.changectx(rev).filectx(fn).renamed()
1780 return repo.changectx(rev).filectx(fn).renamed()
1781 except revlog.LookupError:
1781 except revlog.LookupError:
1782 pass
1782 pass
1783 return None
1783 return None
1784
1784
1785 df = False
1785 df = False
1786 if opts["date"]:
1786 if opts["date"]:
1787 df = util.matchdate(opts["date"])
1787 df = util.matchdate(opts["date"])
1788
1788
1789 only_branches = opts['only_branch']
1789 only_branches = opts['only_branch']
1790
1790
1791 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1791 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1792 for st, rev, fns in changeiter:
1792 for st, rev, fns in changeiter:
1793 if st == 'add':
1793 if st == 'add':
1794 changenode = repo.changelog.node(rev)
1794 changenode = repo.changelog.node(rev)
1795 parents = [p for p in repo.changelog.parentrevs(rev)
1795 parents = [p for p in repo.changelog.parentrevs(rev)
1796 if p != nullrev]
1796 if p != nullrev]
1797 if opts['no_merges'] and len(parents) == 2:
1797 if opts['no_merges'] and len(parents) == 2:
1798 continue
1798 continue
1799 if opts['only_merges'] and len(parents) != 2:
1799 if opts['only_merges'] and len(parents) != 2:
1800 continue
1800 continue
1801
1801
1802 if only_branches:
1802 if only_branches:
1803 revbranch = get(rev)[5]['branch']
1803 revbranch = get(rev)[5]['branch']
1804 if revbranch not in only_branches:
1804 if revbranch not in only_branches:
1805 continue
1805 continue
1806
1806
1807 if df:
1807 if df:
1808 changes = get(rev)
1808 changes = get(rev)
1809 if not df(changes[2][0]):
1809 if not df(changes[2][0]):
1810 continue
1810 continue
1811
1811
1812 if opts['keyword']:
1812 if opts['keyword']:
1813 changes = get(rev)
1813 changes = get(rev)
1814 miss = 0
1814 miss = 0
1815 for k in [kw.lower() for kw in opts['keyword']]:
1815 for k in [kw.lower() for kw in opts['keyword']]:
1816 if not (k in changes[1].lower() or
1816 if not (k in changes[1].lower() or
1817 k in changes[4].lower() or
1817 k in changes[4].lower() or
1818 k in " ".join(changes[3]).lower()):
1818 k in " ".join(changes[3]).lower()):
1819 miss = 1
1819 miss = 1
1820 break
1820 break
1821 if miss:
1821 if miss:
1822 continue
1822 continue
1823
1823
1824 copies = []
1824 copies = []
1825 if opts.get('copies') and rev:
1825 if opts.get('copies') and rev:
1826 for fn in get(rev)[3]:
1826 for fn in get(rev)[3]:
1827 rename = getrenamed(fn, rev)
1827 rename = getrenamed(fn, rev)
1828 if rename:
1828 if rename:
1829 copies.append((fn, rename[0]))
1829 copies.append((fn, rename[0]))
1830 displayer.show(rev, changenode, copies=copies)
1830 displayer.show(rev, changenode, copies=copies)
1831 elif st == 'iter':
1831 elif st == 'iter':
1832 if count == limit: break
1832 if count == limit: break
1833 if displayer.flush(rev):
1833 if displayer.flush(rev):
1834 count += 1
1834 count += 1
1835
1835
1836 def manifest(ui, repo, node=None, rev=None):
1836 def manifest(ui, repo, node=None, rev=None):
1837 """output the current or given revision of the project manifest
1837 """output the current or given revision of the project manifest
1838
1838
1839 Print a list of version controlled files for the given revision.
1839 Print a list of version controlled files for the given revision.
1840 If no revision is given, the parent of the working directory is used,
1840 If no revision is given, the parent of the working directory is used,
1841 or tip if no revision is checked out.
1841 or tip if no revision is checked out.
1842
1842
1843 The manifest is the list of files being version controlled. If no revision
1843 The manifest is the list of files being version controlled. If no revision
1844 is given then the first parent of the working directory is used.
1844 is given then the first parent of the working directory is used.
1845
1845
1846 With -v flag, print file permissions, symlink and executable bits. With
1846 With -v flag, print file permissions, symlink and executable bits. With
1847 --debug flag, print file revision hashes.
1847 --debug flag, print file revision hashes.
1848 """
1848 """
1849
1849
1850 if rev and node:
1850 if rev and node:
1851 raise util.Abort(_("please specify just one revision"))
1851 raise util.Abort(_("please specify just one revision"))
1852
1852
1853 if not node:
1853 if not node:
1854 node = rev
1854 node = rev
1855
1855
1856 m = repo.changectx(node).manifest()
1856 m = repo.changectx(node).manifest()
1857 files = m.keys()
1857 files = m.keys()
1858 files.sort()
1858 files.sort()
1859
1859
1860 for f in files:
1860 for f in files:
1861 if ui.debugflag:
1861 if ui.debugflag:
1862 ui.write("%40s " % hex(m[f]))
1862 ui.write("%40s " % hex(m[f]))
1863 if ui.verbose:
1863 if ui.verbose:
1864 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1864 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1865 perm = m.execf(f) and "755" or "644"
1865 perm = m.execf(f) and "755" or "644"
1866 ui.write("%3s %1s " % (perm, type))
1866 ui.write("%3s %1s " % (perm, type))
1867 ui.write("%s\n" % f)
1867 ui.write("%s\n" % f)
1868
1868
1869 def merge(ui, repo, node=None, force=None, rev=None):
1869 def merge(ui, repo, node=None, force=None, rev=None):
1870 """merge working directory with another revision
1870 """merge working directory with another revision
1871
1871
1872 Merge the contents of the current working directory and the
1872 Merge the contents of the current working directory and the
1873 requested revision. Files that changed between either parent are
1873 requested revision. Files that changed between either parent are
1874 marked as changed for the next commit and a commit must be
1874 marked as changed for the next commit and a commit must be
1875 performed before any further updates are allowed.
1875 performed before any further updates are allowed.
1876
1876
1877 If no revision is specified, the working directory's parent is a
1877 If no revision is specified, the working directory's parent is a
1878 head revision, and the repository contains exactly one other head,
1878 head revision, and the repository contains exactly one other head,
1879 the other head is merged with by default. Otherwise, an explicit
1879 the other head is merged with by default. Otherwise, an explicit
1880 revision to merge with must be provided.
1880 revision to merge with must be provided.
1881 """
1881 """
1882
1882
1883 if rev and node:
1883 if rev and node:
1884 raise util.Abort(_("please specify just one revision"))
1884 raise util.Abort(_("please specify just one revision"))
1885 if not node:
1885 if not node:
1886 node = rev
1886 node = rev
1887
1887
1888 if not node:
1888 if not node:
1889 heads = repo.heads()
1889 heads = repo.heads()
1890 if len(heads) > 2:
1890 if len(heads) > 2:
1891 raise util.Abort(_('repo has %d heads - '
1891 raise util.Abort(_('repo has %d heads - '
1892 'please merge with an explicit rev') %
1892 'please merge with an explicit rev') %
1893 len(heads))
1893 len(heads))
1894 parent = repo.dirstate.parents()[0]
1894 parent = repo.dirstate.parents()[0]
1895 if len(heads) == 1:
1895 if len(heads) == 1:
1896 msg = _('there is nothing to merge')
1896 msg = _('there is nothing to merge')
1897 if parent != repo.lookup(repo.workingctx().branch()):
1897 if parent != repo.lookup(repo.workingctx().branch()):
1898 msg = _('%s - use "hg update" instead') % msg
1898 msg = _('%s - use "hg update" instead') % msg
1899 raise util.Abort(msg)
1899 raise util.Abort(msg)
1900
1900
1901 if parent not in heads:
1901 if parent not in heads:
1902 raise util.Abort(_('working dir not at a head rev - '
1902 raise util.Abort(_('working dir not at a head rev - '
1903 'use "hg update" or merge with an explicit rev'))
1903 'use "hg update" or merge with an explicit rev'))
1904 node = parent == heads[0] and heads[-1] or heads[0]
1904 node = parent == heads[0] and heads[-1] or heads[0]
1905 return hg.merge(repo, node, force=force)
1905 return hg.merge(repo, node, force=force)
1906
1906
1907 def outgoing(ui, repo, dest=None, **opts):
1907 def outgoing(ui, repo, dest=None, **opts):
1908 """show changesets not found in destination
1908 """show changesets not found in destination
1909
1909
1910 Show changesets not found in the specified destination repository or
1910 Show changesets not found in the specified destination repository or
1911 the default push location. These are the changesets that would be pushed
1911 the default push location. These are the changesets that would be pushed
1912 if a push was requested.
1912 if a push was requested.
1913
1913
1914 See pull for valid destination format details.
1914 See pull for valid destination format details.
1915 """
1915 """
1916 limit = cmdutil.loglimit(opts)
1916 limit = cmdutil.loglimit(opts)
1917 dest, revs, checkout = hg.parseurl(
1917 dest, revs, checkout = hg.parseurl(
1918 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1918 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1919 cmdutil.setremoteconfig(ui, opts)
1919 cmdutil.setremoteconfig(ui, opts)
1920 if revs:
1920 if revs:
1921 revs = [repo.lookup(rev) for rev in revs]
1921 revs = [repo.lookup(rev) for rev in revs]
1922
1922
1923 other = hg.repository(ui, dest)
1923 other = hg.repository(ui, dest)
1924 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1924 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1925 o = repo.findoutgoing(other, force=opts['force'])
1925 o = repo.findoutgoing(other, force=opts['force'])
1926 if not o:
1926 if not o:
1927 ui.status(_("no changes found\n"))
1927 ui.status(_("no changes found\n"))
1928 return 1
1928 return 1
1929 o = repo.changelog.nodesbetween(o, revs)[0]
1929 o = repo.changelog.nodesbetween(o, revs)[0]
1930 if opts['newest_first']:
1930 if opts['newest_first']:
1931 o.reverse()
1931 o.reverse()
1932 displayer = cmdutil.show_changeset(ui, repo, opts)
1932 displayer = cmdutil.show_changeset(ui, repo, opts)
1933 count = 0
1933 count = 0
1934 for n in o:
1934 for n in o:
1935 if count >= limit:
1935 if count >= limit:
1936 break
1936 break
1937 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1937 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1938 if opts['no_merges'] and len(parents) == 2:
1938 if opts['no_merges'] and len(parents) == 2:
1939 continue
1939 continue
1940 count += 1
1940 count += 1
1941 displayer.show(changenode=n)
1941 displayer.show(changenode=n)
1942
1942
1943 def parents(ui, repo, file_=None, **opts):
1943 def parents(ui, repo, file_=None, **opts):
1944 """show the parents of the working dir or revision
1944 """show the parents of the working dir or revision
1945
1945
1946 Print the working directory's parent revisions. If a
1946 Print the working directory's parent revisions. If a
1947 revision is given via --rev, the parent of that revision
1947 revision is given via --rev, the parent of that revision
1948 will be printed. If a file argument is given, revision in
1948 will be printed. If a file argument is given, revision in
1949 which the file was last changed (before the working directory
1949 which the file was last changed (before the working directory
1950 revision or the argument to --rev if given) is printed.
1950 revision or the argument to --rev if given) is printed.
1951 """
1951 """
1952 rev = opts.get('rev')
1952 rev = opts.get('rev')
1953 if rev:
1953 if rev:
1954 ctx = repo.changectx(rev)
1954 ctx = repo.changectx(rev)
1955 else:
1955 else:
1956 ctx = repo.workingctx()
1956 ctx = repo.workingctx()
1957
1957
1958 if file_:
1958 if file_:
1959 m = cmdutil.match(repo, (file_,), opts)
1959 m = cmdutil.match(repo, (file_,), opts)
1960 if m.anypats() or len(m.files()) != 1:
1960 if m.anypats() or len(m.files()) != 1:
1961 raise util.Abort(_('can only specify an explicit file name'))
1961 raise util.Abort(_('can only specify an explicit file name'))
1962 file_ = m.files()[0]
1962 file_ = m.files()[0]
1963 filenodes = []
1963 filenodes = []
1964 for cp in ctx.parents():
1964 for cp in ctx.parents():
1965 if not cp:
1965 if not cp:
1966 continue
1966 continue
1967 try:
1967 try:
1968 filenodes.append(cp.filenode(file_))
1968 filenodes.append(cp.filenode(file_))
1969 except revlog.LookupError:
1969 except revlog.LookupError:
1970 pass
1970 pass
1971 if not filenodes:
1971 if not filenodes:
1972 raise util.Abort(_("'%s' not found in manifest!") % file_)
1972 raise util.Abort(_("'%s' not found in manifest!") % file_)
1973 fl = repo.file(file_)
1973 fl = repo.file(file_)
1974 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1974 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1975 else:
1975 else:
1976 p = [cp.node() for cp in ctx.parents()]
1976 p = [cp.node() for cp in ctx.parents()]
1977
1977
1978 displayer = cmdutil.show_changeset(ui, repo, opts)
1978 displayer = cmdutil.show_changeset(ui, repo, opts)
1979 for n in p:
1979 for n in p:
1980 if n != nullid:
1980 if n != nullid:
1981 displayer.show(changenode=n)
1981 displayer.show(changenode=n)
1982
1982
1983 def paths(ui, repo, search=None):
1983 def paths(ui, repo, search=None):
1984 """show definition of symbolic path names
1984 """show definition of symbolic path names
1985
1985
1986 Show definition of symbolic path name NAME. If no name is given, show
1986 Show definition of symbolic path name NAME. If no name is given, show
1987 definition of available names.
1987 definition of available names.
1988
1988
1989 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1989 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1990 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1990 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1991 """
1991 """
1992 if search:
1992 if search:
1993 for name, path in ui.configitems("paths"):
1993 for name, path in ui.configitems("paths"):
1994 if name == search:
1994 if name == search:
1995 ui.write("%s\n" % util.hidepassword(path))
1995 ui.write("%s\n" % util.hidepassword(path))
1996 return
1996 return
1997 ui.warn(_("not found!\n"))
1997 ui.warn(_("not found!\n"))
1998 return 1
1998 return 1
1999 else:
1999 else:
2000 for name, path in ui.configitems("paths"):
2000 for name, path in ui.configitems("paths"):
2001 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2001 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2002
2002
2003 def postincoming(ui, repo, modheads, optupdate, checkout):
2003 def postincoming(ui, repo, modheads, optupdate, checkout):
2004 if modheads == 0:
2004 if modheads == 0:
2005 return
2005 return
2006 if optupdate:
2006 if optupdate:
2007 if modheads <= 1 or checkout:
2007 if modheads <= 1 or checkout:
2008 return hg.update(repo, checkout)
2008 return hg.update(repo, checkout)
2009 else:
2009 else:
2010 ui.status(_("not updating, since new heads added\n"))
2010 ui.status(_("not updating, since new heads added\n"))
2011 if modheads > 1:
2011 if modheads > 1:
2012 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2012 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2013 else:
2013 else:
2014 ui.status(_("(run 'hg update' to get a working copy)\n"))
2014 ui.status(_("(run 'hg update' to get a working copy)\n"))
2015
2015
2016 def pull(ui, repo, source="default", **opts):
2016 def pull(ui, repo, source="default", **opts):
2017 """pull changes from the specified source
2017 """pull changes from the specified source
2018
2018
2019 Pull changes from a remote repository to a local one.
2019 Pull changes from a remote repository to a local one.
2020
2020
2021 This finds all changes from the repository at the specified path
2021 This finds all changes from the repository at the specified path
2022 or URL and adds them to the local repository. By default, this
2022 or URL and adds them to the local repository. By default, this
2023 does not update the copy of the project in the working directory.
2023 does not update the copy of the project in the working directory.
2024
2024
2025 Valid URLs are of the form:
2025 Valid URLs are of the form:
2026
2026
2027 local/filesystem/path (or file://local/filesystem/path)
2027 local/filesystem/path (or file://local/filesystem/path)
2028 http://[user@]host[:port]/[path]
2028 http://[user@]host[:port]/[path]
2029 https://[user@]host[:port]/[path]
2029 https://[user@]host[:port]/[path]
2030 ssh://[user@]host[:port]/[path]
2030 ssh://[user@]host[:port]/[path]
2031 static-http://host[:port]/[path]
2031 static-http://host[:port]/[path]
2032
2032
2033 Paths in the local filesystem can either point to Mercurial
2033 Paths in the local filesystem can either point to Mercurial
2034 repositories or to bundle files (as created by 'hg bundle' or
2034 repositories or to bundle files (as created by 'hg bundle' or
2035 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2035 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2036 allows access to a Mercurial repository where you simply use a web
2036 allows access to a Mercurial repository where you simply use a web
2037 server to publish the .hg directory as static content.
2037 server to publish the .hg directory as static content.
2038
2038
2039 An optional identifier after # indicates a particular branch, tag,
2039 An optional identifier after # indicates a particular branch, tag,
2040 or changeset to pull.
2040 or changeset to pull.
2041
2041
2042 Some notes about using SSH with Mercurial:
2042 Some notes about using SSH with Mercurial:
2043 - SSH requires an accessible shell account on the destination machine
2043 - SSH requires an accessible shell account on the destination machine
2044 and a copy of hg in the remote path or specified with as remotecmd.
2044 and a copy of hg in the remote path or specified with as remotecmd.
2045 - path is relative to the remote user's home directory by default.
2045 - path is relative to the remote user's home directory by default.
2046 Use an extra slash at the start of a path to specify an absolute path:
2046 Use an extra slash at the start of a path to specify an absolute path:
2047 ssh://example.com//tmp/repository
2047 ssh://example.com//tmp/repository
2048 - Mercurial doesn't use its own compression via SSH; the right thing
2048 - Mercurial doesn't use its own compression via SSH; the right thing
2049 to do is to configure it in your ~/.ssh/config, e.g.:
2049 to do is to configure it in your ~/.ssh/config, e.g.:
2050 Host *.mylocalnetwork.example.com
2050 Host *.mylocalnetwork.example.com
2051 Compression no
2051 Compression no
2052 Host *
2052 Host *
2053 Compression yes
2053 Compression yes
2054 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2054 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2055 with the --ssh command line option.
2055 with the --ssh command line option.
2056 """
2056 """
2057 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2057 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2058 cmdutil.setremoteconfig(ui, opts)
2058 cmdutil.setremoteconfig(ui, opts)
2059
2059
2060 other = hg.repository(ui, source)
2060 other = hg.repository(ui, source)
2061 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2061 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2062 if revs:
2062 if revs:
2063 try:
2063 try:
2064 revs = [other.lookup(rev) for rev in revs]
2064 revs = [other.lookup(rev) for rev in revs]
2065 except NoCapability:
2065 except NoCapability:
2066 error = _("Other repository doesn't support revision lookup, "
2066 error = _("Other repository doesn't support revision lookup, "
2067 "so a rev cannot be specified.")
2067 "so a rev cannot be specified.")
2068 raise util.Abort(error)
2068 raise util.Abort(error)
2069
2069
2070 modheads = repo.pull(other, heads=revs, force=opts['force'])
2070 modheads = repo.pull(other, heads=revs, force=opts['force'])
2071 return postincoming(ui, repo, modheads, opts['update'], checkout)
2071 return postincoming(ui, repo, modheads, opts['update'], checkout)
2072
2072
2073 def push(ui, repo, dest=None, **opts):
2073 def push(ui, repo, dest=None, **opts):
2074 """push changes to the specified destination
2074 """push changes to the specified destination
2075
2075
2076 Push changes from the local repository to the given destination.
2076 Push changes from the local repository to the given destination.
2077
2077
2078 This is the symmetrical operation for pull. It helps to move
2078 This is the symmetrical operation for pull. It helps to move
2079 changes from the current repository to a different one. If the
2079 changes from the current repository to a different one. If the
2080 destination is local this is identical to a pull in that directory
2080 destination is local this is identical to a pull in that directory
2081 from the current one.
2081 from the current one.
2082
2082
2083 By default, push will refuse to run if it detects the result would
2083 By default, push will refuse to run if it detects the result would
2084 increase the number of remote heads. This generally indicates the
2084 increase the number of remote heads. This generally indicates the
2085 the client has forgotten to sync and merge before pushing.
2085 the client has forgotten to sync and merge before pushing.
2086
2086
2087 Valid URLs are of the form:
2087 Valid URLs are of the form:
2088
2088
2089 local/filesystem/path (or file://local/filesystem/path)
2089 local/filesystem/path (or file://local/filesystem/path)
2090 ssh://[user@]host[:port]/[path]
2090 ssh://[user@]host[:port]/[path]
2091 http://[user@]host[:port]/[path]
2091 http://[user@]host[:port]/[path]
2092 https://[user@]host[:port]/[path]
2092 https://[user@]host[:port]/[path]
2093
2093
2094 An optional identifier after # indicates a particular branch, tag,
2094 An optional identifier after # indicates a particular branch, tag,
2095 or changeset to push.
2095 or changeset to push.
2096
2096
2097 Look at the help text for the pull command for important details
2097 Look at the help text for the pull command for important details
2098 about ssh:// URLs.
2098 about ssh:// URLs.
2099
2099
2100 Pushing to http:// and https:// URLs is only possible, if this
2100 Pushing to http:// and https:// URLs is only possible, if this
2101 feature is explicitly enabled on the remote Mercurial server.
2101 feature is explicitly enabled on the remote Mercurial server.
2102 """
2102 """
2103 dest, revs, checkout = hg.parseurl(
2103 dest, revs, checkout = hg.parseurl(
2104 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2104 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2105 cmdutil.setremoteconfig(ui, opts)
2105 cmdutil.setremoteconfig(ui, opts)
2106
2106
2107 other = hg.repository(ui, dest)
2107 other = hg.repository(ui, dest)
2108 ui.status('pushing to %s\n' % util.hidepassword(dest))
2108 ui.status('pushing to %s\n' % util.hidepassword(dest))
2109 if revs:
2109 if revs:
2110 revs = [repo.lookup(rev) for rev in revs]
2110 revs = [repo.lookup(rev) for rev in revs]
2111 r = repo.push(other, opts['force'], revs=revs)
2111 r = repo.push(other, opts['force'], revs=revs)
2112 return r == 0
2112 return r == 0
2113
2113
2114 def rawcommit(ui, repo, *pats, **opts):
2114 def rawcommit(ui, repo, *pats, **opts):
2115 """raw commit interface (DEPRECATED)
2115 """raw commit interface (DEPRECATED)
2116
2116
2117 (DEPRECATED)
2117 (DEPRECATED)
2118 Lowlevel commit, for use in helper scripts.
2118 Lowlevel commit, for use in helper scripts.
2119
2119
2120 This command is not intended to be used by normal users, as it is
2120 This command is not intended to be used by normal users, as it is
2121 primarily useful for importing from other SCMs.
2121 primarily useful for importing from other SCMs.
2122
2122
2123 This command is now deprecated and will be removed in a future
2123 This command is now deprecated and will be removed in a future
2124 release, please use debugsetparents and commit instead.
2124 release, please use debugsetparents and commit instead.
2125 """
2125 """
2126
2126
2127 ui.warn(_("(the rawcommit command is deprecated)\n"))
2127 ui.warn(_("(the rawcommit command is deprecated)\n"))
2128
2128
2129 message = cmdutil.logmessage(opts)
2129 message = cmdutil.logmessage(opts)
2130
2130
2131 files = cmdutil.match(repo, pats, opts).files()
2131 files = cmdutil.match(repo, pats, opts).files()
2132 if opts['files']:
2132 if opts['files']:
2133 files += open(opts['files']).read().splitlines()
2133 files += open(opts['files']).read().splitlines()
2134
2134
2135 parents = [repo.lookup(p) for p in opts['parent']]
2135 parents = [repo.lookup(p) for p in opts['parent']]
2136
2136
2137 try:
2137 try:
2138 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2138 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2139 except ValueError, inst:
2139 except ValueError, inst:
2140 raise util.Abort(str(inst))
2140 raise util.Abort(str(inst))
2141
2141
2142 def recover(ui, repo):
2142 def recover(ui, repo):
2143 """roll back an interrupted transaction
2143 """roll back an interrupted transaction
2144
2144
2145 Recover from an interrupted commit or pull.
2145 Recover from an interrupted commit or pull.
2146
2146
2147 This command tries to fix the repository status after an interrupted
2147 This command tries to fix the repository status after an interrupted
2148 operation. It should only be necessary when Mercurial suggests it.
2148 operation. It should only be necessary when Mercurial suggests it.
2149 """
2149 """
2150 if repo.recover():
2150 if repo.recover():
2151 return hg.verify(repo)
2151 return hg.verify(repo)
2152 return 1
2152 return 1
2153
2153
2154 def remove(ui, repo, *pats, **opts):
2154 def remove(ui, repo, *pats, **opts):
2155 """remove the specified files on the next commit
2155 """remove the specified files on the next commit
2156
2156
2157 Schedule the indicated files for removal from the repository.
2157 Schedule the indicated files for removal from the repository.
2158
2158
2159 This only removes files from the current branch, not from the entire
2159 This only removes files from the current branch, not from the entire
2160 project history. -A can be used to remove only files that have already
2160 project history. -A can be used to remove only files that have already
2161 been deleted, -f can be used to force deletion, and -Af can be used
2161 been deleted, -f can be used to force deletion, and -Af can be used
2162 to remove files from the next revision without deleting them.
2162 to remove files from the next revision without deleting them.
2163
2163
2164 The following table details the behavior of remove for different file
2164 The following table details the behavior of remove for different file
2165 states (columns) and option combinations (rows). The file states are
2165 states (columns) and option combinations (rows). The file states are
2166 Added, Clean, Modified and Missing (as reported by hg status). The
2166 Added, Clean, Modified and Missing (as reported by hg status). The
2167 actions are Warn, Remove (from branch) and Delete (from disk).
2167 actions are Warn, Remove (from branch) and Delete (from disk).
2168
2168
2169 A C M !
2169 A C M !
2170 none W RD W R
2170 none W RD W R
2171 -f R RD RD R
2171 -f R RD RD R
2172 -A W W W R
2172 -A W W W R
2173 -Af R R R R
2173 -Af R R R R
2174
2174
2175 This command schedules the files to be removed at the next commit.
2175 This command schedules the files to be removed at the next commit.
2176 To undo a remove before that, see hg revert.
2176 To undo a remove before that, see hg revert.
2177 """
2177 """
2178
2178
2179 after, force = opts.get('after'), opts.get('force')
2179 after, force = opts.get('after'), opts.get('force')
2180 if not pats and not after:
2180 if not pats and not after:
2181 raise util.Abort(_('no files specified'))
2181 raise util.Abort(_('no files specified'))
2182
2182
2183 m = cmdutil.match(repo, pats, opts)
2183 m = cmdutil.match(repo, pats, opts)
2184 mardu = map(dict.fromkeys, repo.status(files=m.files(), match=m))[:5]
2184 mardu = map(dict.fromkeys, repo.status(files=m.files(), match=m))[:5]
2185 modified, added, removed, deleted, unknown = mardu
2185 modified, added, removed, deleted, unknown = mardu
2186
2186
2187 remove, forget = [], []
2187 remove, forget = [], []
2188 for abs in repo.walk(m):
2188 for abs in repo.walk(m):
2189
2189
2190 reason = None
2190 reason = None
2191 if abs in removed or abs in unknown:
2191 if abs in removed or abs in unknown:
2192 continue
2192 continue
2193
2193
2194 # last column
2194 # last column
2195 elif abs in deleted:
2195 elif abs in deleted:
2196 remove.append(abs)
2196 remove.append(abs)
2197
2197
2198 # rest of the third row
2198 # rest of the third row
2199 elif after and not force:
2199 elif after and not force:
2200 reason = _('still exists (use -f to force removal)')
2200 reason = _('still exists (use -f to force removal)')
2201
2201
2202 # rest of the first column
2202 # rest of the first column
2203 elif abs in added:
2203 elif abs in added:
2204 if not force:
2204 if not force:
2205 reason = _('has been marked for add (use -f to force removal)')
2205 reason = _('has been marked for add (use -f to force removal)')
2206 else:
2206 else:
2207 forget.append(abs)
2207 forget.append(abs)
2208
2208
2209 # rest of the third column
2209 # rest of the third column
2210 elif abs in modified:
2210 elif abs in modified:
2211 if not force:
2211 if not force:
2212 reason = _('is modified (use -f to force removal)')
2212 reason = _('is modified (use -f to force removal)')
2213 else:
2213 else:
2214 remove.append(abs)
2214 remove.append(abs)
2215
2215
2216 # rest of the second column
2216 # rest of the second column
2217 elif not reason:
2217 elif not reason:
2218 remove.append(abs)
2218 remove.append(abs)
2219
2219
2220 if reason:
2220 if reason:
2221 ui.warn(_('not removing %s: file %s\n') % (m.rel(abs), reason))
2221 ui.warn(_('not removing %s: file %s\n') % (m.rel(abs), reason))
2222 elif ui.verbose or not m.exact(abs):
2222 elif ui.verbose or not m.exact(abs):
2223 ui.status(_('removing %s\n') % m.rel(abs))
2223 ui.status(_('removing %s\n') % m.rel(abs))
2224
2224
2225 repo.forget(forget)
2225 repo.forget(forget)
2226 repo.remove(remove, unlink=not after)
2226 repo.remove(remove, unlink=not after)
2227
2227
2228 def rename(ui, repo, *pats, **opts):
2228 def rename(ui, repo, *pats, **opts):
2229 """rename files; equivalent of copy + remove
2229 """rename files; equivalent of copy + remove
2230
2230
2231 Mark dest as copies of sources; mark sources for deletion. If
2231 Mark dest as copies of sources; mark sources for deletion. If
2232 dest is a directory, copies are put in that directory. If dest is
2232 dest is a directory, copies are put in that directory. If dest is
2233 a file, there can only be one source.
2233 a file, there can only be one source.
2234
2234
2235 By default, this command copies the contents of files as they
2235 By default, this command copies the contents of files as they
2236 stand in the working directory. If invoked with --after, the
2236 stand in the working directory. If invoked with --after, the
2237 operation is recorded, but no copying is performed.
2237 operation is recorded, but no copying is performed.
2238
2238
2239 This command takes effect in the next commit. To undo a rename
2239 This command takes effect in the next commit. To undo a rename
2240 before that, see hg revert.
2240 before that, see hg revert.
2241 """
2241 """
2242 wlock = repo.wlock(False)
2242 wlock = repo.wlock(False)
2243 try:
2243 try:
2244 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2244 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2245 finally:
2245 finally:
2246 del wlock
2246 del wlock
2247
2247
2248 def resolve(ui, repo, *pats, **opts):
2248 def resolve(ui, repo, *pats, **opts):
2249 """resolve file merges from a branch merge or update
2249 """resolve file merges from a branch merge or update
2250
2250
2251 This command will attempt to resolve unresolved merges from the
2251 This command will attempt to resolve unresolved merges from the
2252 last update or merge command. This will use the local file
2252 last update or merge command. This will use the local file
2253 revision preserved at the last update or merge to cleanly retry
2253 revision preserved at the last update or merge to cleanly retry
2254 the file merge attempt. With no file or options specified, this
2254 the file merge attempt. With no file or options specified, this
2255 command will attempt to resolve all unresolved files.
2255 command will attempt to resolve all unresolved files.
2256 """
2256 """
2257
2257
2258 if len([x for x in opts if opts[x]]) > 1:
2258 if len([x for x in opts if opts[x]]) > 1:
2259 raise util.Abort(_("too many options specified"))
2259 raise util.Abort(_("too many options specified"))
2260
2260
2261 ms = merge_.mergestate(repo)
2261 ms = merge_.mergestate(repo)
2262 m = cmdutil.match(repo, pats, opts)
2262 m = cmdutil.match(repo, pats, opts)
2263
2263
2264 for f in ms:
2264 for f in ms:
2265 if m(f):
2265 if m(f):
2266 if opts.get("list"):
2266 if opts.get("list"):
2267 ui.write("%s %s\n" % (ms[f].upper(), f))
2267 ui.write("%s %s\n" % (ms[f].upper(), f))
2268 elif opts.get("mark"):
2268 elif opts.get("mark"):
2269 ms.mark(f, "r")
2269 ms.mark(f, "r")
2270 elif opts.get("unmark"):
2270 elif opts.get("unmark"):
2271 ms.mark(f, "u")
2271 ms.mark(f, "u")
2272 else:
2272 else:
2273 wctx = repo.workingctx()
2273 wctx = repo.workingctx()
2274 mctx = wctx.parents()[-1]
2274 mctx = wctx.parents()[-1]
2275 ms.resolve(f, wctx, mctx)
2275 ms.resolve(f, wctx, mctx)
2276
2276
2277 def revert(ui, repo, *pats, **opts):
2277 def revert(ui, repo, *pats, **opts):
2278 """restore individual files or dirs to an earlier state
2278 """restore individual files or dirs to an earlier state
2279
2279
2280 (use update -r to check out earlier revisions, revert does not
2280 (use update -r to check out earlier revisions, revert does not
2281 change the working dir parents)
2281 change the working dir parents)
2282
2282
2283 With no revision specified, revert the named files or directories
2283 With no revision specified, revert the named files or directories
2284 to the contents they had in the parent of the working directory.
2284 to the contents they had in the parent of the working directory.
2285 This restores the contents of the affected files to an unmodified
2285 This restores the contents of the affected files to an unmodified
2286 state and unschedules adds, removes, copies, and renames. If the
2286 state and unschedules adds, removes, copies, and renames. If the
2287 working directory has two parents, you must explicitly specify the
2287 working directory has two parents, you must explicitly specify the
2288 revision to revert to.
2288 revision to revert to.
2289
2289
2290 Using the -r option, revert the given files or directories to their
2290 Using the -r option, revert the given files or directories to their
2291 contents as of a specific revision. This can be helpful to "roll
2291 contents as of a specific revision. This can be helpful to "roll
2292 back" some or all of an earlier change.
2292 back" some or all of an earlier change.
2293 See 'hg help dates' for a list of formats valid for -d/--date.
2293 See 'hg help dates' for a list of formats valid for -d/--date.
2294
2294
2295 Revert modifies the working directory. It does not commit any
2295 Revert modifies the working directory. It does not commit any
2296 changes, or change the parent of the working directory. If you
2296 changes, or change the parent of the working directory. If you
2297 revert to a revision other than the parent of the working
2297 revert to a revision other than the parent of the working
2298 directory, the reverted files will thus appear modified
2298 directory, the reverted files will thus appear modified
2299 afterwards.
2299 afterwards.
2300
2300
2301 If a file has been deleted, it is restored. If the executable
2301 If a file has been deleted, it is restored. If the executable
2302 mode of a file was changed, it is reset.
2302 mode of a file was changed, it is reset.
2303
2303
2304 If names are given, all files matching the names are reverted.
2304 If names are given, all files matching the names are reverted.
2305 If no arguments are given, no files are reverted.
2305 If no arguments are given, no files are reverted.
2306
2306
2307 Modified files are saved with a .orig suffix before reverting.
2307 Modified files are saved with a .orig suffix before reverting.
2308 To disable these backups, use --no-backup.
2308 To disable these backups, use --no-backup.
2309 """
2309 """
2310
2310
2311 if opts["date"]:
2311 if opts["date"]:
2312 if opts["rev"]:
2312 if opts["rev"]:
2313 raise util.Abort(_("you can't specify a revision and a date"))
2313 raise util.Abort(_("you can't specify a revision and a date"))
2314 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2314 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2315
2315
2316 if not pats and not opts['all']:
2316 if not pats and not opts['all']:
2317 raise util.Abort(_('no files or directories specified; '
2317 raise util.Abort(_('no files or directories specified; '
2318 'use --all to revert the whole repo'))
2318 'use --all to revert the whole repo'))
2319
2319
2320 parent, p2 = repo.dirstate.parents()
2320 parent, p2 = repo.dirstate.parents()
2321 if not opts['rev'] and p2 != nullid:
2321 if not opts['rev'] and p2 != nullid:
2322 raise util.Abort(_('uncommitted merge - please provide a '
2322 raise util.Abort(_('uncommitted merge - please provide a '
2323 'specific revision'))
2323 'specific revision'))
2324 ctx = repo.changectx(opts['rev'])
2324 ctx = repo.changectx(opts['rev'])
2325 node = ctx.node()
2325 node = ctx.node()
2326 mf = ctx.manifest()
2326 mf = ctx.manifest()
2327 if node == parent:
2327 if node == parent:
2328 pmf = mf
2328 pmf = mf
2329 else:
2329 else:
2330 pmf = None
2330 pmf = None
2331
2331
2332 # need all matching names in dirstate and manifest of target rev,
2332 # need all matching names in dirstate and manifest of target rev,
2333 # so have to walk both. do not print errors if files exist in one
2333 # so have to walk both. do not print errors if files exist in one
2334 # but not other.
2334 # but not other.
2335
2335
2336 names = {}
2336 names = {}
2337
2337
2338 wlock = repo.wlock()
2338 wlock = repo.wlock()
2339 try:
2339 try:
2340 # walk dirstate.
2340 # walk dirstate.
2341 files = []
2341 files = []
2342
2342
2343 m = cmdutil.match(repo, pats, opts)
2343 m = cmdutil.match(repo, pats, opts)
2344 m.bad = lambda x,y: False
2344 m.bad = lambda x,y: False
2345 for abs in repo.walk(m):
2345 for abs in repo.walk(m):
2346 names[abs] = m.rel(abs), m.exact(abs)
2346 names[abs] = m.rel(abs), m.exact(abs)
2347
2347
2348 # walk target manifest.
2348 # walk target manifest.
2349
2349
2350 def badfn(path, msg):
2350 def badfn(path, msg):
2351 if path in names:
2351 if path in names:
2352 return False
2352 return False
2353 path_ = path + '/'
2353 path_ = path + '/'
2354 for f in names:
2354 for f in names:
2355 if f.startswith(path_):
2355 if f.startswith(path_):
2356 return False
2356 return False
2357 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2357 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2358 return False
2358 return False
2359
2359
2360 m = cmdutil.match(repo, pats, opts)
2360 m = cmdutil.match(repo, pats, opts)
2361 m.bad = badfn
2361 m.bad = badfn
2362 for abs in repo.walk(m, node=node):
2362 for abs in repo.walk(m, node=node):
2363 if abs not in names:
2363 if abs not in names:
2364 names[abs] = m.rel(abs), m.exact(abs)
2364 names[abs] = m.rel(abs), m.exact(abs)
2365
2365
2366 changes = repo.status(files=files, match=names.has_key)[:4]
2366 m = cmdutil.matchfiles(repo, names)
2367 changes = repo.status(files=m.files(), match=m)[:4]
2367 modified, added, removed, deleted = map(dict.fromkeys, changes)
2368 modified, added, removed, deleted = map(dict.fromkeys, changes)
2368
2369
2369 # if f is a rename, also revert the source
2370 # if f is a rename, also revert the source
2370 cwd = repo.getcwd()
2371 cwd = repo.getcwd()
2371 for f in added:
2372 for f in added:
2372 src = repo.dirstate.copied(f)
2373 src = repo.dirstate.copied(f)
2373 if src and src not in names and repo.dirstate[src] == 'r':
2374 if src and src not in names and repo.dirstate[src] == 'r':
2374 removed[src] = None
2375 removed[src] = None
2375 names[src] = (repo.pathto(src, cwd), True)
2376 names[src] = (repo.pathto(src, cwd), True)
2376
2377
2377 def removeforget(abs):
2378 def removeforget(abs):
2378 if repo.dirstate[abs] == 'a':
2379 if repo.dirstate[abs] == 'a':
2379 return _('forgetting %s\n')
2380 return _('forgetting %s\n')
2380 return _('removing %s\n')
2381 return _('removing %s\n')
2381
2382
2382 revert = ([], _('reverting %s\n'))
2383 revert = ([], _('reverting %s\n'))
2383 add = ([], _('adding %s\n'))
2384 add = ([], _('adding %s\n'))
2384 remove = ([], removeforget)
2385 remove = ([], removeforget)
2385 undelete = ([], _('undeleting %s\n'))
2386 undelete = ([], _('undeleting %s\n'))
2386
2387
2387 disptable = (
2388 disptable = (
2388 # dispatch table:
2389 # dispatch table:
2389 # file state
2390 # file state
2390 # action if in target manifest
2391 # action if in target manifest
2391 # action if not in target manifest
2392 # action if not in target manifest
2392 # make backup if in target manifest
2393 # make backup if in target manifest
2393 # make backup if not in target manifest
2394 # make backup if not in target manifest
2394 (modified, revert, remove, True, True),
2395 (modified, revert, remove, True, True),
2395 (added, revert, remove, True, False),
2396 (added, revert, remove, True, False),
2396 (removed, undelete, None, False, False),
2397 (removed, undelete, None, False, False),
2397 (deleted, revert, remove, False, False),
2398 (deleted, revert, remove, False, False),
2398 )
2399 )
2399
2400
2400 entries = names.items()
2401 entries = names.items()
2401 entries.sort()
2402 entries.sort()
2402
2403
2403 for abs, (rel, exact) in entries:
2404 for abs, (rel, exact) in entries:
2404 mfentry = mf.get(abs)
2405 mfentry = mf.get(abs)
2405 target = repo.wjoin(abs)
2406 target = repo.wjoin(abs)
2406 def handle(xlist, dobackup):
2407 def handle(xlist, dobackup):
2407 xlist[0].append(abs)
2408 xlist[0].append(abs)
2408 if dobackup and not opts['no_backup'] and util.lexists(target):
2409 if dobackup and not opts['no_backup'] and util.lexists(target):
2409 bakname = "%s.orig" % rel
2410 bakname = "%s.orig" % rel
2410 ui.note(_('saving current version of %s as %s\n') %
2411 ui.note(_('saving current version of %s as %s\n') %
2411 (rel, bakname))
2412 (rel, bakname))
2412 if not opts.get('dry_run'):
2413 if not opts.get('dry_run'):
2413 util.copyfile(target, bakname)
2414 util.copyfile(target, bakname)
2414 if ui.verbose or not exact:
2415 if ui.verbose or not exact:
2415 msg = xlist[1]
2416 msg = xlist[1]
2416 if not isinstance(msg, basestring):
2417 if not isinstance(msg, basestring):
2417 msg = msg(abs)
2418 msg = msg(abs)
2418 ui.status(msg % rel)
2419 ui.status(msg % rel)
2419 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2420 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2420 if abs not in table: continue
2421 if abs not in table: continue
2421 # file has changed in dirstate
2422 # file has changed in dirstate
2422 if mfentry:
2423 if mfentry:
2423 handle(hitlist, backuphit)
2424 handle(hitlist, backuphit)
2424 elif misslist is not None:
2425 elif misslist is not None:
2425 handle(misslist, backupmiss)
2426 handle(misslist, backupmiss)
2426 break
2427 break
2427 else:
2428 else:
2428 if abs not in repo.dirstate:
2429 if abs not in repo.dirstate:
2429 if mfentry:
2430 if mfentry:
2430 handle(add, True)
2431 handle(add, True)
2431 elif exact:
2432 elif exact:
2432 ui.warn(_('file not managed: %s\n') % rel)
2433 ui.warn(_('file not managed: %s\n') % rel)
2433 continue
2434 continue
2434 # file has not changed in dirstate
2435 # file has not changed in dirstate
2435 if node == parent:
2436 if node == parent:
2436 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2437 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2437 continue
2438 continue
2438 if pmf is None:
2439 if pmf is None:
2439 # only need parent manifest in this unlikely case,
2440 # only need parent manifest in this unlikely case,
2440 # so do not read by default
2441 # so do not read by default
2441 pmf = repo.changectx(parent).manifest()
2442 pmf = repo.changectx(parent).manifest()
2442 if abs in pmf:
2443 if abs in pmf:
2443 if mfentry:
2444 if mfentry:
2444 # if version of file is same in parent and target
2445 # if version of file is same in parent and target
2445 # manifests, do nothing
2446 # manifests, do nothing
2446 if (pmf[abs] != mfentry or
2447 if (pmf[abs] != mfentry or
2447 pmf.flags(abs) != mf.flags(abs)):
2448 pmf.flags(abs) != mf.flags(abs)):
2448 handle(revert, False)
2449 handle(revert, False)
2449 else:
2450 else:
2450 handle(remove, False)
2451 handle(remove, False)
2451
2452
2452 if not opts.get('dry_run'):
2453 if not opts.get('dry_run'):
2453 def checkout(f):
2454 def checkout(f):
2454 fc = ctx[f]
2455 fc = ctx[f]
2455 repo.wwrite(f, fc.data(), fc.fileflags())
2456 repo.wwrite(f, fc.data(), fc.fileflags())
2456
2457
2457 audit_path = util.path_auditor(repo.root)
2458 audit_path = util.path_auditor(repo.root)
2458 for f in remove[0]:
2459 for f in remove[0]:
2459 if repo.dirstate[f] == 'a':
2460 if repo.dirstate[f] == 'a':
2460 repo.dirstate.forget(f)
2461 repo.dirstate.forget(f)
2461 continue
2462 continue
2462 audit_path(f)
2463 audit_path(f)
2463 try:
2464 try:
2464 util.unlink(repo.wjoin(f))
2465 util.unlink(repo.wjoin(f))
2465 except OSError:
2466 except OSError:
2466 pass
2467 pass
2467 repo.dirstate.remove(f)
2468 repo.dirstate.remove(f)
2468
2469
2469 normal = None
2470 normal = None
2470 if node == parent:
2471 if node == parent:
2471 # We're reverting to our parent. If possible, we'd like status
2472 # We're reverting to our parent. If possible, we'd like status
2472 # to report the file as clean. We have to use normallookup for
2473 # to report the file as clean. We have to use normallookup for
2473 # merges to avoid losing information about merged/dirty files.
2474 # merges to avoid losing information about merged/dirty files.
2474 if p2 != nullid:
2475 if p2 != nullid:
2475 normal = repo.dirstate.normallookup
2476 normal = repo.dirstate.normallookup
2476 else:
2477 else:
2477 normal = repo.dirstate.normal
2478 normal = repo.dirstate.normal
2478 for f in revert[0]:
2479 for f in revert[0]:
2479 checkout(f)
2480 checkout(f)
2480 if normal:
2481 if normal:
2481 normal(f)
2482 normal(f)
2482
2483
2483 for f in add[0]:
2484 for f in add[0]:
2484 checkout(f)
2485 checkout(f)
2485 repo.dirstate.add(f)
2486 repo.dirstate.add(f)
2486
2487
2487 normal = repo.dirstate.normallookup
2488 normal = repo.dirstate.normallookup
2488 if node == parent and p2 == nullid:
2489 if node == parent and p2 == nullid:
2489 normal = repo.dirstate.normal
2490 normal = repo.dirstate.normal
2490 for f in undelete[0]:
2491 for f in undelete[0]:
2491 checkout(f)
2492 checkout(f)
2492 normal(f)
2493 normal(f)
2493
2494
2494 finally:
2495 finally:
2495 del wlock
2496 del wlock
2496
2497
2497 def rollback(ui, repo):
2498 def rollback(ui, repo):
2498 """roll back the last transaction
2499 """roll back the last transaction
2499
2500
2500 This command should be used with care. There is only one level of
2501 This command should be used with care. There is only one level of
2501 rollback, and there is no way to undo a rollback. It will also
2502 rollback, and there is no way to undo a rollback. It will also
2502 restore the dirstate at the time of the last transaction, losing
2503 restore the dirstate at the time of the last transaction, losing
2503 any dirstate changes since that time.
2504 any dirstate changes since that time.
2504
2505
2505 Transactions are used to encapsulate the effects of all commands
2506 Transactions are used to encapsulate the effects of all commands
2506 that create new changesets or propagate existing changesets into a
2507 that create new changesets or propagate existing changesets into a
2507 repository. For example, the following commands are transactional,
2508 repository. For example, the following commands are transactional,
2508 and their effects can be rolled back:
2509 and their effects can be rolled back:
2509
2510
2510 commit
2511 commit
2511 import
2512 import
2512 pull
2513 pull
2513 push (with this repository as destination)
2514 push (with this repository as destination)
2514 unbundle
2515 unbundle
2515
2516
2516 This command is not intended for use on public repositories. Once
2517 This command is not intended for use on public repositories. Once
2517 changes are visible for pull by other users, rolling a transaction
2518 changes are visible for pull by other users, rolling a transaction
2518 back locally is ineffective (someone else may already have pulled
2519 back locally is ineffective (someone else may already have pulled
2519 the changes). Furthermore, a race is possible with readers of the
2520 the changes). Furthermore, a race is possible with readers of the
2520 repository; for example an in-progress pull from the repository
2521 repository; for example an in-progress pull from the repository
2521 may fail if a rollback is performed.
2522 may fail if a rollback is performed.
2522 """
2523 """
2523 repo.rollback()
2524 repo.rollback()
2524
2525
2525 def root(ui, repo):
2526 def root(ui, repo):
2526 """print the root (top) of the current working dir
2527 """print the root (top) of the current working dir
2527
2528
2528 Print the root directory of the current repository.
2529 Print the root directory of the current repository.
2529 """
2530 """
2530 ui.write(repo.root + "\n")
2531 ui.write(repo.root + "\n")
2531
2532
2532 def serve(ui, repo, **opts):
2533 def serve(ui, repo, **opts):
2533 """export the repository via HTTP
2534 """export the repository via HTTP
2534
2535
2535 Start a local HTTP repository browser and pull server.
2536 Start a local HTTP repository browser and pull server.
2536
2537
2537 By default, the server logs accesses to stdout and errors to
2538 By default, the server logs accesses to stdout and errors to
2538 stderr. Use the "-A" and "-E" options to log to files.
2539 stderr. Use the "-A" and "-E" options to log to files.
2539 """
2540 """
2540
2541
2541 if opts["stdio"]:
2542 if opts["stdio"]:
2542 if repo is None:
2543 if repo is None:
2543 raise RepoError(_("There is no Mercurial repository here"
2544 raise RepoError(_("There is no Mercurial repository here"
2544 " (.hg not found)"))
2545 " (.hg not found)"))
2545 s = sshserver.sshserver(ui, repo)
2546 s = sshserver.sshserver(ui, repo)
2546 s.serve_forever()
2547 s.serve_forever()
2547
2548
2548 parentui = ui.parentui or ui
2549 parentui = ui.parentui or ui
2549 optlist = ("name templates style address port prefix ipv6"
2550 optlist = ("name templates style address port prefix ipv6"
2550 " accesslog errorlog webdir_conf certificate")
2551 " accesslog errorlog webdir_conf certificate")
2551 for o in optlist.split():
2552 for o in optlist.split():
2552 if opts[o]:
2553 if opts[o]:
2553 parentui.setconfig("web", o, str(opts[o]))
2554 parentui.setconfig("web", o, str(opts[o]))
2554 if (repo is not None) and (repo.ui != parentui):
2555 if (repo is not None) and (repo.ui != parentui):
2555 repo.ui.setconfig("web", o, str(opts[o]))
2556 repo.ui.setconfig("web", o, str(opts[o]))
2556
2557
2557 if repo is None and not ui.config("web", "webdir_conf"):
2558 if repo is None and not ui.config("web", "webdir_conf"):
2558 raise RepoError(_("There is no Mercurial repository here"
2559 raise RepoError(_("There is no Mercurial repository here"
2559 " (.hg not found)"))
2560 " (.hg not found)"))
2560
2561
2561 class service:
2562 class service:
2562 def init(self):
2563 def init(self):
2563 util.set_signal_handler()
2564 util.set_signal_handler()
2564 self.httpd = hgweb.server.create_server(parentui, repo)
2565 self.httpd = hgweb.server.create_server(parentui, repo)
2565
2566
2566 if not ui.verbose: return
2567 if not ui.verbose: return
2567
2568
2568 if self.httpd.prefix:
2569 if self.httpd.prefix:
2569 prefix = self.httpd.prefix.strip('/') + '/'
2570 prefix = self.httpd.prefix.strip('/') + '/'
2570 else:
2571 else:
2571 prefix = ''
2572 prefix = ''
2572
2573
2573 port = ':%d' % self.httpd.port
2574 port = ':%d' % self.httpd.port
2574 if port == ':80':
2575 if port == ':80':
2575 port = ''
2576 port = ''
2576
2577
2577 bindaddr = self.httpd.addr
2578 bindaddr = self.httpd.addr
2578 if bindaddr == '0.0.0.0':
2579 if bindaddr == '0.0.0.0':
2579 bindaddr = '*'
2580 bindaddr = '*'
2580 elif ':' in bindaddr: # IPv6
2581 elif ':' in bindaddr: # IPv6
2581 bindaddr = '[%s]' % bindaddr
2582 bindaddr = '[%s]' % bindaddr
2582
2583
2583 fqaddr = self.httpd.fqaddr
2584 fqaddr = self.httpd.fqaddr
2584 if ':' in fqaddr:
2585 if ':' in fqaddr:
2585 fqaddr = '[%s]' % fqaddr
2586 fqaddr = '[%s]' % fqaddr
2586 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2587 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2587 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2588 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2588
2589
2589 def run(self):
2590 def run(self):
2590 self.httpd.serve_forever()
2591 self.httpd.serve_forever()
2591
2592
2592 service = service()
2593 service = service()
2593
2594
2594 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2595 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2595
2596
2596 def status(ui, repo, *pats, **opts):
2597 def status(ui, repo, *pats, **opts):
2597 """show changed files in the working directory
2598 """show changed files in the working directory
2598
2599
2599 Show status of files in the repository. If names are given, only
2600 Show status of files in the repository. If names are given, only
2600 files that match are shown. Files that are clean or ignored or
2601 files that match are shown. Files that are clean or ignored or
2601 source of a copy/move operation, are not listed unless -c (clean),
2602 source of a copy/move operation, are not listed unless -c (clean),
2602 -i (ignored), -C (copies) or -A is given. Unless options described
2603 -i (ignored), -C (copies) or -A is given. Unless options described
2603 with "show only ..." are given, the options -mardu are used.
2604 with "show only ..." are given, the options -mardu are used.
2604
2605
2605 Option -q/--quiet hides untracked (unknown and ignored) files
2606 Option -q/--quiet hides untracked (unknown and ignored) files
2606 unless explicitly requested with -u/--unknown or -i/-ignored.
2607 unless explicitly requested with -u/--unknown or -i/-ignored.
2607
2608
2608 NOTE: status may appear to disagree with diff if permissions have
2609 NOTE: status may appear to disagree with diff if permissions have
2609 changed or a merge has occurred. The standard diff format does not
2610 changed or a merge has occurred. The standard diff format does not
2610 report permission changes and diff only reports changes relative
2611 report permission changes and diff only reports changes relative
2611 to one merge parent.
2612 to one merge parent.
2612
2613
2613 If one revision is given, it is used as the base revision.
2614 If one revision is given, it is used as the base revision.
2614 If two revisions are given, the difference between them is shown.
2615 If two revisions are given, the difference between them is shown.
2615
2616
2616 The codes used to show the status of files are:
2617 The codes used to show the status of files are:
2617 M = modified
2618 M = modified
2618 A = added
2619 A = added
2619 R = removed
2620 R = removed
2620 C = clean
2621 C = clean
2621 ! = deleted, but still tracked
2622 ! = deleted, but still tracked
2622 ? = not tracked
2623 ? = not tracked
2623 I = ignored
2624 I = ignored
2624 = the previous added file was copied from here
2625 = the previous added file was copied from here
2625 """
2626 """
2626
2627
2627 all = opts['all']
2628 all = opts['all']
2628 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2629 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2629
2630
2630 matcher = cmdutil.match(repo, pats, opts)
2631 matcher = cmdutil.match(repo, pats, opts)
2631 cwd = (pats and repo.getcwd()) or ''
2632 cwd = (pats and repo.getcwd()) or ''
2632 modified, added, removed, deleted, unknown, ignored, clean = [
2633 modified, added, removed, deleted, unknown, ignored, clean = [
2633 n for n in repo.status(node1, node2, matcher.files(), matcher,
2634 n for n in repo.status(node1, node2, matcher.files(), matcher,
2634 list_ignored=opts['ignored']
2635 list_ignored=opts['ignored']
2635 or all and not ui.quiet,
2636 or all and not ui.quiet,
2636 list_clean=opts['clean'] or all,
2637 list_clean=opts['clean'] or all,
2637 list_unknown=opts['unknown']
2638 list_unknown=opts['unknown']
2638 or not (ui.quiet or
2639 or not (ui.quiet or
2639 opts['modified'] or
2640 opts['modified'] or
2640 opts['added'] or
2641 opts['added'] or
2641 opts['removed'] or
2642 opts['removed'] or
2642 opts['deleted'] or
2643 opts['deleted'] or
2643 opts['ignored']))]
2644 opts['ignored']))]
2644
2645
2645 changetypes = (('modified', 'M', modified),
2646 changetypes = (('modified', 'M', modified),
2646 ('added', 'A', added),
2647 ('added', 'A', added),
2647 ('removed', 'R', removed),
2648 ('removed', 'R', removed),
2648 ('deleted', '!', deleted),
2649 ('deleted', '!', deleted),
2649 ('unknown', '?', unknown),
2650 ('unknown', '?', unknown),
2650 ('ignored', 'I', ignored))
2651 ('ignored', 'I', ignored))
2651
2652
2652 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2653 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2653
2654
2654 copy = {}
2655 copy = {}
2655 showcopy = {}
2656 showcopy = {}
2656 if ((all or opts.get('copies')) and not opts.get('no_status')):
2657 if ((all or opts.get('copies')) and not opts.get('no_status')):
2657 if opts.get('rev') == []:
2658 if opts.get('rev') == []:
2658 # fast path, more correct with merge parents
2659 # fast path, more correct with merge parents
2659 showcopy = copy = repo.dirstate.copies().copy()
2660 showcopy = copy = repo.dirstate.copies().copy()
2660 else:
2661 else:
2661 ctxn = repo.changectx(nullid)
2662 ctxn = repo.changectx(nullid)
2662 ctx1 = repo.changectx(node1)
2663 ctx1 = repo.changectx(node1)
2663 ctx2 = repo.changectx(node2)
2664 ctx2 = repo.changectx(node2)
2664 if node2 is None:
2665 if node2 is None:
2665 ctx2 = repo.workingctx()
2666 ctx2 = repo.workingctx()
2666 copy, diverge = copies.copies(repo, ctx1, ctx2, ctxn)
2667 copy, diverge = copies.copies(repo, ctx1, ctx2, ctxn)
2667 for k, v in copy.items():
2668 for k, v in copy.items():
2668 copy[v] = k
2669 copy[v] = k
2669
2670
2670 end = opts['print0'] and '\0' or '\n'
2671 end = opts['print0'] and '\0' or '\n'
2671
2672
2672 for opt, char, changes in ([ct for ct in explicit_changetypes
2673 for opt, char, changes in ([ct for ct in explicit_changetypes
2673 if all or opts[ct[0]]]
2674 if all or opts[ct[0]]]
2674 or changetypes):
2675 or changetypes):
2675
2676
2676 if opts['no_status']:
2677 if opts['no_status']:
2677 format = "%%s%s" % end
2678 format = "%%s%s" % end
2678 else:
2679 else:
2679 format = "%s %%s%s" % (char, end)
2680 format = "%s %%s%s" % (char, end)
2680
2681
2681 for f in changes:
2682 for f in changes:
2682 ui.write(format % repo.pathto(f, cwd))
2683 ui.write(format % repo.pathto(f, cwd))
2683 if f in copy and (f in added or f in showcopy):
2684 if f in copy and (f in added or f in showcopy):
2684 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2685 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2685
2686
2686 def tag(ui, repo, name1, *names, **opts):
2687 def tag(ui, repo, name1, *names, **opts):
2687 """add one or more tags for the current or given revision
2688 """add one or more tags for the current or given revision
2688
2689
2689 Name a particular revision using <name>.
2690 Name a particular revision using <name>.
2690
2691
2691 Tags are used to name particular revisions of the repository and are
2692 Tags are used to name particular revisions of the repository and are
2692 very useful to compare different revisions, to go back to significant
2693 very useful to compare different revisions, to go back to significant
2693 earlier versions or to mark branch points as releases, etc.
2694 earlier versions or to mark branch points as releases, etc.
2694
2695
2695 If no revision is given, the parent of the working directory is used,
2696 If no revision is given, the parent of the working directory is used,
2696 or tip if no revision is checked out.
2697 or tip if no revision is checked out.
2697
2698
2698 To facilitate version control, distribution, and merging of tags,
2699 To facilitate version control, distribution, and merging of tags,
2699 they are stored as a file named ".hgtags" which is managed
2700 they are stored as a file named ".hgtags" which is managed
2700 similarly to other project files and can be hand-edited if
2701 similarly to other project files and can be hand-edited if
2701 necessary. The file '.hg/localtags' is used for local tags (not
2702 necessary. The file '.hg/localtags' is used for local tags (not
2702 shared among repositories).
2703 shared among repositories).
2703
2704
2704 See 'hg help dates' for a list of formats valid for -d/--date.
2705 See 'hg help dates' for a list of formats valid for -d/--date.
2705 """
2706 """
2706
2707
2707 rev_ = None
2708 rev_ = None
2708 names = (name1,) + names
2709 names = (name1,) + names
2709 if len(names) != len(dict.fromkeys(names)):
2710 if len(names) != len(dict.fromkeys(names)):
2710 raise util.Abort(_('tag names must be unique'))
2711 raise util.Abort(_('tag names must be unique'))
2711 for n in names:
2712 for n in names:
2712 if n in ['tip', '.', 'null']:
2713 if n in ['tip', '.', 'null']:
2713 raise util.Abort(_('the name \'%s\' is reserved') % n)
2714 raise util.Abort(_('the name \'%s\' is reserved') % n)
2714 if opts['rev'] and opts['remove']:
2715 if opts['rev'] and opts['remove']:
2715 raise util.Abort(_("--rev and --remove are incompatible"))
2716 raise util.Abort(_("--rev and --remove are incompatible"))
2716 if opts['rev']:
2717 if opts['rev']:
2717 rev_ = opts['rev']
2718 rev_ = opts['rev']
2718 message = opts['message']
2719 message = opts['message']
2719 if opts['remove']:
2720 if opts['remove']:
2720 expectedtype = opts['local'] and 'local' or 'global'
2721 expectedtype = opts['local'] and 'local' or 'global'
2721 for n in names:
2722 for n in names:
2722 if not repo.tagtype(n):
2723 if not repo.tagtype(n):
2723 raise util.Abort(_('tag \'%s\' does not exist') % n)
2724 raise util.Abort(_('tag \'%s\' does not exist') % n)
2724 if repo.tagtype(n) != expectedtype:
2725 if repo.tagtype(n) != expectedtype:
2725 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2726 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2726 (n, expectedtype))
2727 (n, expectedtype))
2727 rev_ = nullid
2728 rev_ = nullid
2728 if not message:
2729 if not message:
2729 message = _('Removed tag %s') % ', '.join(names)
2730 message = _('Removed tag %s') % ', '.join(names)
2730 elif not opts['force']:
2731 elif not opts['force']:
2731 for n in names:
2732 for n in names:
2732 if n in repo.tags():
2733 if n in repo.tags():
2733 raise util.Abort(_('tag \'%s\' already exists '
2734 raise util.Abort(_('tag \'%s\' already exists '
2734 '(use -f to force)') % n)
2735 '(use -f to force)') % n)
2735 if not rev_ and repo.dirstate.parents()[1] != nullid:
2736 if not rev_ and repo.dirstate.parents()[1] != nullid:
2736 raise util.Abort(_('uncommitted merge - please provide a '
2737 raise util.Abort(_('uncommitted merge - please provide a '
2737 'specific revision'))
2738 'specific revision'))
2738 r = repo.changectx(rev_).node()
2739 r = repo.changectx(rev_).node()
2739
2740
2740 if not message:
2741 if not message:
2741 message = (_('Added tag %s for changeset %s') %
2742 message = (_('Added tag %s for changeset %s') %
2742 (', '.join(names), short(r)))
2743 (', '.join(names), short(r)))
2743
2744
2744 date = opts.get('date')
2745 date = opts.get('date')
2745 if date:
2746 if date:
2746 date = util.parsedate(date)
2747 date = util.parsedate(date)
2747
2748
2748 repo.tag(names, r, message, opts['local'], opts['user'], date)
2749 repo.tag(names, r, message, opts['local'], opts['user'], date)
2749
2750
2750 def tags(ui, repo):
2751 def tags(ui, repo):
2751 """list repository tags
2752 """list repository tags
2752
2753
2753 List the repository tags.
2754 List the repository tags.
2754
2755
2755 This lists both regular and local tags. When the -v/--verbose switch
2756 This lists both regular and local tags. When the -v/--verbose switch
2756 is used, a third column "local" is printed for local tags.
2757 is used, a third column "local" is printed for local tags.
2757 """
2758 """
2758
2759
2759 l = repo.tagslist()
2760 l = repo.tagslist()
2760 l.reverse()
2761 l.reverse()
2761 hexfunc = ui.debugflag and hex or short
2762 hexfunc = ui.debugflag and hex or short
2762 tagtype = ""
2763 tagtype = ""
2763
2764
2764 for t, n in l:
2765 for t, n in l:
2765 if ui.quiet:
2766 if ui.quiet:
2766 ui.write("%s\n" % t)
2767 ui.write("%s\n" % t)
2767 continue
2768 continue
2768
2769
2769 try:
2770 try:
2770 hn = hexfunc(n)
2771 hn = hexfunc(n)
2771 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2772 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2772 except revlog.LookupError:
2773 except revlog.LookupError:
2773 r = " ?:%s" % hn
2774 r = " ?:%s" % hn
2774 else:
2775 else:
2775 spaces = " " * (30 - util.locallen(t))
2776 spaces = " " * (30 - util.locallen(t))
2776 if ui.verbose:
2777 if ui.verbose:
2777 if repo.tagtype(t) == 'local':
2778 if repo.tagtype(t) == 'local':
2778 tagtype = " local"
2779 tagtype = " local"
2779 else:
2780 else:
2780 tagtype = ""
2781 tagtype = ""
2781 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2782 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2782
2783
2783 def tip(ui, repo, **opts):
2784 def tip(ui, repo, **opts):
2784 """show the tip revision
2785 """show the tip revision
2785
2786
2786 The tip revision (usually just called the tip) is the most
2787 The tip revision (usually just called the tip) is the most
2787 recently added changeset in the repository, the most recently
2788 recently added changeset in the repository, the most recently
2788 changed head.
2789 changed head.
2789
2790
2790 If you have just made a commit, that commit will be the tip. If
2791 If you have just made a commit, that commit will be the tip. If
2791 you have just pulled changes from another repository, the tip of
2792 you have just pulled changes from another repository, the tip of
2792 that repository becomes the current tip. The "tip" tag is special
2793 that repository becomes the current tip. The "tip" tag is special
2793 and cannot be renamed or assigned to a different changeset.
2794 and cannot be renamed or assigned to a different changeset.
2794 """
2795 """
2795 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2796 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2796
2797
2797 def unbundle(ui, repo, fname1, *fnames, **opts):
2798 def unbundle(ui, repo, fname1, *fnames, **opts):
2798 """apply one or more changegroup files
2799 """apply one or more changegroup files
2799
2800
2800 Apply one or more compressed changegroup files generated by the
2801 Apply one or more compressed changegroup files generated by the
2801 bundle command.
2802 bundle command.
2802 """
2803 """
2803 fnames = (fname1,) + fnames
2804 fnames = (fname1,) + fnames
2804
2805
2805 lock = None
2806 lock = None
2806 try:
2807 try:
2807 lock = repo.lock()
2808 lock = repo.lock()
2808 for fname in fnames:
2809 for fname in fnames:
2809 if os.path.exists(fname):
2810 if os.path.exists(fname):
2810 f = open(fname, "rb")
2811 f = open(fname, "rb")
2811 else:
2812 else:
2812 f = urllib.urlopen(fname)
2813 f = urllib.urlopen(fname)
2813 gen = changegroup.readbundle(f, fname)
2814 gen = changegroup.readbundle(f, fname)
2814 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2815 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2815 finally:
2816 finally:
2816 del lock
2817 del lock
2817
2818
2818 return postincoming(ui, repo, modheads, opts['update'], None)
2819 return postincoming(ui, repo, modheads, opts['update'], None)
2819
2820
2820 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2821 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2821 """update working directory
2822 """update working directory
2822
2823
2823 Update the working directory to the specified revision, or the
2824 Update the working directory to the specified revision, or the
2824 tip of the current branch if none is specified.
2825 tip of the current branch if none is specified.
2825
2826
2826 If the requested revision is a descendant of the working
2827 If the requested revision is a descendant of the working
2827 directory, any outstanding changes in the working directory will
2828 directory, any outstanding changes in the working directory will
2828 be merged into the result. If it is not directly descended but is
2829 be merged into the result. If it is not directly descended but is
2829 on the same named branch, update aborts with a suggestion to use
2830 on the same named branch, update aborts with a suggestion to use
2830 merge or update -C instead.
2831 merge or update -C instead.
2831
2832
2832 If the requested revision is on a different named branch and the
2833 If the requested revision is on a different named branch and the
2833 working directory is clean, update quietly switches branches.
2834 working directory is clean, update quietly switches branches.
2834
2835
2835 See 'hg help dates' for a list of formats valid for --date.
2836 See 'hg help dates' for a list of formats valid for --date.
2836 """
2837 """
2837 if rev and node:
2838 if rev and node:
2838 raise util.Abort(_("please specify just one revision"))
2839 raise util.Abort(_("please specify just one revision"))
2839
2840
2840 if not rev:
2841 if not rev:
2841 rev = node
2842 rev = node
2842
2843
2843 if date:
2844 if date:
2844 if rev:
2845 if rev:
2845 raise util.Abort(_("you can't specify a revision and a date"))
2846 raise util.Abort(_("you can't specify a revision and a date"))
2846 rev = cmdutil.finddate(ui, repo, date)
2847 rev = cmdutil.finddate(ui, repo, date)
2847
2848
2848 if clean:
2849 if clean:
2849 return hg.clean(repo, rev)
2850 return hg.clean(repo, rev)
2850 else:
2851 else:
2851 return hg.update(repo, rev)
2852 return hg.update(repo, rev)
2852
2853
2853 def verify(ui, repo):
2854 def verify(ui, repo):
2854 """verify the integrity of the repository
2855 """verify the integrity of the repository
2855
2856
2856 Verify the integrity of the current repository.
2857 Verify the integrity of the current repository.
2857
2858
2858 This will perform an extensive check of the repository's
2859 This will perform an extensive check of the repository's
2859 integrity, validating the hashes and checksums of each entry in
2860 integrity, validating the hashes and checksums of each entry in
2860 the changelog, manifest, and tracked files, as well as the
2861 the changelog, manifest, and tracked files, as well as the
2861 integrity of their crosslinks and indices.
2862 integrity of their crosslinks and indices.
2862 """
2863 """
2863 return hg.verify(repo)
2864 return hg.verify(repo)
2864
2865
2865 def version_(ui):
2866 def version_(ui):
2866 """output version and copyright information"""
2867 """output version and copyright information"""
2867 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2868 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2868 % version.get_version())
2869 % version.get_version())
2869 ui.status(_(
2870 ui.status(_(
2870 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2871 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2871 "This is free software; see the source for copying conditions. "
2872 "This is free software; see the source for copying conditions. "
2872 "There is NO\nwarranty; "
2873 "There is NO\nwarranty; "
2873 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2874 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2874 ))
2875 ))
2875
2876
2876 # Command options and aliases are listed here, alphabetically
2877 # Command options and aliases are listed here, alphabetically
2877
2878
2878 globalopts = [
2879 globalopts = [
2879 ('R', 'repository', '',
2880 ('R', 'repository', '',
2880 _('repository root directory or symbolic path name')),
2881 _('repository root directory or symbolic path name')),
2881 ('', 'cwd', '', _('change working directory')),
2882 ('', 'cwd', '', _('change working directory')),
2882 ('y', 'noninteractive', None,
2883 ('y', 'noninteractive', None,
2883 _('do not prompt, assume \'yes\' for any required answers')),
2884 _('do not prompt, assume \'yes\' for any required answers')),
2884 ('q', 'quiet', None, _('suppress output')),
2885 ('q', 'quiet', None, _('suppress output')),
2885 ('v', 'verbose', None, _('enable additional output')),
2886 ('v', 'verbose', None, _('enable additional output')),
2886 ('', 'config', [], _('set/override config option')),
2887 ('', 'config', [], _('set/override config option')),
2887 ('', 'debug', None, _('enable debugging output')),
2888 ('', 'debug', None, _('enable debugging output')),
2888 ('', 'debugger', None, _('start debugger')),
2889 ('', 'debugger', None, _('start debugger')),
2889 ('', 'encoding', util._encoding, _('set the charset encoding')),
2890 ('', 'encoding', util._encoding, _('set the charset encoding')),
2890 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2891 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2891 ('', 'lsprof', None, _('print improved command execution profile')),
2892 ('', 'lsprof', None, _('print improved command execution profile')),
2892 ('', 'traceback', None, _('print traceback on exception')),
2893 ('', 'traceback', None, _('print traceback on exception')),
2893 ('', 'time', None, _('time how long the command takes')),
2894 ('', 'time', None, _('time how long the command takes')),
2894 ('', 'profile', None, _('print command execution profile')),
2895 ('', 'profile', None, _('print command execution profile')),
2895 ('', 'version', None, _('output version information and exit')),
2896 ('', 'version', None, _('output version information and exit')),
2896 ('h', 'help', None, _('display help and exit')),
2897 ('h', 'help', None, _('display help and exit')),
2897 ]
2898 ]
2898
2899
2899 dryrunopts = [('n', 'dry-run', None,
2900 dryrunopts = [('n', 'dry-run', None,
2900 _('do not perform actions, just print output'))]
2901 _('do not perform actions, just print output'))]
2901
2902
2902 remoteopts = [
2903 remoteopts = [
2903 ('e', 'ssh', '', _('specify ssh command to use')),
2904 ('e', 'ssh', '', _('specify ssh command to use')),
2904 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2905 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2905 ]
2906 ]
2906
2907
2907 walkopts = [
2908 walkopts = [
2908 ('I', 'include', [], _('include names matching the given patterns')),
2909 ('I', 'include', [], _('include names matching the given patterns')),
2909 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2910 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2910 ]
2911 ]
2911
2912
2912 commitopts = [
2913 commitopts = [
2913 ('m', 'message', '', _('use <text> as commit message')),
2914 ('m', 'message', '', _('use <text> as commit message')),
2914 ('l', 'logfile', '', _('read commit message from <file>')),
2915 ('l', 'logfile', '', _('read commit message from <file>')),
2915 ]
2916 ]
2916
2917
2917 commitopts2 = [
2918 commitopts2 = [
2918 ('d', 'date', '', _('record datecode as commit date')),
2919 ('d', 'date', '', _('record datecode as commit date')),
2919 ('u', 'user', '', _('record user as committer')),
2920 ('u', 'user', '', _('record user as committer')),
2920 ]
2921 ]
2921
2922
2922 templateopts = [
2923 templateopts = [
2923 ('', 'style', '', _('display using template map file')),
2924 ('', 'style', '', _('display using template map file')),
2924 ('', 'template', '', _('display with template')),
2925 ('', 'template', '', _('display with template')),
2925 ]
2926 ]
2926
2927
2927 logopts = [
2928 logopts = [
2928 ('p', 'patch', None, _('show patch')),
2929 ('p', 'patch', None, _('show patch')),
2929 ('l', 'limit', '', _('limit number of changes displayed')),
2930 ('l', 'limit', '', _('limit number of changes displayed')),
2930 ('M', 'no-merges', None, _('do not show merges')),
2931 ('M', 'no-merges', None, _('do not show merges')),
2931 ] + templateopts
2932 ] + templateopts
2932
2933
2933 table = {
2934 table = {
2934 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2935 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2935 "addremove":
2936 "addremove":
2936 (addremove,
2937 (addremove,
2937 [('s', 'similarity', '',
2938 [('s', 'similarity', '',
2938 _('guess renamed files by similarity (0<=s<=100)')),
2939 _('guess renamed files by similarity (0<=s<=100)')),
2939 ] + walkopts + dryrunopts,
2940 ] + walkopts + dryrunopts,
2940 _('hg addremove [OPTION]... [FILE]...')),
2941 _('hg addremove [OPTION]... [FILE]...')),
2941 "^annotate|blame":
2942 "^annotate|blame":
2942 (annotate,
2943 (annotate,
2943 [('r', 'rev', '', _('annotate the specified revision')),
2944 [('r', 'rev', '', _('annotate the specified revision')),
2944 ('f', 'follow', None, _('follow file copies and renames')),
2945 ('f', 'follow', None, _('follow file copies and renames')),
2945 ('a', 'text', None, _('treat all files as text')),
2946 ('a', 'text', None, _('treat all files as text')),
2946 ('u', 'user', None, _('list the author (long with -v)')),
2947 ('u', 'user', None, _('list the author (long with -v)')),
2947 ('d', 'date', None, _('list the date (short with -q)')),
2948 ('d', 'date', None, _('list the date (short with -q)')),
2948 ('n', 'number', None, _('list the revision number (default)')),
2949 ('n', 'number', None, _('list the revision number (default)')),
2949 ('c', 'changeset', None, _('list the changeset')),
2950 ('c', 'changeset', None, _('list the changeset')),
2950 ('l', 'line-number', None,
2951 ('l', 'line-number', None,
2951 _('show line number at the first appearance'))
2952 _('show line number at the first appearance'))
2952 ] + walkopts,
2953 ] + walkopts,
2953 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2954 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2954 "archive":
2955 "archive":
2955 (archive,
2956 (archive,
2956 [('', 'no-decode', None, _('do not pass files through decoders')),
2957 [('', 'no-decode', None, _('do not pass files through decoders')),
2957 ('p', 'prefix', '', _('directory prefix for files in archive')),
2958 ('p', 'prefix', '', _('directory prefix for files in archive')),
2958 ('r', 'rev', '', _('revision to distribute')),
2959 ('r', 'rev', '', _('revision to distribute')),
2959 ('t', 'type', '', _('type of distribution to create')),
2960 ('t', 'type', '', _('type of distribution to create')),
2960 ] + walkopts,
2961 ] + walkopts,
2961 _('hg archive [OPTION]... DEST')),
2962 _('hg archive [OPTION]... DEST')),
2962 "backout":
2963 "backout":
2963 (backout,
2964 (backout,
2964 [('', 'merge', None,
2965 [('', 'merge', None,
2965 _('merge with old dirstate parent after backout')),
2966 _('merge with old dirstate parent after backout')),
2966 ('', 'parent', '', _('parent to choose when backing out merge')),
2967 ('', 'parent', '', _('parent to choose when backing out merge')),
2967 ('r', 'rev', '', _('revision to backout')),
2968 ('r', 'rev', '', _('revision to backout')),
2968 ] + walkopts + commitopts + commitopts2,
2969 ] + walkopts + commitopts + commitopts2,
2969 _('hg backout [OPTION]... [-r] REV')),
2970 _('hg backout [OPTION]... [-r] REV')),
2970 "bisect":
2971 "bisect":
2971 (bisect,
2972 (bisect,
2972 [('r', 'reset', False, _('reset bisect state')),
2973 [('r', 'reset', False, _('reset bisect state')),
2973 ('g', 'good', False, _('mark changeset good')),
2974 ('g', 'good', False, _('mark changeset good')),
2974 ('b', 'bad', False, _('mark changeset bad')),
2975 ('b', 'bad', False, _('mark changeset bad')),
2975 ('s', 'skip', False, _('skip testing changeset')),
2976 ('s', 'skip', False, _('skip testing changeset')),
2976 ('U', 'noupdate', False, _('do not update to target'))],
2977 ('U', 'noupdate', False, _('do not update to target'))],
2977 _("hg bisect [-gbsr] [REV]")),
2978 _("hg bisect [-gbsr] [REV]")),
2978 "branch":
2979 "branch":
2979 (branch,
2980 (branch,
2980 [('f', 'force', None,
2981 [('f', 'force', None,
2981 _('set branch name even if it shadows an existing branch'))],
2982 _('set branch name even if it shadows an existing branch'))],
2982 _('hg branch [-f] [NAME]')),
2983 _('hg branch [-f] [NAME]')),
2983 "branches":
2984 "branches":
2984 (branches,
2985 (branches,
2985 [('a', 'active', False,
2986 [('a', 'active', False,
2986 _('show only branches that have unmerged heads'))],
2987 _('show only branches that have unmerged heads'))],
2987 _('hg branches [-a]')),
2988 _('hg branches [-a]')),
2988 "bundle":
2989 "bundle":
2989 (bundle,
2990 (bundle,
2990 [('f', 'force', None,
2991 [('f', 'force', None,
2991 _('run even when remote repository is unrelated')),
2992 _('run even when remote repository is unrelated')),
2992 ('r', 'rev', [],
2993 ('r', 'rev', [],
2993 _('a changeset up to which you would like to bundle')),
2994 _('a changeset up to which you would like to bundle')),
2994 ('', 'base', [],
2995 ('', 'base', [],
2995 _('a base changeset to specify instead of a destination')),
2996 _('a base changeset to specify instead of a destination')),
2996 ('a', 'all', None, _('bundle all changesets in the repository')),
2997 ('a', 'all', None, _('bundle all changesets in the repository')),
2997 ('t', 'type', 'bzip2', _('bundle compression type to use')),
2998 ('t', 'type', 'bzip2', _('bundle compression type to use')),
2998 ] + remoteopts,
2999 ] + remoteopts,
2999 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3000 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3000 "cat":
3001 "cat":
3001 (cat,
3002 (cat,
3002 [('o', 'output', '', _('print output to file with formatted name')),
3003 [('o', 'output', '', _('print output to file with formatted name')),
3003 ('r', 'rev', '', _('print the given revision')),
3004 ('r', 'rev', '', _('print the given revision')),
3004 ('', 'decode', None, _('apply any matching decode filter')),
3005 ('', 'decode', None, _('apply any matching decode filter')),
3005 ] + walkopts,
3006 ] + walkopts,
3006 _('hg cat [OPTION]... FILE...')),
3007 _('hg cat [OPTION]... FILE...')),
3007 "^clone":
3008 "^clone":
3008 (clone,
3009 (clone,
3009 [('U', 'noupdate', None, _('do not update the new working directory')),
3010 [('U', 'noupdate', None, _('do not update the new working directory')),
3010 ('r', 'rev', [],
3011 ('r', 'rev', [],
3011 _('a changeset you would like to have after cloning')),
3012 _('a changeset you would like to have after cloning')),
3012 ('', 'pull', None, _('use pull protocol to copy metadata')),
3013 ('', 'pull', None, _('use pull protocol to copy metadata')),
3013 ('', 'uncompressed', None,
3014 ('', 'uncompressed', None,
3014 _('use uncompressed transfer (fast over LAN)')),
3015 _('use uncompressed transfer (fast over LAN)')),
3015 ] + remoteopts,
3016 ] + remoteopts,
3016 _('hg clone [OPTION]... SOURCE [DEST]')),
3017 _('hg clone [OPTION]... SOURCE [DEST]')),
3017 "^commit|ci":
3018 "^commit|ci":
3018 (commit,
3019 (commit,
3019 [('A', 'addremove', None,
3020 [('A', 'addremove', None,
3020 _('mark new/missing files as added/removed before committing')),
3021 _('mark new/missing files as added/removed before committing')),
3021 ] + walkopts + commitopts + commitopts2,
3022 ] + walkopts + commitopts + commitopts2,
3022 _('hg commit [OPTION]... [FILE]...')),
3023 _('hg commit [OPTION]... [FILE]...')),
3023 "copy|cp":
3024 "copy|cp":
3024 (copy,
3025 (copy,
3025 [('A', 'after', None, _('record a copy that has already occurred')),
3026 [('A', 'after', None, _('record a copy that has already occurred')),
3026 ('f', 'force', None,
3027 ('f', 'force', None,
3027 _('forcibly copy over an existing managed file')),
3028 _('forcibly copy over an existing managed file')),
3028 ] + walkopts + dryrunopts,
3029 ] + walkopts + dryrunopts,
3029 _('hg copy [OPTION]... [SOURCE]... DEST')),
3030 _('hg copy [OPTION]... [SOURCE]... DEST')),
3030 "debugancestor": (debugancestor, [],
3031 "debugancestor": (debugancestor, [],
3031 _('hg debugancestor [INDEX] REV1 REV2')),
3032 _('hg debugancestor [INDEX] REV1 REV2')),
3032 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3033 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3033 "debugcomplete":
3034 "debugcomplete":
3034 (debugcomplete,
3035 (debugcomplete,
3035 [('o', 'options', None, _('show the command options'))],
3036 [('o', 'options', None, _('show the command options'))],
3036 _('hg debugcomplete [-o] CMD')),
3037 _('hg debugcomplete [-o] CMD')),
3037 "debugdate":
3038 "debugdate":
3038 (debugdate,
3039 (debugdate,
3039 [('e', 'extended', None, _('try extended date formats'))],
3040 [('e', 'extended', None, _('try extended date formats'))],
3040 _('hg debugdate [-e] DATE [RANGE]')),
3041 _('hg debugdate [-e] DATE [RANGE]')),
3041 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3042 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3042 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3043 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3043 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3044 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3044 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3045 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3045 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3046 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3046 "debugrawcommit|rawcommit":
3047 "debugrawcommit|rawcommit":
3047 (rawcommit,
3048 (rawcommit,
3048 [('p', 'parent', [], _('parent')),
3049 [('p', 'parent', [], _('parent')),
3049 ('F', 'files', '', _('file list'))
3050 ('F', 'files', '', _('file list'))
3050 ] + commitopts + commitopts2,
3051 ] + commitopts + commitopts2,
3051 _('hg debugrawcommit [OPTION]... [FILE]...')),
3052 _('hg debugrawcommit [OPTION]... [FILE]...')),
3052 "debugrebuildstate":
3053 "debugrebuildstate":
3053 (debugrebuildstate,
3054 (debugrebuildstate,
3054 [('r', 'rev', '', _('revision to rebuild to'))],
3055 [('r', 'rev', '', _('revision to rebuild to'))],
3055 _('hg debugrebuildstate [-r REV] [REV]')),
3056 _('hg debugrebuildstate [-r REV] [REV]')),
3056 "debugrename":
3057 "debugrename":
3057 (debugrename,
3058 (debugrename,
3058 [('r', 'rev', '', _('revision to debug'))],
3059 [('r', 'rev', '', _('revision to debug'))],
3059 _('hg debugrename [-r REV] FILE')),
3060 _('hg debugrename [-r REV] FILE')),
3060 "debugsetparents":
3061 "debugsetparents":
3061 (debugsetparents,
3062 (debugsetparents,
3062 [],
3063 [],
3063 _('hg debugsetparents REV1 [REV2]')),
3064 _('hg debugsetparents REV1 [REV2]')),
3064 "debugstate":
3065 "debugstate":
3065 (debugstate,
3066 (debugstate,
3066 [('', 'nodates', None, _('do not display the saved mtime'))],
3067 [('', 'nodates', None, _('do not display the saved mtime'))],
3067 _('hg debugstate [OPTS]')),
3068 _('hg debugstate [OPTS]')),
3068 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3069 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3069 "^diff":
3070 "^diff":
3070 (diff,
3071 (diff,
3071 [('r', 'rev', [], _('revision')),
3072 [('r', 'rev', [], _('revision')),
3072 ('a', 'text', None, _('treat all files as text')),
3073 ('a', 'text', None, _('treat all files as text')),
3073 ('p', 'show-function', None,
3074 ('p', 'show-function', None,
3074 _('show which function each change is in')),
3075 _('show which function each change is in')),
3075 ('g', 'git', None, _('use git extended diff format')),
3076 ('g', 'git', None, _('use git extended diff format')),
3076 ('', 'nodates', None, _("don't include dates in diff headers")),
3077 ('', 'nodates', None, _("don't include dates in diff headers")),
3077 ('w', 'ignore-all-space', None,
3078 ('w', 'ignore-all-space', None,
3078 _('ignore white space when comparing lines')),
3079 _('ignore white space when comparing lines')),
3079 ('b', 'ignore-space-change', None,
3080 ('b', 'ignore-space-change', None,
3080 _('ignore changes in the amount of white space')),
3081 _('ignore changes in the amount of white space')),
3081 ('B', 'ignore-blank-lines', None,
3082 ('B', 'ignore-blank-lines', None,
3082 _('ignore changes whose lines are all blank')),
3083 _('ignore changes whose lines are all blank')),
3083 ('U', 'unified', '',
3084 ('U', 'unified', '',
3084 _('number of lines of context to show'))
3085 _('number of lines of context to show'))
3085 ] + walkopts,
3086 ] + walkopts,
3086 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3087 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3087 "^export":
3088 "^export":
3088 (export,
3089 (export,
3089 [('o', 'output', '', _('print output to file with formatted name')),
3090 [('o', 'output', '', _('print output to file with formatted name')),
3090 ('a', 'text', None, _('treat all files as text')),
3091 ('a', 'text', None, _('treat all files as text')),
3091 ('g', 'git', None, _('use git extended diff format')),
3092 ('g', 'git', None, _('use git extended diff format')),
3092 ('', 'nodates', None, _("don't include dates in diff headers")),
3093 ('', 'nodates', None, _("don't include dates in diff headers")),
3093 ('', 'switch-parent', None, _('diff against the second parent'))],
3094 ('', 'switch-parent', None, _('diff against the second parent'))],
3094 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3095 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3095 "grep":
3096 "grep":
3096 (grep,
3097 (grep,
3097 [('0', 'print0', None, _('end fields with NUL')),
3098 [('0', 'print0', None, _('end fields with NUL')),
3098 ('', 'all', None, _('print all revisions that match')),
3099 ('', 'all', None, _('print all revisions that match')),
3099 ('f', 'follow', None,
3100 ('f', 'follow', None,
3100 _('follow changeset history, or file history across copies and renames')),
3101 _('follow changeset history, or file history across copies and renames')),
3101 ('i', 'ignore-case', None, _('ignore case when matching')),
3102 ('i', 'ignore-case', None, _('ignore case when matching')),
3102 ('l', 'files-with-matches', None,
3103 ('l', 'files-with-matches', None,
3103 _('print only filenames and revs that match')),
3104 _('print only filenames and revs that match')),
3104 ('n', 'line-number', None, _('print matching line numbers')),
3105 ('n', 'line-number', None, _('print matching line numbers')),
3105 ('r', 'rev', [], _('search in given revision range')),
3106 ('r', 'rev', [], _('search in given revision range')),
3106 ('u', 'user', None, _('list the author (long with -v)')),
3107 ('u', 'user', None, _('list the author (long with -v)')),
3107 ('d', 'date', None, _('list the date (short with -q)')),
3108 ('d', 'date', None, _('list the date (short with -q)')),
3108 ] + walkopts,
3109 ] + walkopts,
3109 _('hg grep [OPTION]... PATTERN [FILE]...')),
3110 _('hg grep [OPTION]... PATTERN [FILE]...')),
3110 "heads":
3111 "heads":
3111 (heads,
3112 (heads,
3112 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3113 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3113 ] + templateopts,
3114 ] + templateopts,
3114 _('hg heads [-r REV] [REV]...')),
3115 _('hg heads [-r REV] [REV]...')),
3115 "help": (help_, [], _('hg help [COMMAND]')),
3116 "help": (help_, [], _('hg help [COMMAND]')),
3116 "identify|id":
3117 "identify|id":
3117 (identify,
3118 (identify,
3118 [('r', 'rev', '', _('identify the specified rev')),
3119 [('r', 'rev', '', _('identify the specified rev')),
3119 ('n', 'num', None, _('show local revision number')),
3120 ('n', 'num', None, _('show local revision number')),
3120 ('i', 'id', None, _('show global revision id')),
3121 ('i', 'id', None, _('show global revision id')),
3121 ('b', 'branch', None, _('show branch')),
3122 ('b', 'branch', None, _('show branch')),
3122 ('t', 'tags', None, _('show tags'))],
3123 ('t', 'tags', None, _('show tags'))],
3123 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3124 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3124 "import|patch":
3125 "import|patch":
3125 (import_,
3126 (import_,
3126 [('p', 'strip', 1,
3127 [('p', 'strip', 1,
3127 _('directory strip option for patch. This has the same\n'
3128 _('directory strip option for patch. This has the same\n'
3128 'meaning as the corresponding patch option')),
3129 'meaning as the corresponding patch option')),
3129 ('b', 'base', '', _('base path')),
3130 ('b', 'base', '', _('base path')),
3130 ('f', 'force', None,
3131 ('f', 'force', None,
3131 _('skip check for outstanding uncommitted changes')),
3132 _('skip check for outstanding uncommitted changes')),
3132 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3133 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3133 ('', 'exact', None,
3134 ('', 'exact', None,
3134 _('apply patch to the nodes from which it was generated')),
3135 _('apply patch to the nodes from which it was generated')),
3135 ('', 'import-branch', None,
3136 ('', 'import-branch', None,
3136 _('Use any branch information in patch (implied by --exact)'))] +
3137 _('Use any branch information in patch (implied by --exact)'))] +
3137 commitopts + commitopts2,
3138 commitopts + commitopts2,
3138 _('hg import [OPTION]... PATCH...')),
3139 _('hg import [OPTION]... PATCH...')),
3139 "incoming|in":
3140 "incoming|in":
3140 (incoming,
3141 (incoming,
3141 [('f', 'force', None,
3142 [('f', 'force', None,
3142 _('run even when remote repository is unrelated')),
3143 _('run even when remote repository is unrelated')),
3143 ('n', 'newest-first', None, _('show newest record first')),
3144 ('n', 'newest-first', None, _('show newest record first')),
3144 ('', 'bundle', '', _('file to store the bundles into')),
3145 ('', 'bundle', '', _('file to store the bundles into')),
3145 ('r', 'rev', [],
3146 ('r', 'rev', [],
3146 _('a specific revision up to which you would like to pull')),
3147 _('a specific revision up to which you would like to pull')),
3147 ] + logopts + remoteopts,
3148 ] + logopts + remoteopts,
3148 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3149 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3149 ' [--bundle FILENAME] [SOURCE]')),
3150 ' [--bundle FILENAME] [SOURCE]')),
3150 "^init":
3151 "^init":
3151 (init,
3152 (init,
3152 remoteopts,
3153 remoteopts,
3153 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3154 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3154 "locate":
3155 "locate":
3155 (locate,
3156 (locate,
3156 [('r', 'rev', '', _('search the repository as it stood at rev')),
3157 [('r', 'rev', '', _('search the repository as it stood at rev')),
3157 ('0', 'print0', None,
3158 ('0', 'print0', None,
3158 _('end filenames with NUL, for use with xargs')),
3159 _('end filenames with NUL, for use with xargs')),
3159 ('f', 'fullpath', None,
3160 ('f', 'fullpath', None,
3160 _('print complete paths from the filesystem root')),
3161 _('print complete paths from the filesystem root')),
3161 ] + walkopts,
3162 ] + walkopts,
3162 _('hg locate [OPTION]... [PATTERN]...')),
3163 _('hg locate [OPTION]... [PATTERN]...')),
3163 "^log|history":
3164 "^log|history":
3164 (log,
3165 (log,
3165 [('f', 'follow', None,
3166 [('f', 'follow', None,
3166 _('follow changeset history, or file history across copies and renames')),
3167 _('follow changeset history, or file history across copies and renames')),
3167 ('', 'follow-first', None,
3168 ('', 'follow-first', None,
3168 _('only follow the first parent of merge changesets')),
3169 _('only follow the first parent of merge changesets')),
3169 ('d', 'date', '', _('show revs matching date spec')),
3170 ('d', 'date', '', _('show revs matching date spec')),
3170 ('C', 'copies', None, _('show copied files')),
3171 ('C', 'copies', None, _('show copied files')),
3171 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3172 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3172 ('r', 'rev', [], _('show the specified revision or range')),
3173 ('r', 'rev', [], _('show the specified revision or range')),
3173 ('', 'removed', None, _('include revs where files were removed')),
3174 ('', 'removed', None, _('include revs where files were removed')),
3174 ('m', 'only-merges', None, _('show only merges')),
3175 ('m', 'only-merges', None, _('show only merges')),
3175 ('b', 'only-branch', [],
3176 ('b', 'only-branch', [],
3176 _('show only changesets within the given named branch')),
3177 _('show only changesets within the given named branch')),
3177 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3178 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3178 ] + logopts + walkopts,
3179 ] + logopts + walkopts,
3179 _('hg log [OPTION]... [FILE]')),
3180 _('hg log [OPTION]... [FILE]')),
3180 "manifest":
3181 "manifest":
3181 (manifest,
3182 (manifest,
3182 [('r', 'rev', '', _('revision to display'))],
3183 [('r', 'rev', '', _('revision to display'))],
3183 _('hg manifest [-r REV]')),
3184 _('hg manifest [-r REV]')),
3184 "^merge":
3185 "^merge":
3185 (merge,
3186 (merge,
3186 [('f', 'force', None, _('force a merge with outstanding changes')),
3187 [('f', 'force', None, _('force a merge with outstanding changes')),
3187 ('r', 'rev', '', _('revision to merge')),
3188 ('r', 'rev', '', _('revision to merge')),
3188 ],
3189 ],
3189 _('hg merge [-f] [[-r] REV]')),
3190 _('hg merge [-f] [[-r] REV]')),
3190 "outgoing|out":
3191 "outgoing|out":
3191 (outgoing,
3192 (outgoing,
3192 [('f', 'force', None,
3193 [('f', 'force', None,
3193 _('run even when remote repository is unrelated')),
3194 _('run even when remote repository is unrelated')),
3194 ('r', 'rev', [],
3195 ('r', 'rev', [],
3195 _('a specific revision up to which you would like to push')),
3196 _('a specific revision up to which you would like to push')),
3196 ('n', 'newest-first', None, _('show newest record first')),
3197 ('n', 'newest-first', None, _('show newest record first')),
3197 ] + logopts + remoteopts,
3198 ] + logopts + remoteopts,
3198 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3199 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3199 "^parents":
3200 "^parents":
3200 (parents,
3201 (parents,
3201 [('r', 'rev', '', _('show parents from the specified rev')),
3202 [('r', 'rev', '', _('show parents from the specified rev')),
3202 ] + templateopts,
3203 ] + templateopts,
3203 _('hg parents [-r REV] [FILE]')),
3204 _('hg parents [-r REV] [FILE]')),
3204 "paths": (paths, [], _('hg paths [NAME]')),
3205 "paths": (paths, [], _('hg paths [NAME]')),
3205 "^pull":
3206 "^pull":
3206 (pull,
3207 (pull,
3207 [('u', 'update', None,
3208 [('u', 'update', None,
3208 _('update to new tip if changesets were pulled')),
3209 _('update to new tip if changesets were pulled')),
3209 ('f', 'force', None,
3210 ('f', 'force', None,
3210 _('run even when remote repository is unrelated')),
3211 _('run even when remote repository is unrelated')),
3211 ('r', 'rev', [],
3212 ('r', 'rev', [],
3212 _('a specific revision up to which you would like to pull')),
3213 _('a specific revision up to which you would like to pull')),
3213 ] + remoteopts,
3214 ] + remoteopts,
3214 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3215 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3215 "^push":
3216 "^push":
3216 (push,
3217 (push,
3217 [('f', 'force', None, _('force push')),
3218 [('f', 'force', None, _('force push')),
3218 ('r', 'rev', [],
3219 ('r', 'rev', [],
3219 _('a specific revision up to which you would like to push')),
3220 _('a specific revision up to which you would like to push')),
3220 ] + remoteopts,
3221 ] + remoteopts,
3221 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3222 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3222 "recover": (recover, [], _('hg recover')),
3223 "recover": (recover, [], _('hg recover')),
3223 "^remove|rm":
3224 "^remove|rm":
3224 (remove,
3225 (remove,
3225 [('A', 'after', None, _('record delete for missing files')),
3226 [('A', 'after', None, _('record delete for missing files')),
3226 ('f', 'force', None,
3227 ('f', 'force', None,
3227 _('remove (and delete) file even if added or modified')),
3228 _('remove (and delete) file even if added or modified')),
3228 ] + walkopts,
3229 ] + walkopts,
3229 _('hg remove [OPTION]... FILE...')),
3230 _('hg remove [OPTION]... FILE...')),
3230 "rename|mv":
3231 "rename|mv":
3231 (rename,
3232 (rename,
3232 [('A', 'after', None, _('record a rename that has already occurred')),
3233 [('A', 'after', None, _('record a rename that has already occurred')),
3233 ('f', 'force', None,
3234 ('f', 'force', None,
3234 _('forcibly copy over an existing managed file')),
3235 _('forcibly copy over an existing managed file')),
3235 ] + walkopts + dryrunopts,
3236 ] + walkopts + dryrunopts,
3236 _('hg rename [OPTION]... SOURCE... DEST')),
3237 _('hg rename [OPTION]... SOURCE... DEST')),
3237 "resolve":
3238 "resolve":
3238 (resolve,
3239 (resolve,
3239 [('l', 'list', None, _('list state of files needing merge')),
3240 [('l', 'list', None, _('list state of files needing merge')),
3240 ('m', 'mark', None, _('mark files as resolved')),
3241 ('m', 'mark', None, _('mark files as resolved')),
3241 ('u', 'unmark', None, _('unmark files as resolved'))],
3242 ('u', 'unmark', None, _('unmark files as resolved'))],
3242 ('hg resolve [OPTION] [FILES...]')),
3243 ('hg resolve [OPTION] [FILES...]')),
3243 "revert":
3244 "revert":
3244 (revert,
3245 (revert,
3245 [('a', 'all', None, _('revert all changes when no arguments given')),
3246 [('a', 'all', None, _('revert all changes when no arguments given')),
3246 ('d', 'date', '', _('tipmost revision matching date')),
3247 ('d', 'date', '', _('tipmost revision matching date')),
3247 ('r', 'rev', '', _('revision to revert to')),
3248 ('r', 'rev', '', _('revision to revert to')),
3248 ('', 'no-backup', None, _('do not save backup copies of files')),
3249 ('', 'no-backup', None, _('do not save backup copies of files')),
3249 ] + walkopts + dryrunopts,
3250 ] + walkopts + dryrunopts,
3250 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3251 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3251 "rollback": (rollback, [], _('hg rollback')),
3252 "rollback": (rollback, [], _('hg rollback')),
3252 "root": (root, [], _('hg root')),
3253 "root": (root, [], _('hg root')),
3253 "^serve":
3254 "^serve":
3254 (serve,
3255 (serve,
3255 [('A', 'accesslog', '', _('name of access log file to write to')),
3256 [('A', 'accesslog', '', _('name of access log file to write to')),
3256 ('d', 'daemon', None, _('run server in background')),
3257 ('d', 'daemon', None, _('run server in background')),
3257 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3258 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3258 ('E', 'errorlog', '', _('name of error log file to write to')),
3259 ('E', 'errorlog', '', _('name of error log file to write to')),
3259 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3260 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3260 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3261 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3261 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3262 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3262 ('n', 'name', '',
3263 ('n', 'name', '',
3263 _('name to show in web pages (default: working dir)')),
3264 _('name to show in web pages (default: working dir)')),
3264 ('', 'webdir-conf', '', _('name of the webdir config file'
3265 ('', 'webdir-conf', '', _('name of the webdir config file'
3265 ' (serve more than one repo)')),
3266 ' (serve more than one repo)')),
3266 ('', 'pid-file', '', _('name of file to write process ID to')),
3267 ('', 'pid-file', '', _('name of file to write process ID to')),
3267 ('', 'stdio', None, _('for remote clients')),
3268 ('', 'stdio', None, _('for remote clients')),
3268 ('t', 'templates', '', _('web templates to use')),
3269 ('t', 'templates', '', _('web templates to use')),
3269 ('', 'style', '', _('template style to use')),
3270 ('', 'style', '', _('template style to use')),
3270 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3271 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3271 ('', 'certificate', '', _('SSL certificate file'))],
3272 ('', 'certificate', '', _('SSL certificate file'))],
3272 _('hg serve [OPTION]...')),
3273 _('hg serve [OPTION]...')),
3273 "showconfig|debugconfig":
3274 "showconfig|debugconfig":
3274 (showconfig,
3275 (showconfig,
3275 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3276 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3276 _('hg showconfig [-u] [NAME]...')),
3277 _('hg showconfig [-u] [NAME]...')),
3277 "^status|st":
3278 "^status|st":
3278 (status,
3279 (status,
3279 [('A', 'all', None, _('show status of all files')),
3280 [('A', 'all', None, _('show status of all files')),
3280 ('m', 'modified', None, _('show only modified files')),
3281 ('m', 'modified', None, _('show only modified files')),
3281 ('a', 'added', None, _('show only added files')),
3282 ('a', 'added', None, _('show only added files')),
3282 ('r', 'removed', None, _('show only removed files')),
3283 ('r', 'removed', None, _('show only removed files')),
3283 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3284 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3284 ('c', 'clean', None, _('show only files without changes')),
3285 ('c', 'clean', None, _('show only files without changes')),
3285 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3286 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3286 ('i', 'ignored', None, _('show only ignored files')),
3287 ('i', 'ignored', None, _('show only ignored files')),
3287 ('n', 'no-status', None, _('hide status prefix')),
3288 ('n', 'no-status', None, _('hide status prefix')),
3288 ('C', 'copies', None, _('show source of copied files')),
3289 ('C', 'copies', None, _('show source of copied files')),
3289 ('0', 'print0', None,
3290 ('0', 'print0', None,
3290 _('end filenames with NUL, for use with xargs')),
3291 _('end filenames with NUL, for use with xargs')),
3291 ('', 'rev', [], _('show difference from revision')),
3292 ('', 'rev', [], _('show difference from revision')),
3292 ] + walkopts,
3293 ] + walkopts,
3293 _('hg status [OPTION]... [FILE]...')),
3294 _('hg status [OPTION]... [FILE]...')),
3294 "tag":
3295 "tag":
3295 (tag,
3296 (tag,
3296 [('f', 'force', None, _('replace existing tag')),
3297 [('f', 'force', None, _('replace existing tag')),
3297 ('l', 'local', None, _('make the tag local')),
3298 ('l', 'local', None, _('make the tag local')),
3298 ('r', 'rev', '', _('revision to tag')),
3299 ('r', 'rev', '', _('revision to tag')),
3299 ('', 'remove', None, _('remove a tag')),
3300 ('', 'remove', None, _('remove a tag')),
3300 # -l/--local is already there, commitopts cannot be used
3301 # -l/--local is already there, commitopts cannot be used
3301 ('m', 'message', '', _('use <text> as commit message')),
3302 ('m', 'message', '', _('use <text> as commit message')),
3302 ] + commitopts2,
3303 ] + commitopts2,
3303 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3304 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3304 "tags": (tags, [], _('hg tags')),
3305 "tags": (tags, [], _('hg tags')),
3305 "tip":
3306 "tip":
3306 (tip,
3307 (tip,
3307 [('p', 'patch', None, _('show patch')),
3308 [('p', 'patch', None, _('show patch')),
3308 ] + templateopts,
3309 ] + templateopts,
3309 _('hg tip [-p]')),
3310 _('hg tip [-p]')),
3310 "unbundle":
3311 "unbundle":
3311 (unbundle,
3312 (unbundle,
3312 [('u', 'update', None,
3313 [('u', 'update', None,
3313 _('update to new tip if changesets were unbundled'))],
3314 _('update to new tip if changesets were unbundled'))],
3314 _('hg unbundle [-u] FILE...')),
3315 _('hg unbundle [-u] FILE...')),
3315 "^update|up|checkout|co":
3316 "^update|up|checkout|co":
3316 (update,
3317 (update,
3317 [('C', 'clean', None, _('overwrite locally modified files')),
3318 [('C', 'clean', None, _('overwrite locally modified files')),
3318 ('d', 'date', '', _('tipmost revision matching date')),
3319 ('d', 'date', '', _('tipmost revision matching date')),
3319 ('r', 'rev', '', _('revision'))],
3320 ('r', 'rev', '', _('revision'))],
3320 _('hg update [-C] [-d DATE] [[-r] REV]')),
3321 _('hg update [-C] [-d DATE] [[-r] REV]')),
3321 "verify": (verify, [], _('hg verify')),
3322 "verify": (verify, [], _('hg verify')),
3322 "version": (version_, [], _('hg version')),
3323 "version": (version_, [], _('hg version')),
3323 }
3324 }
3324
3325
3325 norepo = ("clone init version help debugcomplete debugdata"
3326 norepo = ("clone init version help debugcomplete debugdata"
3326 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3327 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3327 optionalrepo = ("identify paths serve showconfig debugancestor")
3328 optionalrepo = ("identify paths serve showconfig debugancestor")
General Comments 0
You need to be logged in to leave comments. Login now