##// END OF EJS Templates
mq: qdiff: support all diffopts
Jason Orendorff -
r6668:034f4449 default
parent child Browse files
Show More
@@ -1,2463 +1,2458 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 if not guard:
129 if not guard:
130 return _('guard cannot be an empty string')
130 return _('guard cannot be an empty string')
131 bad_chars = '# \t\r\n\f'
131 bad_chars = '# \t\r\n\f'
132 first = guard[0]
132 first = guard[0]
133 for c in '-+':
133 for c in '-+':
134 if first == c:
134 if first == c:
135 return (_('guard %r starts with invalid character: %r') %
135 return (_('guard %r starts with invalid character: %r') %
136 (guard, c))
136 (guard, c))
137 for c in bad_chars:
137 for c in bad_chars:
138 if c in guard:
138 if c in guard:
139 return _('invalid character in guard %r: %r') % (guard, c)
139 return _('invalid character in guard %r: %r') % (guard, c)
140
140
141 def set_active(self, guards):
141 def set_active(self, guards):
142 for guard in guards:
142 for guard in guards:
143 bad = self.check_guard(guard)
143 bad = self.check_guard(guard)
144 if bad:
144 if bad:
145 raise util.Abort(bad)
145 raise util.Abort(bad)
146 guards = dict.fromkeys(guards).keys()
146 guards = dict.fromkeys(guards).keys()
147 guards.sort()
147 guards.sort()
148 self.ui.debug('active guards: %s\n' % ' '.join(guards))
148 self.ui.debug('active guards: %s\n' % ' '.join(guards))
149 self.active_guards = guards
149 self.active_guards = guards
150 self.guards_dirty = True
150 self.guards_dirty = True
151
151
152 def active(self):
152 def active(self):
153 if self.active_guards is None:
153 if self.active_guards is None:
154 self.active_guards = []
154 self.active_guards = []
155 try:
155 try:
156 guards = self.opener(self.guards_path).read().split()
156 guards = self.opener(self.guards_path).read().split()
157 except IOError, err:
157 except IOError, err:
158 if err.errno != errno.ENOENT: raise
158 if err.errno != errno.ENOENT: raise
159 guards = []
159 guards = []
160 for i, guard in enumerate(guards):
160 for i, guard in enumerate(guards):
161 bad = self.check_guard(guard)
161 bad = self.check_guard(guard)
162 if bad:
162 if bad:
163 self.ui.warn('%s:%d: %s\n' %
163 self.ui.warn('%s:%d: %s\n' %
164 (self.join(self.guards_path), i + 1, bad))
164 (self.join(self.guards_path), i + 1, bad))
165 else:
165 else:
166 self.active_guards.append(guard)
166 self.active_guards.append(guard)
167 return self.active_guards
167 return self.active_guards
168
168
169 def set_guards(self, idx, guards):
169 def set_guards(self, idx, guards):
170 for g in guards:
170 for g in guards:
171 if len(g) < 2:
171 if len(g) < 2:
172 raise util.Abort(_('guard %r too short') % g)
172 raise util.Abort(_('guard %r too short') % g)
173 if g[0] not in '-+':
173 if g[0] not in '-+':
174 raise util.Abort(_('guard %r starts with invalid char') % g)
174 raise util.Abort(_('guard %r starts with invalid char') % g)
175 bad = self.check_guard(g[1:])
175 bad = self.check_guard(g[1:])
176 if bad:
176 if bad:
177 raise util.Abort(bad)
177 raise util.Abort(bad)
178 drop = self.guard_re.sub('', self.full_series[idx])
178 drop = self.guard_re.sub('', self.full_series[idx])
179 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
179 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
180 self.parse_series()
180 self.parse_series()
181 self.series_dirty = True
181 self.series_dirty = True
182
182
183 def pushable(self, idx):
183 def pushable(self, idx):
184 if isinstance(idx, str):
184 if isinstance(idx, str):
185 idx = self.series.index(idx)
185 idx = self.series.index(idx)
186 patchguards = self.series_guards[idx]
186 patchguards = self.series_guards[idx]
187 if not patchguards:
187 if not patchguards:
188 return True, None
188 return True, None
189 default = False
189 default = False
190 guards = self.active()
190 guards = self.active()
191 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
191 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
192 if exactneg:
192 if exactneg:
193 return False, exactneg[0]
193 return False, exactneg[0]
194 pos = [g for g in patchguards if g[0] == '+']
194 pos = [g for g in patchguards if g[0] == '+']
195 exactpos = [g for g in pos if g[1:] in guards]
195 exactpos = [g for g in pos if g[1:] in guards]
196 if pos:
196 if pos:
197 if exactpos:
197 if exactpos:
198 return True, exactpos[0]
198 return True, exactpos[0]
199 return False, pos
199 return False, pos
200 return True, ''
200 return True, ''
201
201
202 def explain_pushable(self, idx, all_patches=False):
202 def explain_pushable(self, idx, all_patches=False):
203 write = all_patches and self.ui.write or self.ui.warn
203 write = all_patches and self.ui.write or self.ui.warn
204 if all_patches or self.ui.verbose:
204 if all_patches or self.ui.verbose:
205 if isinstance(idx, str):
205 if isinstance(idx, str):
206 idx = self.series.index(idx)
206 idx = self.series.index(idx)
207 pushable, why = self.pushable(idx)
207 pushable, why = self.pushable(idx)
208 if all_patches and pushable:
208 if all_patches and pushable:
209 if why is None:
209 if why is None:
210 write(_('allowing %s - no guards in effect\n') %
210 write(_('allowing %s - no guards in effect\n') %
211 self.series[idx])
211 self.series[idx])
212 else:
212 else:
213 if not why:
213 if not why:
214 write(_('allowing %s - no matching negative guards\n') %
214 write(_('allowing %s - no matching negative guards\n') %
215 self.series[idx])
215 self.series[idx])
216 else:
216 else:
217 write(_('allowing %s - guarded by %r\n') %
217 write(_('allowing %s - guarded by %r\n') %
218 (self.series[idx], why))
218 (self.series[idx], why))
219 if not pushable:
219 if not pushable:
220 if why:
220 if why:
221 write(_('skipping %s - guarded by %r\n') %
221 write(_('skipping %s - guarded by %r\n') %
222 (self.series[idx], why))
222 (self.series[idx], why))
223 else:
223 else:
224 write(_('skipping %s - no matching guards\n') %
224 write(_('skipping %s - no matching guards\n') %
225 self.series[idx])
225 self.series[idx])
226
226
227 def save_dirty(self):
227 def save_dirty(self):
228 def write_list(items, path):
228 def write_list(items, path):
229 fp = self.opener(path, 'w')
229 fp = self.opener(path, 'w')
230 for i in items:
230 for i in items:
231 fp.write("%s\n" % i)
231 fp.write("%s\n" % i)
232 fp.close()
232 fp.close()
233 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
233 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
234 if self.series_dirty: write_list(self.full_series, self.series_path)
234 if self.series_dirty: write_list(self.full_series, self.series_path)
235 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
235 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
236
236
237 def readheaders(self, patch):
237 def readheaders(self, patch):
238 def eatdiff(lines):
238 def eatdiff(lines):
239 while lines:
239 while lines:
240 l = lines[-1]
240 l = lines[-1]
241 if (l.startswith("diff -") or
241 if (l.startswith("diff -") or
242 l.startswith("Index:") or
242 l.startswith("Index:") or
243 l.startswith("===========")):
243 l.startswith("===========")):
244 del lines[-1]
244 del lines[-1]
245 else:
245 else:
246 break
246 break
247 def eatempty(lines):
247 def eatempty(lines):
248 while lines:
248 while lines:
249 l = lines[-1]
249 l = lines[-1]
250 if re.match('\s*$', l):
250 if re.match('\s*$', l):
251 del lines[-1]
251 del lines[-1]
252 else:
252 else:
253 break
253 break
254
254
255 pf = self.join(patch)
255 pf = self.join(patch)
256 message = []
256 message = []
257 comments = []
257 comments = []
258 user = None
258 user = None
259 date = None
259 date = None
260 format = None
260 format = None
261 subject = None
261 subject = None
262 diffstart = 0
262 diffstart = 0
263
263
264 for line in file(pf):
264 for line in file(pf):
265 line = line.rstrip()
265 line = line.rstrip()
266 if line.startswith('diff --git'):
266 if line.startswith('diff --git'):
267 diffstart = 2
267 diffstart = 2
268 break
268 break
269 if diffstart:
269 if diffstart:
270 if line.startswith('+++ '):
270 if line.startswith('+++ '):
271 diffstart = 2
271 diffstart = 2
272 break
272 break
273 if line.startswith("--- "):
273 if line.startswith("--- "):
274 diffstart = 1
274 diffstart = 1
275 continue
275 continue
276 elif format == "hgpatch":
276 elif format == "hgpatch":
277 # parse values when importing the result of an hg export
277 # parse values when importing the result of an hg export
278 if line.startswith("# User "):
278 if line.startswith("# User "):
279 user = line[7:]
279 user = line[7:]
280 elif line.startswith("# Date "):
280 elif line.startswith("# Date "):
281 date = line[7:]
281 date = line[7:]
282 elif not line.startswith("# ") and line:
282 elif not line.startswith("# ") and line:
283 message.append(line)
283 message.append(line)
284 format = None
284 format = None
285 elif line == '# HG changeset patch':
285 elif line == '# HG changeset patch':
286 format = "hgpatch"
286 format = "hgpatch"
287 elif (format != "tagdone" and (line.startswith("Subject: ") or
287 elif (format != "tagdone" and (line.startswith("Subject: ") or
288 line.startswith("subject: "))):
288 line.startswith("subject: "))):
289 subject = line[9:]
289 subject = line[9:]
290 format = "tag"
290 format = "tag"
291 elif (format != "tagdone" and (line.startswith("From: ") or
291 elif (format != "tagdone" and (line.startswith("From: ") or
292 line.startswith("from: "))):
292 line.startswith("from: "))):
293 user = line[6:]
293 user = line[6:]
294 format = "tag"
294 format = "tag"
295 elif format == "tag" and line == "":
295 elif format == "tag" and line == "":
296 # when looking for tags (subject: from: etc) they
296 # when looking for tags (subject: from: etc) they
297 # end once you find a blank line in the source
297 # end once you find a blank line in the source
298 format = "tagdone"
298 format = "tagdone"
299 elif message or line:
299 elif message or line:
300 message.append(line)
300 message.append(line)
301 comments.append(line)
301 comments.append(line)
302
302
303 eatdiff(message)
303 eatdiff(message)
304 eatdiff(comments)
304 eatdiff(comments)
305 eatempty(message)
305 eatempty(message)
306 eatempty(comments)
306 eatempty(comments)
307
307
308 # make sure message isn't empty
308 # make sure message isn't empty
309 if format and format.startswith("tag") and subject:
309 if format and format.startswith("tag") and subject:
310 message.insert(0, "")
310 message.insert(0, "")
311 message.insert(0, subject)
311 message.insert(0, subject)
312 return (message, comments, user, date, diffstart > 1)
312 return (message, comments, user, date, diffstart > 1)
313
313
314 def removeundo(self, repo):
314 def removeundo(self, repo):
315 undo = repo.sjoin('undo')
315 undo = repo.sjoin('undo')
316 if not os.path.exists(undo):
316 if not os.path.exists(undo):
317 return
317 return
318 try:
318 try:
319 os.unlink(undo)
319 os.unlink(undo)
320 except OSError, inst:
320 except OSError, inst:
321 self.ui.warn('error removing undo: %s\n' % str(inst))
321 self.ui.warn('error removing undo: %s\n' % str(inst))
322
322
323 def printdiff(self, repo, node1, node2=None, files=None,
323 def printdiff(self, repo, node1, node2=None, files=None,
324 fp=None, changes=None, opts={}):
324 fp=None, changes=None, opts={}):
325 m = cmdutil.match(repo, files, opts)
325 m = cmdutil.match(repo, files, opts)
326 patch.diff(repo, node1, node2, m, fp, changes, self.diffopts())
326 patch.diff(repo, node1, node2, m, fp, changes, self.diffopts())
327
327
328 def mergeone(self, repo, mergeq, head, patch, rev):
328 def mergeone(self, repo, mergeq, head, patch, rev):
329 # first try just applying the patch
329 # first try just applying the patch
330 (err, n) = self.apply(repo, [ patch ], update_status=False,
330 (err, n) = self.apply(repo, [ patch ], update_status=False,
331 strict=True, merge=rev)
331 strict=True, merge=rev)
332
332
333 if err == 0:
333 if err == 0:
334 return (err, n)
334 return (err, n)
335
335
336 if n is None:
336 if n is None:
337 raise util.Abort(_("apply failed for patch %s") % patch)
337 raise util.Abort(_("apply failed for patch %s") % patch)
338
338
339 self.ui.warn("patch didn't work out, merging %s\n" % patch)
339 self.ui.warn("patch didn't work out, merging %s\n" % patch)
340
340
341 # apply failed, strip away that rev and merge.
341 # apply failed, strip away that rev and merge.
342 hg.clean(repo, head)
342 hg.clean(repo, head)
343 self.strip(repo, n, update=False, backup='strip')
343 self.strip(repo, n, update=False, backup='strip')
344
344
345 ctx = repo.changectx(rev)
345 ctx = repo.changectx(rev)
346 ret = hg.merge(repo, rev)
346 ret = hg.merge(repo, rev)
347 if ret:
347 if ret:
348 raise util.Abort(_("update returned %d") % ret)
348 raise util.Abort(_("update returned %d") % ret)
349 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
349 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
350 if n == None:
350 if n == None:
351 raise util.Abort(_("repo commit failed"))
351 raise util.Abort(_("repo commit failed"))
352 try:
352 try:
353 message, comments, user, date, patchfound = mergeq.readheaders(patch)
353 message, comments, user, date, patchfound = mergeq.readheaders(patch)
354 except:
354 except:
355 raise util.Abort(_("unable to read %s") % patch)
355 raise util.Abort(_("unable to read %s") % patch)
356
356
357 patchf = self.opener(patch, "w")
357 patchf = self.opener(patch, "w")
358 if comments:
358 if comments:
359 comments = "\n".join(comments) + '\n\n'
359 comments = "\n".join(comments) + '\n\n'
360 patchf.write(comments)
360 patchf.write(comments)
361 self.printdiff(repo, head, n, fp=patchf)
361 self.printdiff(repo, head, n, fp=patchf)
362 patchf.close()
362 patchf.close()
363 self.removeundo(repo)
363 self.removeundo(repo)
364 return (0, n)
364 return (0, n)
365
365
366 def qparents(self, repo, rev=None):
366 def qparents(self, repo, rev=None):
367 if rev is None:
367 if rev is None:
368 (p1, p2) = repo.dirstate.parents()
368 (p1, p2) = repo.dirstate.parents()
369 if p2 == revlog.nullid:
369 if p2 == revlog.nullid:
370 return p1
370 return p1
371 if len(self.applied) == 0:
371 if len(self.applied) == 0:
372 return None
372 return None
373 return revlog.bin(self.applied[-1].rev)
373 return revlog.bin(self.applied[-1].rev)
374 pp = repo.changelog.parents(rev)
374 pp = repo.changelog.parents(rev)
375 if pp[1] != revlog.nullid:
375 if pp[1] != revlog.nullid:
376 arevs = [ x.rev for x in self.applied ]
376 arevs = [ x.rev for x in self.applied ]
377 p0 = revlog.hex(pp[0])
377 p0 = revlog.hex(pp[0])
378 p1 = revlog.hex(pp[1])
378 p1 = revlog.hex(pp[1])
379 if p0 in arevs:
379 if p0 in arevs:
380 return pp[0]
380 return pp[0]
381 if p1 in arevs:
381 if p1 in arevs:
382 return pp[1]
382 return pp[1]
383 return pp[0]
383 return pp[0]
384
384
385 def mergepatch(self, repo, mergeq, series):
385 def mergepatch(self, repo, mergeq, series):
386 if len(self.applied) == 0:
386 if len(self.applied) == 0:
387 # each of the patches merged in will have two parents. This
387 # each of the patches merged in will have two parents. This
388 # can confuse the qrefresh, qdiff, and strip code because it
388 # can confuse the qrefresh, qdiff, and strip code because it
389 # needs to know which parent is actually in the patch queue.
389 # needs to know which parent is actually in the patch queue.
390 # so, we insert a merge marker with only one parent. This way
390 # so, we insert a merge marker with only one parent. This way
391 # the first patch in the queue is never a merge patch
391 # the first patch in the queue is never a merge patch
392 #
392 #
393 pname = ".hg.patches.merge.marker"
393 pname = ".hg.patches.merge.marker"
394 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
394 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
395 self.removeundo(repo)
395 self.removeundo(repo)
396 self.applied.append(statusentry(revlog.hex(n), pname))
396 self.applied.append(statusentry(revlog.hex(n), pname))
397 self.applied_dirty = 1
397 self.applied_dirty = 1
398
398
399 head = self.qparents(repo)
399 head = self.qparents(repo)
400
400
401 for patch in series:
401 for patch in series:
402 patch = mergeq.lookup(patch, strict=True)
402 patch = mergeq.lookup(patch, strict=True)
403 if not patch:
403 if not patch:
404 self.ui.warn("patch %s does not exist\n" % patch)
404 self.ui.warn("patch %s does not exist\n" % patch)
405 return (1, None)
405 return (1, None)
406 pushable, reason = self.pushable(patch)
406 pushable, reason = self.pushable(patch)
407 if not pushable:
407 if not pushable:
408 self.explain_pushable(patch, all_patches=True)
408 self.explain_pushable(patch, all_patches=True)
409 continue
409 continue
410 info = mergeq.isapplied(patch)
410 info = mergeq.isapplied(patch)
411 if not info:
411 if not info:
412 self.ui.warn("patch %s is not applied\n" % patch)
412 self.ui.warn("patch %s is not applied\n" % patch)
413 return (1, None)
413 return (1, None)
414 rev = revlog.bin(info[1])
414 rev = revlog.bin(info[1])
415 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
415 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
416 if head:
416 if head:
417 self.applied.append(statusentry(revlog.hex(head), patch))
417 self.applied.append(statusentry(revlog.hex(head), patch))
418 self.applied_dirty = 1
418 self.applied_dirty = 1
419 if err:
419 if err:
420 return (err, head)
420 return (err, head)
421 self.save_dirty()
421 self.save_dirty()
422 return (0, head)
422 return (0, head)
423
423
424 def patch(self, repo, patchfile):
424 def patch(self, repo, patchfile):
425 '''Apply patchfile to the working directory.
425 '''Apply patchfile to the working directory.
426 patchfile: file name of patch'''
426 patchfile: file name of patch'''
427 files = {}
427 files = {}
428 try:
428 try:
429 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
429 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
430 files=files)
430 files=files)
431 except Exception, inst:
431 except Exception, inst:
432 self.ui.note(str(inst) + '\n')
432 self.ui.note(str(inst) + '\n')
433 if not self.ui.verbose:
433 if not self.ui.verbose:
434 self.ui.warn("patch failed, unable to continue (try -v)\n")
434 self.ui.warn("patch failed, unable to continue (try -v)\n")
435 return (False, files, False)
435 return (False, files, False)
436
436
437 return (True, files, fuzz)
437 return (True, files, fuzz)
438
438
439 def apply(self, repo, series, list=False, update_status=True,
439 def apply(self, repo, series, list=False, update_status=True,
440 strict=False, patchdir=None, merge=None, all_files={}):
440 strict=False, patchdir=None, merge=None, all_files={}):
441 wlock = lock = tr = None
441 wlock = lock = tr = None
442 try:
442 try:
443 wlock = repo.wlock()
443 wlock = repo.wlock()
444 lock = repo.lock()
444 lock = repo.lock()
445 tr = repo.transaction()
445 tr = repo.transaction()
446 try:
446 try:
447 ret = self._apply(repo, series, list, update_status,
447 ret = self._apply(repo, series, list, update_status,
448 strict, patchdir, merge, all_files=all_files)
448 strict, patchdir, merge, all_files=all_files)
449 tr.close()
449 tr.close()
450 self.save_dirty()
450 self.save_dirty()
451 return ret
451 return ret
452 except:
452 except:
453 try:
453 try:
454 tr.abort()
454 tr.abort()
455 finally:
455 finally:
456 repo.invalidate()
456 repo.invalidate()
457 repo.dirstate.invalidate()
457 repo.dirstate.invalidate()
458 raise
458 raise
459 finally:
459 finally:
460 del tr, lock, wlock
460 del tr, lock, wlock
461 self.removeundo(repo)
461 self.removeundo(repo)
462
462
463 def _apply(self, repo, series, list=False, update_status=True,
463 def _apply(self, repo, series, list=False, update_status=True,
464 strict=False, patchdir=None, merge=None, all_files={}):
464 strict=False, patchdir=None, merge=None, all_files={}):
465 # TODO unify with commands.py
465 # TODO unify with commands.py
466 if not patchdir:
466 if not patchdir:
467 patchdir = self.path
467 patchdir = self.path
468 err = 0
468 err = 0
469 n = None
469 n = None
470 for patchname in series:
470 for patchname in series:
471 pushable, reason = self.pushable(patchname)
471 pushable, reason = self.pushable(patchname)
472 if not pushable:
472 if not pushable:
473 self.explain_pushable(patchname, all_patches=True)
473 self.explain_pushable(patchname, all_patches=True)
474 continue
474 continue
475 self.ui.warn("applying %s\n" % patchname)
475 self.ui.warn("applying %s\n" % patchname)
476 pf = os.path.join(patchdir, patchname)
476 pf = os.path.join(patchdir, patchname)
477
477
478 try:
478 try:
479 message, comments, user, date, patchfound = self.readheaders(patchname)
479 message, comments, user, date, patchfound = self.readheaders(patchname)
480 except:
480 except:
481 self.ui.warn("Unable to read %s\n" % patchname)
481 self.ui.warn("Unable to read %s\n" % patchname)
482 err = 1
482 err = 1
483 break
483 break
484
484
485 if not message:
485 if not message:
486 message = "imported patch %s\n" % patchname
486 message = "imported patch %s\n" % patchname
487 else:
487 else:
488 if list:
488 if list:
489 message.append("\nimported patch %s" % patchname)
489 message.append("\nimported patch %s" % patchname)
490 message = '\n'.join(message)
490 message = '\n'.join(message)
491
491
492 (patcherr, files, fuzz) = self.patch(repo, pf)
492 (patcherr, files, fuzz) = self.patch(repo, pf)
493 all_files.update(files)
493 all_files.update(files)
494 patcherr = not patcherr
494 patcherr = not patcherr
495
495
496 if merge and files:
496 if merge and files:
497 # Mark as removed/merged and update dirstate parent info
497 # Mark as removed/merged and update dirstate parent info
498 removed = []
498 removed = []
499 merged = []
499 merged = []
500 for f in files:
500 for f in files:
501 if os.path.exists(repo.wjoin(f)):
501 if os.path.exists(repo.wjoin(f)):
502 merged.append(f)
502 merged.append(f)
503 else:
503 else:
504 removed.append(f)
504 removed.append(f)
505 for f in removed:
505 for f in removed:
506 repo.dirstate.remove(f)
506 repo.dirstate.remove(f)
507 for f in merged:
507 for f in merged:
508 repo.dirstate.merge(f)
508 repo.dirstate.merge(f)
509 p1, p2 = repo.dirstate.parents()
509 p1, p2 = repo.dirstate.parents()
510 repo.dirstate.setparents(p1, merge)
510 repo.dirstate.setparents(p1, merge)
511
511
512 files = patch.updatedir(self.ui, repo, files)
512 files = patch.updatedir(self.ui, repo, files)
513 match = cmdutil.matchfiles(repo, files or [])
513 match = cmdutil.matchfiles(repo, files or [])
514 n = repo.commit(files, message, user, date, match=match,
514 n = repo.commit(files, message, user, date, match=match,
515 force=True)
515 force=True)
516
516
517 if n == None:
517 if n == None:
518 raise util.Abort(_("repo commit failed"))
518 raise util.Abort(_("repo commit failed"))
519
519
520 if update_status:
520 if update_status:
521 self.applied.append(statusentry(revlog.hex(n), patchname))
521 self.applied.append(statusentry(revlog.hex(n), patchname))
522
522
523 if patcherr:
523 if patcherr:
524 if not patchfound:
524 if not patchfound:
525 self.ui.warn("patch %s is empty\n" % patchname)
525 self.ui.warn("patch %s is empty\n" % patchname)
526 err = 0
526 err = 0
527 else:
527 else:
528 self.ui.warn("patch failed, rejects left in working dir\n")
528 self.ui.warn("patch failed, rejects left in working dir\n")
529 err = 1
529 err = 1
530 break
530 break
531
531
532 if fuzz and strict:
532 if fuzz and strict:
533 self.ui.warn("fuzz found when applying patch, stopping\n")
533 self.ui.warn("fuzz found when applying patch, stopping\n")
534 err = 1
534 err = 1
535 break
535 break
536 return (err, n)
536 return (err, n)
537
537
538 def _clean_series(self, patches):
538 def _clean_series(self, patches):
539 indices = [self.find_series(p) for p in patches]
539 indices = [self.find_series(p) for p in patches]
540 indices.sort()
540 indices.sort()
541 for i in indices[-1::-1]:
541 for i in indices[-1::-1]:
542 del self.full_series[i]
542 del self.full_series[i]
543 self.parse_series()
543 self.parse_series()
544 self.series_dirty = 1
544 self.series_dirty = 1
545
545
546 def finish(self, repo, revs):
546 def finish(self, repo, revs):
547 revs.sort()
547 revs.sort()
548 firstrev = repo.changelog.rev(revlog.bin(self.applied[0].rev))
548 firstrev = repo.changelog.rev(revlog.bin(self.applied[0].rev))
549 appliedbase = 0
549 appliedbase = 0
550 patches = []
550 patches = []
551 for rev in revs:
551 for rev in revs:
552 if rev < firstrev:
552 if rev < firstrev:
553 raise util.Abort(_('revision %d is not managed') % rev)
553 raise util.Abort(_('revision %d is not managed') % rev)
554 base = revlog.bin(self.applied[appliedbase].rev)
554 base = revlog.bin(self.applied[appliedbase].rev)
555 node = repo.changelog.node(rev)
555 node = repo.changelog.node(rev)
556 if node != base:
556 if node != base:
557 raise util.Abort(_('cannot delete revision %d above '
557 raise util.Abort(_('cannot delete revision %d above '
558 'applied patches') % rev)
558 'applied patches') % rev)
559 patches.append(self.applied[appliedbase].name)
559 patches.append(self.applied[appliedbase].name)
560 appliedbase += 1
560 appliedbase += 1
561
561
562 r = self.qrepo()
562 r = self.qrepo()
563 if r:
563 if r:
564 r.remove(patches, True)
564 r.remove(patches, True)
565 else:
565 else:
566 for p in patches:
566 for p in patches:
567 os.unlink(self.join(p))
567 os.unlink(self.join(p))
568
568
569 del self.applied[:appliedbase]
569 del self.applied[:appliedbase]
570 self.applied_dirty = 1
570 self.applied_dirty = 1
571 self._clean_series(patches)
571 self._clean_series(patches)
572
572
573 def delete(self, repo, patches, opts):
573 def delete(self, repo, patches, opts):
574 if not patches and not opts.get('rev'):
574 if not patches and not opts.get('rev'):
575 raise util.Abort(_('qdelete requires at least one revision or '
575 raise util.Abort(_('qdelete requires at least one revision or '
576 'patch name'))
576 'patch name'))
577
577
578 realpatches = []
578 realpatches = []
579 for patch in patches:
579 for patch in patches:
580 patch = self.lookup(patch, strict=True)
580 patch = self.lookup(patch, strict=True)
581 info = self.isapplied(patch)
581 info = self.isapplied(patch)
582 if info:
582 if info:
583 raise util.Abort(_("cannot delete applied patch %s") % patch)
583 raise util.Abort(_("cannot delete applied patch %s") % patch)
584 if patch not in self.series:
584 if patch not in self.series:
585 raise util.Abort(_("patch %s not in series file") % patch)
585 raise util.Abort(_("patch %s not in series file") % patch)
586 realpatches.append(patch)
586 realpatches.append(patch)
587
587
588 appliedbase = 0
588 appliedbase = 0
589 if opts.get('rev'):
589 if opts.get('rev'):
590 if not self.applied:
590 if not self.applied:
591 raise util.Abort(_('no patches applied'))
591 raise util.Abort(_('no patches applied'))
592 revs = cmdutil.revrange(repo, opts['rev'])
592 revs = cmdutil.revrange(repo, opts['rev'])
593 if len(revs) > 1 and revs[0] > revs[1]:
593 if len(revs) > 1 and revs[0] > revs[1]:
594 revs.reverse()
594 revs.reverse()
595 for rev in revs:
595 for rev in revs:
596 if appliedbase >= len(self.applied):
596 if appliedbase >= len(self.applied):
597 raise util.Abort(_("revision %d is not managed") % rev)
597 raise util.Abort(_("revision %d is not managed") % rev)
598
598
599 base = revlog.bin(self.applied[appliedbase].rev)
599 base = revlog.bin(self.applied[appliedbase].rev)
600 node = repo.changelog.node(rev)
600 node = repo.changelog.node(rev)
601 if node != base:
601 if node != base:
602 raise util.Abort(_("cannot delete revision %d above "
602 raise util.Abort(_("cannot delete revision %d above "
603 "applied patches") % rev)
603 "applied patches") % rev)
604 realpatches.append(self.applied[appliedbase].name)
604 realpatches.append(self.applied[appliedbase].name)
605 appliedbase += 1
605 appliedbase += 1
606
606
607 if not opts.get('keep'):
607 if not opts.get('keep'):
608 r = self.qrepo()
608 r = self.qrepo()
609 if r:
609 if r:
610 r.remove(realpatches, True)
610 r.remove(realpatches, True)
611 else:
611 else:
612 for p in realpatches:
612 for p in realpatches:
613 os.unlink(self.join(p))
613 os.unlink(self.join(p))
614
614
615 if appliedbase:
615 if appliedbase:
616 del self.applied[:appliedbase]
616 del self.applied[:appliedbase]
617 self.applied_dirty = 1
617 self.applied_dirty = 1
618 self._clean_series(realpatches)
618 self._clean_series(realpatches)
619
619
620 def check_toppatch(self, repo):
620 def check_toppatch(self, repo):
621 if len(self.applied) > 0:
621 if len(self.applied) > 0:
622 top = revlog.bin(self.applied[-1].rev)
622 top = revlog.bin(self.applied[-1].rev)
623 pp = repo.dirstate.parents()
623 pp = repo.dirstate.parents()
624 if top not in pp:
624 if top not in pp:
625 raise util.Abort(_("working directory revision is not qtip"))
625 raise util.Abort(_("working directory revision is not qtip"))
626 return top
626 return top
627 return None
627 return None
628 def check_localchanges(self, repo, force=False, refresh=True):
628 def check_localchanges(self, repo, force=False, refresh=True):
629 m, a, r, d = repo.status()[:4]
629 m, a, r, d = repo.status()[:4]
630 if m or a or r or d:
630 if m or a or r or d:
631 if not force:
631 if not force:
632 if refresh:
632 if refresh:
633 raise util.Abort(_("local changes found, refresh first"))
633 raise util.Abort(_("local changes found, refresh first"))
634 else:
634 else:
635 raise util.Abort(_("local changes found"))
635 raise util.Abort(_("local changes found"))
636 return m, a, r, d
636 return m, a, r, d
637
637
638 _reserved = ('series', 'status', 'guards')
638 _reserved = ('series', 'status', 'guards')
639 def check_reserved_name(self, name):
639 def check_reserved_name(self, name):
640 if (name in self._reserved or name.startswith('.hg')
640 if (name in self._reserved or name.startswith('.hg')
641 or name.startswith('.mq')):
641 or name.startswith('.mq')):
642 raise util.Abort(_('"%s" cannot be used as the name of a patch')
642 raise util.Abort(_('"%s" cannot be used as the name of a patch')
643 % name)
643 % name)
644
644
645 def new(self, repo, patch, *pats, **opts):
645 def new(self, repo, patch, *pats, **opts):
646 msg = opts.get('msg')
646 msg = opts.get('msg')
647 force = opts.get('force')
647 force = opts.get('force')
648 user = opts.get('user')
648 user = opts.get('user')
649 date = opts.get('date')
649 date = opts.get('date')
650 if date:
650 if date:
651 date = util.parsedate(date)
651 date = util.parsedate(date)
652 self.check_reserved_name(patch)
652 self.check_reserved_name(patch)
653 if os.path.exists(self.join(patch)):
653 if os.path.exists(self.join(patch)):
654 raise util.Abort(_('patch "%s" already exists') % patch)
654 raise util.Abort(_('patch "%s" already exists') % patch)
655 if opts.get('include') or opts.get('exclude') or pats:
655 if opts.get('include') or opts.get('exclude') or pats:
656 match = cmdutil.match(repo, pats, opts)
656 match = cmdutil.match(repo, pats, opts)
657 m, a, r, d = repo.status(match=match)[:4]
657 m, a, r, d = repo.status(match=match)[:4]
658 else:
658 else:
659 m, a, r, d = self.check_localchanges(repo, force)
659 m, a, r, d = self.check_localchanges(repo, force)
660 match = cmdutil.match(repo, m + a + r)
660 match = cmdutil.match(repo, m + a + r)
661 commitfiles = m + a + r
661 commitfiles = m + a + r
662 self.check_toppatch(repo)
662 self.check_toppatch(repo)
663 wlock = repo.wlock()
663 wlock = repo.wlock()
664 try:
664 try:
665 insert = self.full_series_end()
665 insert = self.full_series_end()
666 commitmsg = msg and msg or ("[mq]: %s" % patch)
666 commitmsg = msg and msg or ("[mq]: %s" % patch)
667 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
667 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
668 if n == None:
668 if n == None:
669 raise util.Abort(_("repo commit failed"))
669 raise util.Abort(_("repo commit failed"))
670 self.full_series[insert:insert] = [patch]
670 self.full_series[insert:insert] = [patch]
671 self.applied.append(statusentry(revlog.hex(n), patch))
671 self.applied.append(statusentry(revlog.hex(n), patch))
672 self.parse_series()
672 self.parse_series()
673 self.series_dirty = 1
673 self.series_dirty = 1
674 self.applied_dirty = 1
674 self.applied_dirty = 1
675 p = self.opener(patch, "w")
675 p = self.opener(patch, "w")
676 if date:
676 if date:
677 p.write("# HG changeset patch\n")
677 p.write("# HG changeset patch\n")
678 if user:
678 if user:
679 p.write("# User " + user + "\n")
679 p.write("# User " + user + "\n")
680 p.write("# Date %d %d\n" % date)
680 p.write("# Date %d %d\n" % date)
681 p.write("\n")
681 p.write("\n")
682 elif user:
682 elif user:
683 p.write("From: " + user + "\n")
683 p.write("From: " + user + "\n")
684 p.write("\n")
684 p.write("\n")
685 if msg:
685 if msg:
686 msg = msg + "\n"
686 msg = msg + "\n"
687 p.write(msg)
687 p.write(msg)
688 p.close()
688 p.close()
689 wlock = None
689 wlock = None
690 r = self.qrepo()
690 r = self.qrepo()
691 if r: r.add([patch])
691 if r: r.add([patch])
692 if commitfiles:
692 if commitfiles:
693 self.refresh(repo, short=True, git=opts.get('git'))
693 self.refresh(repo, short=True, git=opts.get('git'))
694 self.removeundo(repo)
694 self.removeundo(repo)
695 finally:
695 finally:
696 del wlock
696 del wlock
697
697
698 def strip(self, repo, rev, update=True, backup="all", force=None):
698 def strip(self, repo, rev, update=True, backup="all", force=None):
699 wlock = lock = None
699 wlock = lock = None
700 try:
700 try:
701 wlock = repo.wlock()
701 wlock = repo.wlock()
702 lock = repo.lock()
702 lock = repo.lock()
703
703
704 if update:
704 if update:
705 self.check_localchanges(repo, force=force, refresh=False)
705 self.check_localchanges(repo, force=force, refresh=False)
706 urev = self.qparents(repo, rev)
706 urev = self.qparents(repo, rev)
707 hg.clean(repo, urev)
707 hg.clean(repo, urev)
708 repo.dirstate.write()
708 repo.dirstate.write()
709
709
710 self.removeundo(repo)
710 self.removeundo(repo)
711 repair.strip(self.ui, repo, rev, backup)
711 repair.strip(self.ui, repo, rev, backup)
712 # strip may have unbundled a set of backed up revisions after
712 # strip may have unbundled a set of backed up revisions after
713 # the actual strip
713 # the actual strip
714 self.removeundo(repo)
714 self.removeundo(repo)
715 finally:
715 finally:
716 del lock, wlock
716 del lock, wlock
717
717
718 def isapplied(self, patch):
718 def isapplied(self, patch):
719 """returns (index, rev, patch)"""
719 """returns (index, rev, patch)"""
720 for i in xrange(len(self.applied)):
720 for i in xrange(len(self.applied)):
721 a = self.applied[i]
721 a = self.applied[i]
722 if a.name == patch:
722 if a.name == patch:
723 return (i, a.rev, a.name)
723 return (i, a.rev, a.name)
724 return None
724 return None
725
725
726 # if the exact patch name does not exist, we try a few
726 # if the exact patch name does not exist, we try a few
727 # variations. If strict is passed, we try only #1
727 # variations. If strict is passed, we try only #1
728 #
728 #
729 # 1) a number to indicate an offset in the series file
729 # 1) a number to indicate an offset in the series file
730 # 2) a unique substring of the patch name was given
730 # 2) a unique substring of the patch name was given
731 # 3) patchname[-+]num to indicate an offset in the series file
731 # 3) patchname[-+]num to indicate an offset in the series file
732 def lookup(self, patch, strict=False):
732 def lookup(self, patch, strict=False):
733 patch = patch and str(patch)
733 patch = patch and str(patch)
734
734
735 def partial_name(s):
735 def partial_name(s):
736 if s in self.series:
736 if s in self.series:
737 return s
737 return s
738 matches = [x for x in self.series if s in x]
738 matches = [x for x in self.series if s in x]
739 if len(matches) > 1:
739 if len(matches) > 1:
740 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
740 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
741 for m in matches:
741 for m in matches:
742 self.ui.warn(' %s\n' % m)
742 self.ui.warn(' %s\n' % m)
743 return None
743 return None
744 if matches:
744 if matches:
745 return matches[0]
745 return matches[0]
746 if len(self.series) > 0 and len(self.applied) > 0:
746 if len(self.series) > 0 and len(self.applied) > 0:
747 if s == 'qtip':
747 if s == 'qtip':
748 return self.series[self.series_end(True)-1]
748 return self.series[self.series_end(True)-1]
749 if s == 'qbase':
749 if s == 'qbase':
750 return self.series[0]
750 return self.series[0]
751 return None
751 return None
752 if patch == None:
752 if patch == None:
753 return None
753 return None
754
754
755 # we don't want to return a partial match until we make
755 # we don't want to return a partial match until we make
756 # sure the file name passed in does not exist (checked below)
756 # sure the file name passed in does not exist (checked below)
757 res = partial_name(patch)
757 res = partial_name(patch)
758 if res and res == patch:
758 if res and res == patch:
759 return res
759 return res
760
760
761 if not os.path.isfile(self.join(patch)):
761 if not os.path.isfile(self.join(patch)):
762 try:
762 try:
763 sno = int(patch)
763 sno = int(patch)
764 except(ValueError, OverflowError):
764 except(ValueError, OverflowError):
765 pass
765 pass
766 else:
766 else:
767 if sno < len(self.series):
767 if sno < len(self.series):
768 return self.series[sno]
768 return self.series[sno]
769 if not strict:
769 if not strict:
770 # return any partial match made above
770 # return any partial match made above
771 if res:
771 if res:
772 return res
772 return res
773 minus = patch.rfind('-')
773 minus = patch.rfind('-')
774 if minus >= 0:
774 if minus >= 0:
775 res = partial_name(patch[:minus])
775 res = partial_name(patch[:minus])
776 if res:
776 if res:
777 i = self.series.index(res)
777 i = self.series.index(res)
778 try:
778 try:
779 off = int(patch[minus+1:] or 1)
779 off = int(patch[minus+1:] or 1)
780 except(ValueError, OverflowError):
780 except(ValueError, OverflowError):
781 pass
781 pass
782 else:
782 else:
783 if i - off >= 0:
783 if i - off >= 0:
784 return self.series[i - off]
784 return self.series[i - off]
785 plus = patch.rfind('+')
785 plus = patch.rfind('+')
786 if plus >= 0:
786 if plus >= 0:
787 res = partial_name(patch[:plus])
787 res = partial_name(patch[:plus])
788 if res:
788 if res:
789 i = self.series.index(res)
789 i = self.series.index(res)
790 try:
790 try:
791 off = int(patch[plus+1:] or 1)
791 off = int(patch[plus+1:] or 1)
792 except(ValueError, OverflowError):
792 except(ValueError, OverflowError):
793 pass
793 pass
794 else:
794 else:
795 if i + off < len(self.series):
795 if i + off < len(self.series):
796 return self.series[i + off]
796 return self.series[i + off]
797 raise util.Abort(_("patch %s not in series") % patch)
797 raise util.Abort(_("patch %s not in series") % patch)
798
798
799 def push(self, repo, patch=None, force=False, list=False,
799 def push(self, repo, patch=None, force=False, list=False,
800 mergeq=None):
800 mergeq=None):
801 wlock = repo.wlock()
801 wlock = repo.wlock()
802 if repo.dirstate.parents()[0] != repo.changelog.tip():
802 if repo.dirstate.parents()[0] != repo.changelog.tip():
803 self.ui.status(_("(working directory not at tip)\n"))
803 self.ui.status(_("(working directory not at tip)\n"))
804
804
805 try:
805 try:
806 patch = self.lookup(patch)
806 patch = self.lookup(patch)
807 # Suppose our series file is: A B C and the current 'top'
807 # Suppose our series file is: A B C and the current 'top'
808 # patch is B. qpush C should be performed (moving forward)
808 # patch is B. qpush C should be performed (moving forward)
809 # qpush B is a NOP (no change) qpush A is an error (can't
809 # qpush B is a NOP (no change) qpush A is an error (can't
810 # go backwards with qpush)
810 # go backwards with qpush)
811 if patch:
811 if patch:
812 info = self.isapplied(patch)
812 info = self.isapplied(patch)
813 if info:
813 if info:
814 if info[0] < len(self.applied) - 1:
814 if info[0] < len(self.applied) - 1:
815 raise util.Abort(
815 raise util.Abort(
816 _("cannot push to a previous patch: %s") % patch)
816 _("cannot push to a previous patch: %s") % patch)
817 if info[0] < len(self.series) - 1:
817 if info[0] < len(self.series) - 1:
818 self.ui.warn(
818 self.ui.warn(
819 _('qpush: %s is already at the top\n') % patch)
819 _('qpush: %s is already at the top\n') % patch)
820 else:
820 else:
821 self.ui.warn(_('all patches are currently applied\n'))
821 self.ui.warn(_('all patches are currently applied\n'))
822 return
822 return
823
823
824 # Following the above example, starting at 'top' of B:
824 # Following the above example, starting at 'top' of B:
825 # qpush should be performed (pushes C), but a subsequent
825 # qpush should be performed (pushes C), but a subsequent
826 # qpush without an argument is an error (nothing to
826 # qpush without an argument is an error (nothing to
827 # apply). This allows a loop of "...while hg qpush..." to
827 # apply). This allows a loop of "...while hg qpush..." to
828 # work as it detects an error when done
828 # work as it detects an error when done
829 if self.series_end() == len(self.series):
829 if self.series_end() == len(self.series):
830 self.ui.warn(_('patch series already fully applied\n'))
830 self.ui.warn(_('patch series already fully applied\n'))
831 return 1
831 return 1
832 if not force:
832 if not force:
833 self.check_localchanges(repo)
833 self.check_localchanges(repo)
834
834
835 self.applied_dirty = 1;
835 self.applied_dirty = 1;
836 start = self.series_end()
836 start = self.series_end()
837 if start > 0:
837 if start > 0:
838 self.check_toppatch(repo)
838 self.check_toppatch(repo)
839 if not patch:
839 if not patch:
840 patch = self.series[start]
840 patch = self.series[start]
841 end = start + 1
841 end = start + 1
842 else:
842 else:
843 end = self.series.index(patch, start) + 1
843 end = self.series.index(patch, start) + 1
844 s = self.series[start:end]
844 s = self.series[start:end]
845 all_files = {}
845 all_files = {}
846 try:
846 try:
847 if mergeq:
847 if mergeq:
848 ret = self.mergepatch(repo, mergeq, s)
848 ret = self.mergepatch(repo, mergeq, s)
849 else:
849 else:
850 ret = self.apply(repo, s, list, all_files=all_files)
850 ret = self.apply(repo, s, list, all_files=all_files)
851 except:
851 except:
852 self.ui.warn(_('cleaning up working directory...'))
852 self.ui.warn(_('cleaning up working directory...'))
853 node = repo.dirstate.parents()[0]
853 node = repo.dirstate.parents()[0]
854 hg.revert(repo, node, None)
854 hg.revert(repo, node, None)
855 unknown = repo.status()[4]
855 unknown = repo.status()[4]
856 # only remove unknown files that we know we touched or
856 # only remove unknown files that we know we touched or
857 # created while patching
857 # created while patching
858 for f in unknown:
858 for f in unknown:
859 if f in all_files:
859 if f in all_files:
860 util.unlink(repo.wjoin(f))
860 util.unlink(repo.wjoin(f))
861 self.ui.warn(_('done\n'))
861 self.ui.warn(_('done\n'))
862 raise
862 raise
863 top = self.applied[-1].name
863 top = self.applied[-1].name
864 if ret[0]:
864 if ret[0]:
865 self.ui.write(
865 self.ui.write(
866 "Errors during apply, please fix and refresh %s\n" % top)
866 "Errors during apply, please fix and refresh %s\n" % top)
867 else:
867 else:
868 self.ui.write("Now at: %s\n" % top)
868 self.ui.write("Now at: %s\n" % top)
869 return ret[0]
869 return ret[0]
870 finally:
870 finally:
871 del wlock
871 del wlock
872
872
873 def pop(self, repo, patch=None, force=False, update=True, all=False):
873 def pop(self, repo, patch=None, force=False, update=True, all=False):
874 def getfile(f, rev, flags):
874 def getfile(f, rev, flags):
875 t = repo.file(f).read(rev)
875 t = repo.file(f).read(rev)
876 repo.wwrite(f, t, flags)
876 repo.wwrite(f, t, flags)
877
877
878 wlock = repo.wlock()
878 wlock = repo.wlock()
879 try:
879 try:
880 if patch:
880 if patch:
881 # index, rev, patch
881 # index, rev, patch
882 info = self.isapplied(patch)
882 info = self.isapplied(patch)
883 if not info:
883 if not info:
884 patch = self.lookup(patch)
884 patch = self.lookup(patch)
885 info = self.isapplied(patch)
885 info = self.isapplied(patch)
886 if not info:
886 if not info:
887 raise util.Abort(_("patch %s is not applied") % patch)
887 raise util.Abort(_("patch %s is not applied") % patch)
888
888
889 if len(self.applied) == 0:
889 if len(self.applied) == 0:
890 # Allow qpop -a to work repeatedly,
890 # Allow qpop -a to work repeatedly,
891 # but not qpop without an argument
891 # but not qpop without an argument
892 self.ui.warn(_("no patches applied\n"))
892 self.ui.warn(_("no patches applied\n"))
893 return not all
893 return not all
894
894
895 if not update:
895 if not update:
896 parents = repo.dirstate.parents()
896 parents = repo.dirstate.parents()
897 rr = [ revlog.bin(x.rev) for x in self.applied ]
897 rr = [ revlog.bin(x.rev) for x in self.applied ]
898 for p in parents:
898 for p in parents:
899 if p in rr:
899 if p in rr:
900 self.ui.warn("qpop: forcing dirstate update\n")
900 self.ui.warn("qpop: forcing dirstate update\n")
901 update = True
901 update = True
902
902
903 if not force and update:
903 if not force and update:
904 self.check_localchanges(repo)
904 self.check_localchanges(repo)
905
905
906 self.applied_dirty = 1;
906 self.applied_dirty = 1;
907 end = len(self.applied)
907 end = len(self.applied)
908 if not patch:
908 if not patch:
909 if all:
909 if all:
910 popi = 0
910 popi = 0
911 else:
911 else:
912 popi = len(self.applied) - 1
912 popi = len(self.applied) - 1
913 else:
913 else:
914 popi = info[0] + 1
914 popi = info[0] + 1
915 if popi >= end:
915 if popi >= end:
916 self.ui.warn("qpop: %s is already at the top\n" % patch)
916 self.ui.warn("qpop: %s is already at the top\n" % patch)
917 return
917 return
918 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
918 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
919
919
920 start = info[0]
920 start = info[0]
921 rev = revlog.bin(info[1])
921 rev = revlog.bin(info[1])
922
922
923 if update:
923 if update:
924 top = self.check_toppatch(repo)
924 top = self.check_toppatch(repo)
925
925
926 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
926 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
927 raise util.Abort("popping would remove a revision not "
927 raise util.Abort("popping would remove a revision not "
928 "managed by this patch queue")
928 "managed by this patch queue")
929
929
930 # we know there are no local changes, so we can make a simplified
930 # we know there are no local changes, so we can make a simplified
931 # form of hg.update.
931 # form of hg.update.
932 if update:
932 if update:
933 qp = self.qparents(repo, rev)
933 qp = self.qparents(repo, rev)
934 changes = repo.changelog.read(qp)
934 changes = repo.changelog.read(qp)
935 mmap = repo.manifest.read(changes[0])
935 mmap = repo.manifest.read(changes[0])
936 m, a, r, d, u = repo.status(qp, top)[:5]
936 m, a, r, d, u = repo.status(qp, top)[:5]
937 if d:
937 if d:
938 raise util.Abort("deletions found between repo revs")
938 raise util.Abort("deletions found between repo revs")
939 for f in m:
939 for f in m:
940 getfile(f, mmap[f], mmap.flags(f))
940 getfile(f, mmap[f], mmap.flags(f))
941 for f in r:
941 for f in r:
942 getfile(f, mmap[f], mmap.flags(f))
942 getfile(f, mmap[f], mmap.flags(f))
943 for f in m + r:
943 for f in m + r:
944 repo.dirstate.normal(f)
944 repo.dirstate.normal(f)
945 for f in a:
945 for f in a:
946 try:
946 try:
947 os.unlink(repo.wjoin(f))
947 os.unlink(repo.wjoin(f))
948 except OSError, e:
948 except OSError, e:
949 if e.errno != errno.ENOENT:
949 if e.errno != errno.ENOENT:
950 raise
950 raise
951 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
951 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
952 except: pass
952 except: pass
953 repo.dirstate.forget(f)
953 repo.dirstate.forget(f)
954 repo.dirstate.setparents(qp, revlog.nullid)
954 repo.dirstate.setparents(qp, revlog.nullid)
955 del self.applied[start:end]
955 del self.applied[start:end]
956 self.strip(repo, rev, update=False, backup='strip')
956 self.strip(repo, rev, update=False, backup='strip')
957 if len(self.applied):
957 if len(self.applied):
958 self.ui.write("Now at: %s\n" % self.applied[-1].name)
958 self.ui.write("Now at: %s\n" % self.applied[-1].name)
959 else:
959 else:
960 self.ui.write("Patch queue now empty\n")
960 self.ui.write("Patch queue now empty\n")
961 finally:
961 finally:
962 del wlock
962 del wlock
963
963
964 def diff(self, repo, pats, opts):
964 def diff(self, repo, pats, opts):
965 top = self.check_toppatch(repo)
965 top = self.check_toppatch(repo)
966 if not top:
966 if not top:
967 self.ui.write("No patches applied\n")
967 self.ui.write("No patches applied\n")
968 return
968 return
969 qp = self.qparents(repo, top)
969 qp = self.qparents(repo, top)
970 if opts.get('git'):
970 self._diffopts = patch.diffopts(self.ui, opts)
971 self.diffopts().git = True
972 if opts.get('unified') is not None:
973 self.diffopts().context = opts['unified']
974 self.printdiff(repo, qp, files=pats, opts=opts)
971 self.printdiff(repo, qp, files=pats, opts=opts)
975
972
976 def refresh(self, repo, pats=None, **opts):
973 def refresh(self, repo, pats=None, **opts):
977 if len(self.applied) == 0:
974 if len(self.applied) == 0:
978 self.ui.write("No patches applied\n")
975 self.ui.write("No patches applied\n")
979 return 1
976 return 1
980 newdate = opts.get('date')
977 newdate = opts.get('date')
981 if newdate:
978 if newdate:
982 newdate = '%d %d' % util.parsedate(newdate)
979 newdate = '%d %d' % util.parsedate(newdate)
983 wlock = repo.wlock()
980 wlock = repo.wlock()
984 try:
981 try:
985 self.check_toppatch(repo)
982 self.check_toppatch(repo)
986 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
983 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
987 top = revlog.bin(top)
984 top = revlog.bin(top)
988 if repo.changelog.heads(top) != [top]:
985 if repo.changelog.heads(top) != [top]:
989 raise util.Abort("cannot refresh a revision with children")
986 raise util.Abort("cannot refresh a revision with children")
990 cparents = repo.changelog.parents(top)
987 cparents = repo.changelog.parents(top)
991 patchparent = self.qparents(repo, top)
988 patchparent = self.qparents(repo, top)
992 message, comments, user, date, patchfound = self.readheaders(patchfn)
989 message, comments, user, date, patchfound = self.readheaders(patchfn)
993
990
994 patchf = self.opener(patchfn, 'r+')
991 patchf = self.opener(patchfn, 'r+')
995
992
996 # if the patch was a git patch, refresh it as a git patch
993 # if the patch was a git patch, refresh it as a git patch
997 for line in patchf:
994 for line in patchf:
998 if line.startswith('diff --git'):
995 if line.startswith('diff --git'):
999 self.diffopts().git = True
996 self.diffopts().git = True
1000 break
997 break
1001
998
1002 msg = opts.get('msg', '').rstrip()
999 msg = opts.get('msg', '').rstrip()
1003 if msg and comments:
1000 if msg and comments:
1004 # Remove existing message, keeping the rest of the comments
1001 # Remove existing message, keeping the rest of the comments
1005 # fields.
1002 # fields.
1006 # If comments contains 'subject: ', message will prepend
1003 # If comments contains 'subject: ', message will prepend
1007 # the field and a blank line.
1004 # the field and a blank line.
1008 if message:
1005 if message:
1009 subj = 'subject: ' + message[0].lower()
1006 subj = 'subject: ' + message[0].lower()
1010 for i in xrange(len(comments)):
1007 for i in xrange(len(comments)):
1011 if subj == comments[i].lower():
1008 if subj == comments[i].lower():
1012 del comments[i]
1009 del comments[i]
1013 message = message[2:]
1010 message = message[2:]
1014 break
1011 break
1015 ci = 0
1012 ci = 0
1016 for mi in xrange(len(message)):
1013 for mi in xrange(len(message)):
1017 while message[mi] != comments[ci]:
1014 while message[mi] != comments[ci]:
1018 ci += 1
1015 ci += 1
1019 del comments[ci]
1016 del comments[ci]
1020
1017
1021 def setheaderfield(comments, prefixes, new):
1018 def setheaderfield(comments, prefixes, new):
1022 # Update all references to a field in the patch header.
1019 # Update all references to a field in the patch header.
1023 # If none found, add it email style.
1020 # If none found, add it email style.
1024 res = False
1021 res = False
1025 for prefix in prefixes:
1022 for prefix in prefixes:
1026 for i in xrange(len(comments)):
1023 for i in xrange(len(comments)):
1027 if comments[i].startswith(prefix):
1024 if comments[i].startswith(prefix):
1028 comments[i] = prefix + new
1025 comments[i] = prefix + new
1029 res = True
1026 res = True
1030 break
1027 break
1031 return res
1028 return res
1032
1029
1033 newuser = opts.get('user')
1030 newuser = opts.get('user')
1034 if newuser:
1031 if newuser:
1035 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1032 if not setheaderfield(comments, ['From: ', '# User '], newuser):
1036 try:
1033 try:
1037 patchheaderat = comments.index('# HG changeset patch')
1034 patchheaderat = comments.index('# HG changeset patch')
1038 comments.insert(patchheaderat + 1,'# User ' + newuser)
1035 comments.insert(patchheaderat + 1,'# User ' + newuser)
1039 except ValueError:
1036 except ValueError:
1040 comments = ['From: ' + newuser, ''] + comments
1037 comments = ['From: ' + newuser, ''] + comments
1041 user = newuser
1038 user = newuser
1042
1039
1043 if newdate:
1040 if newdate:
1044 if setheaderfield(comments, ['# Date '], newdate):
1041 if setheaderfield(comments, ['# Date '], newdate):
1045 date = newdate
1042 date = newdate
1046
1043
1047 if msg:
1044 if msg:
1048 comments.append(msg)
1045 comments.append(msg)
1049
1046
1050 patchf.seek(0)
1047 patchf.seek(0)
1051 patchf.truncate()
1048 patchf.truncate()
1052
1049
1053 if comments:
1050 if comments:
1054 comments = "\n".join(comments) + '\n\n'
1051 comments = "\n".join(comments) + '\n\n'
1055 patchf.write(comments)
1052 patchf.write(comments)
1056
1053
1057 if opts.get('git'):
1054 if opts.get('git'):
1058 self.diffopts().git = True
1055 self.diffopts().git = True
1059 matchfn = cmdutil.match(repo, pats, opts)
1056 matchfn = cmdutil.match(repo, pats, opts)
1060 tip = repo.changelog.tip()
1057 tip = repo.changelog.tip()
1061 if top == tip:
1058 if top == tip:
1062 # if the top of our patch queue is also the tip, there is an
1059 # if the top of our patch queue is also the tip, there is an
1063 # optimization here. We update the dirstate in place and strip
1060 # optimization here. We update the dirstate in place and strip
1064 # off the tip commit. Then just commit the current directory
1061 # off the tip commit. Then just commit the current directory
1065 # tree. We can also send repo.commit the list of files
1062 # tree. We can also send repo.commit the list of files
1066 # changed to speed up the diff
1063 # changed to speed up the diff
1067 #
1064 #
1068 # in short mode, we only diff the files included in the
1065 # in short mode, we only diff the files included in the
1069 # patch already
1066 # patch already
1070 #
1067 #
1071 # this should really read:
1068 # this should really read:
1072 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1069 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1073 # but we do it backwards to take advantage of manifest/chlog
1070 # but we do it backwards to take advantage of manifest/chlog
1074 # caching against the next repo.status call
1071 # caching against the next repo.status call
1075 #
1072 #
1076 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1073 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1077 changes = repo.changelog.read(tip)
1074 changes = repo.changelog.read(tip)
1078 man = repo.manifest.read(changes[0])
1075 man = repo.manifest.read(changes[0])
1079 aaa = aa[:]
1076 aaa = aa[:]
1080 if opts.get('short'):
1077 if opts.get('short'):
1081 match = cmdutil.matchfiles(repo, mm + aa + dd)
1078 match = cmdutil.matchfiles(repo, mm + aa + dd)
1082 else:
1079 else:
1083 match = cmdutil.matchall(repo)
1080 match = cmdutil.matchall(repo)
1084 m, a, r, d, u = repo.status(match=match)[:5]
1081 m, a, r, d, u = repo.status(match=match)[:5]
1085
1082
1086 # we might end up with files that were added between
1083 # we might end up with files that were added between
1087 # tip and the dirstate parent, but then changed in the
1084 # tip and the dirstate parent, but then changed in the
1088 # local dirstate. in this case, we want them to only
1085 # local dirstate. in this case, we want them to only
1089 # show up in the added section
1086 # show up in the added section
1090 for x in m:
1087 for x in m:
1091 if x not in aa:
1088 if x not in aa:
1092 mm.append(x)
1089 mm.append(x)
1093 # we might end up with files added by the local dirstate that
1090 # we might end up with files added by the local dirstate that
1094 # were deleted by the patch. In this case, they should only
1091 # were deleted by the patch. In this case, they should only
1095 # show up in the changed section.
1092 # show up in the changed section.
1096 for x in a:
1093 for x in a:
1097 if x in dd:
1094 if x in dd:
1098 del dd[dd.index(x)]
1095 del dd[dd.index(x)]
1099 mm.append(x)
1096 mm.append(x)
1100 else:
1097 else:
1101 aa.append(x)
1098 aa.append(x)
1102 # make sure any files deleted in the local dirstate
1099 # make sure any files deleted in the local dirstate
1103 # are not in the add or change column of the patch
1100 # are not in the add or change column of the patch
1104 forget = []
1101 forget = []
1105 for x in d + r:
1102 for x in d + r:
1106 if x in aa:
1103 if x in aa:
1107 del aa[aa.index(x)]
1104 del aa[aa.index(x)]
1108 forget.append(x)
1105 forget.append(x)
1109 continue
1106 continue
1110 elif x in mm:
1107 elif x in mm:
1111 del mm[mm.index(x)]
1108 del mm[mm.index(x)]
1112 dd.append(x)
1109 dd.append(x)
1113
1110
1114 m = util.unique(mm)
1111 m = util.unique(mm)
1115 r = util.unique(dd)
1112 r = util.unique(dd)
1116 a = util.unique(aa)
1113 a = util.unique(aa)
1117 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1114 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1118 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1115 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1119 patch.diff(repo, patchparent, match=match,
1116 patch.diff(repo, patchparent, match=match,
1120 fp=patchf, changes=c, opts=self.diffopts())
1117 fp=patchf, changes=c, opts=self.diffopts())
1121 patchf.close()
1118 patchf.close()
1122
1119
1123 repo.dirstate.setparents(*cparents)
1120 repo.dirstate.setparents(*cparents)
1124 copies = {}
1121 copies = {}
1125 for dst in a:
1122 for dst in a:
1126 src = repo.dirstate.copied(dst)
1123 src = repo.dirstate.copied(dst)
1127 if src is not None:
1124 if src is not None:
1128 copies.setdefault(src, []).append(dst)
1125 copies.setdefault(src, []).append(dst)
1129 repo.dirstate.add(dst)
1126 repo.dirstate.add(dst)
1130 # remember the copies between patchparent and tip
1127 # remember the copies between patchparent and tip
1131 # this may be slow, so don't do it if we're not tracking copies
1128 # this may be slow, so don't do it if we're not tracking copies
1132 if self.diffopts().git:
1129 if self.diffopts().git:
1133 for dst in aaa:
1130 for dst in aaa:
1134 f = repo.file(dst)
1131 f = repo.file(dst)
1135 src = f.renamed(man[dst])
1132 src = f.renamed(man[dst])
1136 if src:
1133 if src:
1137 copies[src[0]] = copies.get(dst, [])
1134 copies[src[0]] = copies.get(dst, [])
1138 if dst in a:
1135 if dst in a:
1139 copies[src[0]].append(dst)
1136 copies[src[0]].append(dst)
1140 # we can't copy a file created by the patch itself
1137 # we can't copy a file created by the patch itself
1141 if dst in copies:
1138 if dst in copies:
1142 del copies[dst]
1139 del copies[dst]
1143 for src, dsts in copies.iteritems():
1140 for src, dsts in copies.iteritems():
1144 for dst in dsts:
1141 for dst in dsts:
1145 repo.dirstate.copy(src, dst)
1142 repo.dirstate.copy(src, dst)
1146 for f in r:
1143 for f in r:
1147 repo.dirstate.remove(f)
1144 repo.dirstate.remove(f)
1148 # if the patch excludes a modified file, mark that
1145 # if the patch excludes a modified file, mark that
1149 # file with mtime=0 so status can see it.
1146 # file with mtime=0 so status can see it.
1150 mm = []
1147 mm = []
1151 for i in xrange(len(m)-1, -1, -1):
1148 for i in xrange(len(m)-1, -1, -1):
1152 if not matchfn(m[i]):
1149 if not matchfn(m[i]):
1153 mm.append(m[i])
1150 mm.append(m[i])
1154 del m[i]
1151 del m[i]
1155 for f in m:
1152 for f in m:
1156 repo.dirstate.normal(f)
1153 repo.dirstate.normal(f)
1157 for f in mm:
1154 for f in mm:
1158 repo.dirstate.normallookup(f)
1155 repo.dirstate.normallookup(f)
1159 for f in forget:
1156 for f in forget:
1160 repo.dirstate.forget(f)
1157 repo.dirstate.forget(f)
1161
1158
1162 if not msg:
1159 if not msg:
1163 if not message:
1160 if not message:
1164 message = "[mq]: %s\n" % patchfn
1161 message = "[mq]: %s\n" % patchfn
1165 else:
1162 else:
1166 message = "\n".join(message)
1163 message = "\n".join(message)
1167 else:
1164 else:
1168 message = msg
1165 message = msg
1169
1166
1170 if not user:
1167 if not user:
1171 user = changes[1]
1168 user = changes[1]
1172
1169
1173 self.applied.pop()
1170 self.applied.pop()
1174 self.applied_dirty = 1
1171 self.applied_dirty = 1
1175 self.strip(repo, top, update=False,
1172 self.strip(repo, top, update=False,
1176 backup='strip')
1173 backup='strip')
1177 n = repo.commit(match.files(), message, user, date, match=match,
1174 n = repo.commit(match.files(), message, user, date, match=match,
1178 force=1)
1175 force=1)
1179 self.applied.append(statusentry(revlog.hex(n), patchfn))
1176 self.applied.append(statusentry(revlog.hex(n), patchfn))
1180 self.removeundo(repo)
1177 self.removeundo(repo)
1181 else:
1178 else:
1182 self.printdiff(repo, patchparent, fp=patchf)
1179 self.printdiff(repo, patchparent, fp=patchf)
1183 patchf.close()
1180 patchf.close()
1184 added = repo.status()[1]
1181 added = repo.status()[1]
1185 for a in added:
1182 for a in added:
1186 f = repo.wjoin(a)
1183 f = repo.wjoin(a)
1187 try:
1184 try:
1188 os.unlink(f)
1185 os.unlink(f)
1189 except OSError, e:
1186 except OSError, e:
1190 if e.errno != errno.ENOENT:
1187 if e.errno != errno.ENOENT:
1191 raise
1188 raise
1192 try: os.removedirs(os.path.dirname(f))
1189 try: os.removedirs(os.path.dirname(f))
1193 except: pass
1190 except: pass
1194 # forget the file copies in the dirstate
1191 # forget the file copies in the dirstate
1195 # push should readd the files later on
1192 # push should readd the files later on
1196 repo.dirstate.forget(a)
1193 repo.dirstate.forget(a)
1197 self.pop(repo, force=True)
1194 self.pop(repo, force=True)
1198 self.push(repo, force=True)
1195 self.push(repo, force=True)
1199 finally:
1196 finally:
1200 del wlock
1197 del wlock
1201
1198
1202 def init(self, repo, create=False):
1199 def init(self, repo, create=False):
1203 if not create and os.path.isdir(self.path):
1200 if not create and os.path.isdir(self.path):
1204 raise util.Abort(_("patch queue directory already exists"))
1201 raise util.Abort(_("patch queue directory already exists"))
1205 try:
1202 try:
1206 os.mkdir(self.path)
1203 os.mkdir(self.path)
1207 except OSError, inst:
1204 except OSError, inst:
1208 if inst.errno != errno.EEXIST or not create:
1205 if inst.errno != errno.EEXIST or not create:
1209 raise
1206 raise
1210 if create:
1207 if create:
1211 return self.qrepo(create=True)
1208 return self.qrepo(create=True)
1212
1209
1213 def unapplied(self, repo, patch=None):
1210 def unapplied(self, repo, patch=None):
1214 if patch and patch not in self.series:
1211 if patch and patch not in self.series:
1215 raise util.Abort(_("patch %s is not in series file") % patch)
1212 raise util.Abort(_("patch %s is not in series file") % patch)
1216 if not patch:
1213 if not patch:
1217 start = self.series_end()
1214 start = self.series_end()
1218 else:
1215 else:
1219 start = self.series.index(patch) + 1
1216 start = self.series.index(patch) + 1
1220 unapplied = []
1217 unapplied = []
1221 for i in xrange(start, len(self.series)):
1218 for i in xrange(start, len(self.series)):
1222 pushable, reason = self.pushable(i)
1219 pushable, reason = self.pushable(i)
1223 if pushable:
1220 if pushable:
1224 unapplied.append((i, self.series[i]))
1221 unapplied.append((i, self.series[i]))
1225 self.explain_pushable(i)
1222 self.explain_pushable(i)
1226 return unapplied
1223 return unapplied
1227
1224
1228 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1225 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1229 summary=False):
1226 summary=False):
1230 def displayname(patchname):
1227 def displayname(patchname):
1231 if summary:
1228 if summary:
1232 msg = self.readheaders(patchname)[0]
1229 msg = self.readheaders(patchname)[0]
1233 msg = msg and ': ' + msg[0] or ': '
1230 msg = msg and ': ' + msg[0] or ': '
1234 else:
1231 else:
1235 msg = ''
1232 msg = ''
1236 return '%s%s' % (patchname, msg)
1233 return '%s%s' % (patchname, msg)
1237
1234
1238 applied = dict.fromkeys([p.name for p in self.applied])
1235 applied = dict.fromkeys([p.name for p in self.applied])
1239 if length is None:
1236 if length is None:
1240 length = len(self.series) - start
1237 length = len(self.series) - start
1241 if not missing:
1238 if not missing:
1242 for i in xrange(start, start+length):
1239 for i in xrange(start, start+length):
1243 patch = self.series[i]
1240 patch = self.series[i]
1244 if patch in applied:
1241 if patch in applied:
1245 stat = 'A'
1242 stat = 'A'
1246 elif self.pushable(i)[0]:
1243 elif self.pushable(i)[0]:
1247 stat = 'U'
1244 stat = 'U'
1248 else:
1245 else:
1249 stat = 'G'
1246 stat = 'G'
1250 pfx = ''
1247 pfx = ''
1251 if self.ui.verbose:
1248 if self.ui.verbose:
1252 pfx = '%d %s ' % (i, stat)
1249 pfx = '%d %s ' % (i, stat)
1253 elif status and status != stat:
1250 elif status and status != stat:
1254 continue
1251 continue
1255 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1252 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1256 else:
1253 else:
1257 msng_list = []
1254 msng_list = []
1258 for root, dirs, files in os.walk(self.path):
1255 for root, dirs, files in os.walk(self.path):
1259 d = root[len(self.path) + 1:]
1256 d = root[len(self.path) + 1:]
1260 for f in files:
1257 for f in files:
1261 fl = os.path.join(d, f)
1258 fl = os.path.join(d, f)
1262 if (fl not in self.series and
1259 if (fl not in self.series and
1263 fl not in (self.status_path, self.series_path,
1260 fl not in (self.status_path, self.series_path,
1264 self.guards_path)
1261 self.guards_path)
1265 and not fl.startswith('.')):
1262 and not fl.startswith('.')):
1266 msng_list.append(fl)
1263 msng_list.append(fl)
1267 msng_list.sort()
1264 msng_list.sort()
1268 for x in msng_list:
1265 for x in msng_list:
1269 pfx = self.ui.verbose and ('D ') or ''
1266 pfx = self.ui.verbose and ('D ') or ''
1270 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1267 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1271
1268
1272 def issaveline(self, l):
1269 def issaveline(self, l):
1273 if l.name == '.hg.patches.save.line':
1270 if l.name == '.hg.patches.save.line':
1274 return True
1271 return True
1275
1272
1276 def qrepo(self, create=False):
1273 def qrepo(self, create=False):
1277 if create or os.path.isdir(self.join(".hg")):
1274 if create or os.path.isdir(self.join(".hg")):
1278 return hg.repository(self.ui, path=self.path, create=create)
1275 return hg.repository(self.ui, path=self.path, create=create)
1279
1276
1280 def restore(self, repo, rev, delete=None, qupdate=None):
1277 def restore(self, repo, rev, delete=None, qupdate=None):
1281 c = repo.changelog.read(rev)
1278 c = repo.changelog.read(rev)
1282 desc = c[4].strip()
1279 desc = c[4].strip()
1283 lines = desc.splitlines()
1280 lines = desc.splitlines()
1284 i = 0
1281 i = 0
1285 datastart = None
1282 datastart = None
1286 series = []
1283 series = []
1287 applied = []
1284 applied = []
1288 qpp = None
1285 qpp = None
1289 for i in xrange(0, len(lines)):
1286 for i in xrange(0, len(lines)):
1290 if lines[i] == 'Patch Data:':
1287 if lines[i] == 'Patch Data:':
1291 datastart = i + 1
1288 datastart = i + 1
1292 elif lines[i].startswith('Dirstate:'):
1289 elif lines[i].startswith('Dirstate:'):
1293 l = lines[i].rstrip()
1290 l = lines[i].rstrip()
1294 l = l[10:].split(' ')
1291 l = l[10:].split(' ')
1295 qpp = [ bin(x) for x in l ]
1292 qpp = [ bin(x) for x in l ]
1296 elif datastart != None:
1293 elif datastart != None:
1297 l = lines[i].rstrip()
1294 l = lines[i].rstrip()
1298 se = statusentry(l)
1295 se = statusentry(l)
1299 file_ = se.name
1296 file_ = se.name
1300 if se.rev:
1297 if se.rev:
1301 applied.append(se)
1298 applied.append(se)
1302 else:
1299 else:
1303 series.append(file_)
1300 series.append(file_)
1304 if datastart == None:
1301 if datastart == None:
1305 self.ui.warn("No saved patch data found\n")
1302 self.ui.warn("No saved patch data found\n")
1306 return 1
1303 return 1
1307 self.ui.warn("restoring status: %s\n" % lines[0])
1304 self.ui.warn("restoring status: %s\n" % lines[0])
1308 self.full_series = series
1305 self.full_series = series
1309 self.applied = applied
1306 self.applied = applied
1310 self.parse_series()
1307 self.parse_series()
1311 self.series_dirty = 1
1308 self.series_dirty = 1
1312 self.applied_dirty = 1
1309 self.applied_dirty = 1
1313 heads = repo.changelog.heads()
1310 heads = repo.changelog.heads()
1314 if delete:
1311 if delete:
1315 if rev not in heads:
1312 if rev not in heads:
1316 self.ui.warn("save entry has children, leaving it alone\n")
1313 self.ui.warn("save entry has children, leaving it alone\n")
1317 else:
1314 else:
1318 self.ui.warn("removing save entry %s\n" % short(rev))
1315 self.ui.warn("removing save entry %s\n" % short(rev))
1319 pp = repo.dirstate.parents()
1316 pp = repo.dirstate.parents()
1320 if rev in pp:
1317 if rev in pp:
1321 update = True
1318 update = True
1322 else:
1319 else:
1323 update = False
1320 update = False
1324 self.strip(repo, rev, update=update, backup='strip')
1321 self.strip(repo, rev, update=update, backup='strip')
1325 if qpp:
1322 if qpp:
1326 self.ui.warn("saved queue repository parents: %s %s\n" %
1323 self.ui.warn("saved queue repository parents: %s %s\n" %
1327 (short(qpp[0]), short(qpp[1])))
1324 (short(qpp[0]), short(qpp[1])))
1328 if qupdate:
1325 if qupdate:
1329 self.ui.status(_("queue directory updating\n"))
1326 self.ui.status(_("queue directory updating\n"))
1330 r = self.qrepo()
1327 r = self.qrepo()
1331 if not r:
1328 if not r:
1332 self.ui.warn("Unable to load queue repository\n")
1329 self.ui.warn("Unable to load queue repository\n")
1333 return 1
1330 return 1
1334 hg.clean(r, qpp[0])
1331 hg.clean(r, qpp[0])
1335
1332
1336 def save(self, repo, msg=None):
1333 def save(self, repo, msg=None):
1337 if len(self.applied) == 0:
1334 if len(self.applied) == 0:
1338 self.ui.warn("save: no patches applied, exiting\n")
1335 self.ui.warn("save: no patches applied, exiting\n")
1339 return 1
1336 return 1
1340 if self.issaveline(self.applied[-1]):
1337 if self.issaveline(self.applied[-1]):
1341 self.ui.warn("status is already saved\n")
1338 self.ui.warn("status is already saved\n")
1342 return 1
1339 return 1
1343
1340
1344 ar = [ ':' + x for x in self.full_series ]
1341 ar = [ ':' + x for x in self.full_series ]
1345 if not msg:
1342 if not msg:
1346 msg = "hg patches saved state"
1343 msg = "hg patches saved state"
1347 else:
1344 else:
1348 msg = "hg patches: " + msg.rstrip('\r\n')
1345 msg = "hg patches: " + msg.rstrip('\r\n')
1349 r = self.qrepo()
1346 r = self.qrepo()
1350 if r:
1347 if r:
1351 pp = r.dirstate.parents()
1348 pp = r.dirstate.parents()
1352 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1349 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1353 msg += "\n\nPatch Data:\n"
1350 msg += "\n\nPatch Data:\n"
1354 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1351 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1355 "\n".join(ar) + '\n' or "")
1352 "\n".join(ar) + '\n' or "")
1356 n = repo.commit(None, text, user=None, force=1)
1353 n = repo.commit(None, text, user=None, force=1)
1357 if not n:
1354 if not n:
1358 self.ui.warn("repo commit failed\n")
1355 self.ui.warn("repo commit failed\n")
1359 return 1
1356 return 1
1360 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1357 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1361 self.applied_dirty = 1
1358 self.applied_dirty = 1
1362 self.removeundo(repo)
1359 self.removeundo(repo)
1363
1360
1364 def full_series_end(self):
1361 def full_series_end(self):
1365 if len(self.applied) > 0:
1362 if len(self.applied) > 0:
1366 p = self.applied[-1].name
1363 p = self.applied[-1].name
1367 end = self.find_series(p)
1364 end = self.find_series(p)
1368 if end == None:
1365 if end == None:
1369 return len(self.full_series)
1366 return len(self.full_series)
1370 return end + 1
1367 return end + 1
1371 return 0
1368 return 0
1372
1369
1373 def series_end(self, all_patches=False):
1370 def series_end(self, all_patches=False):
1374 """If all_patches is False, return the index of the next pushable patch
1371 """If all_patches is False, return the index of the next pushable patch
1375 in the series, or the series length. If all_patches is True, return the
1372 in the series, or the series length. If all_patches is True, return the
1376 index of the first patch past the last applied one.
1373 index of the first patch past the last applied one.
1377 """
1374 """
1378 end = 0
1375 end = 0
1379 def next(start):
1376 def next(start):
1380 if all_patches:
1377 if all_patches:
1381 return start
1378 return start
1382 i = start
1379 i = start
1383 while i < len(self.series):
1380 while i < len(self.series):
1384 p, reason = self.pushable(i)
1381 p, reason = self.pushable(i)
1385 if p:
1382 if p:
1386 break
1383 break
1387 self.explain_pushable(i)
1384 self.explain_pushable(i)
1388 i += 1
1385 i += 1
1389 return i
1386 return i
1390 if len(self.applied) > 0:
1387 if len(self.applied) > 0:
1391 p = self.applied[-1].name
1388 p = self.applied[-1].name
1392 try:
1389 try:
1393 end = self.series.index(p)
1390 end = self.series.index(p)
1394 except ValueError:
1391 except ValueError:
1395 return 0
1392 return 0
1396 return next(end + 1)
1393 return next(end + 1)
1397 return next(end)
1394 return next(end)
1398
1395
1399 def appliedname(self, index):
1396 def appliedname(self, index):
1400 pname = self.applied[index].name
1397 pname = self.applied[index].name
1401 if not self.ui.verbose:
1398 if not self.ui.verbose:
1402 p = pname
1399 p = pname
1403 else:
1400 else:
1404 p = str(self.series.index(pname)) + " " + pname
1401 p = str(self.series.index(pname)) + " " + pname
1405 return p
1402 return p
1406
1403
1407 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1404 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1408 force=None, git=False):
1405 force=None, git=False):
1409 def checkseries(patchname):
1406 def checkseries(patchname):
1410 if patchname in self.series:
1407 if patchname in self.series:
1411 raise util.Abort(_('patch %s is already in the series file')
1408 raise util.Abort(_('patch %s is already in the series file')
1412 % patchname)
1409 % patchname)
1413 def checkfile(patchname):
1410 def checkfile(patchname):
1414 if not force and os.path.exists(self.join(patchname)):
1411 if not force and os.path.exists(self.join(patchname)):
1415 raise util.Abort(_('patch "%s" already exists')
1412 raise util.Abort(_('patch "%s" already exists')
1416 % patchname)
1413 % patchname)
1417
1414
1418 if rev:
1415 if rev:
1419 if files:
1416 if files:
1420 raise util.Abort(_('option "-r" not valid when importing '
1417 raise util.Abort(_('option "-r" not valid when importing '
1421 'files'))
1418 'files'))
1422 rev = cmdutil.revrange(repo, rev)
1419 rev = cmdutil.revrange(repo, rev)
1423 rev.sort(lambda x, y: cmp(y, x))
1420 rev.sort(lambda x, y: cmp(y, x))
1424 if (len(files) > 1 or len(rev) > 1) and patchname:
1421 if (len(files) > 1 or len(rev) > 1) and patchname:
1425 raise util.Abort(_('option "-n" not valid when importing multiple '
1422 raise util.Abort(_('option "-n" not valid when importing multiple '
1426 'patches'))
1423 'patches'))
1427 i = 0
1424 i = 0
1428 added = []
1425 added = []
1429 if rev:
1426 if rev:
1430 # If mq patches are applied, we can only import revisions
1427 # If mq patches are applied, we can only import revisions
1431 # that form a linear path to qbase.
1428 # that form a linear path to qbase.
1432 # Otherwise, they should form a linear path to a head.
1429 # Otherwise, they should form a linear path to a head.
1433 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1430 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1434 if len(heads) > 1:
1431 if len(heads) > 1:
1435 raise util.Abort(_('revision %d is the root of more than one '
1432 raise util.Abort(_('revision %d is the root of more than one '
1436 'branch') % rev[-1])
1433 'branch') % rev[-1])
1437 if self.applied:
1434 if self.applied:
1438 base = revlog.hex(repo.changelog.node(rev[0]))
1435 base = revlog.hex(repo.changelog.node(rev[0]))
1439 if base in [n.rev for n in self.applied]:
1436 if base in [n.rev for n in self.applied]:
1440 raise util.Abort(_('revision %d is already managed')
1437 raise util.Abort(_('revision %d is already managed')
1441 % rev[0])
1438 % rev[0])
1442 if heads != [revlog.bin(self.applied[-1].rev)]:
1439 if heads != [revlog.bin(self.applied[-1].rev)]:
1443 raise util.Abort(_('revision %d is not the parent of '
1440 raise util.Abort(_('revision %d is not the parent of '
1444 'the queue') % rev[0])
1441 'the queue') % rev[0])
1445 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1442 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1446 lastparent = repo.changelog.parentrevs(base)[0]
1443 lastparent = repo.changelog.parentrevs(base)[0]
1447 else:
1444 else:
1448 if heads != [repo.changelog.node(rev[0])]:
1445 if heads != [repo.changelog.node(rev[0])]:
1449 raise util.Abort(_('revision %d has unmanaged children')
1446 raise util.Abort(_('revision %d has unmanaged children')
1450 % rev[0])
1447 % rev[0])
1451 lastparent = None
1448 lastparent = None
1452
1449
1453 if git:
1450 if git:
1454 self.diffopts().git = True
1451 self.diffopts().git = True
1455
1452
1456 for r in rev:
1453 for r in rev:
1457 p1, p2 = repo.changelog.parentrevs(r)
1454 p1, p2 = repo.changelog.parentrevs(r)
1458 n = repo.changelog.node(r)
1455 n = repo.changelog.node(r)
1459 if p2 != revlog.nullrev:
1456 if p2 != revlog.nullrev:
1460 raise util.Abort(_('cannot import merge revision %d') % r)
1457 raise util.Abort(_('cannot import merge revision %d') % r)
1461 if lastparent and lastparent != r:
1458 if lastparent and lastparent != r:
1462 raise util.Abort(_('revision %d is not the parent of %d')
1459 raise util.Abort(_('revision %d is not the parent of %d')
1463 % (r, lastparent))
1460 % (r, lastparent))
1464 lastparent = p1
1461 lastparent = p1
1465
1462
1466 if not patchname:
1463 if not patchname:
1467 patchname = normname('%d.diff' % r)
1464 patchname = normname('%d.diff' % r)
1468 self.check_reserved_name(patchname)
1465 self.check_reserved_name(patchname)
1469 checkseries(patchname)
1466 checkseries(patchname)
1470 checkfile(patchname)
1467 checkfile(patchname)
1471 self.full_series.insert(0, patchname)
1468 self.full_series.insert(0, patchname)
1472
1469
1473 patchf = self.opener(patchname, "w")
1470 patchf = self.opener(patchname, "w")
1474 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1471 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1475 patchf.close()
1472 patchf.close()
1476
1473
1477 se = statusentry(revlog.hex(n), patchname)
1474 se = statusentry(revlog.hex(n), patchname)
1478 self.applied.insert(0, se)
1475 self.applied.insert(0, se)
1479
1476
1480 added.append(patchname)
1477 added.append(patchname)
1481 patchname = None
1478 patchname = None
1482 self.parse_series()
1479 self.parse_series()
1483 self.applied_dirty = 1
1480 self.applied_dirty = 1
1484
1481
1485 for filename in files:
1482 for filename in files:
1486 if existing:
1483 if existing:
1487 if filename == '-':
1484 if filename == '-':
1488 raise util.Abort(_('-e is incompatible with import from -'))
1485 raise util.Abort(_('-e is incompatible with import from -'))
1489 if not patchname:
1486 if not patchname:
1490 patchname = normname(filename)
1487 patchname = normname(filename)
1491 self.check_reserved_name(patchname)
1488 self.check_reserved_name(patchname)
1492 if not os.path.isfile(self.join(patchname)):
1489 if not os.path.isfile(self.join(patchname)):
1493 raise util.Abort(_("patch %s does not exist") % patchname)
1490 raise util.Abort(_("patch %s does not exist") % patchname)
1494 else:
1491 else:
1495 try:
1492 try:
1496 if filename == '-':
1493 if filename == '-':
1497 if not patchname:
1494 if not patchname:
1498 raise util.Abort(_('need --name to import a patch from -'))
1495 raise util.Abort(_('need --name to import a patch from -'))
1499 text = sys.stdin.read()
1496 text = sys.stdin.read()
1500 else:
1497 else:
1501 text = file(filename, 'rb').read()
1498 text = file(filename, 'rb').read()
1502 except IOError:
1499 except IOError:
1503 raise util.Abort(_("unable to read %s") % patchname)
1500 raise util.Abort(_("unable to read %s") % patchname)
1504 if not patchname:
1501 if not patchname:
1505 patchname = normname(os.path.basename(filename))
1502 patchname = normname(os.path.basename(filename))
1506 self.check_reserved_name(patchname)
1503 self.check_reserved_name(patchname)
1507 checkfile(patchname)
1504 checkfile(patchname)
1508 patchf = self.opener(patchname, "w")
1505 patchf = self.opener(patchname, "w")
1509 patchf.write(text)
1506 patchf.write(text)
1510 checkseries(patchname)
1507 checkseries(patchname)
1511 index = self.full_series_end() + i
1508 index = self.full_series_end() + i
1512 self.full_series[index:index] = [patchname]
1509 self.full_series[index:index] = [patchname]
1513 self.parse_series()
1510 self.parse_series()
1514 self.ui.warn("adding %s to series file\n" % patchname)
1511 self.ui.warn("adding %s to series file\n" % patchname)
1515 i += 1
1512 i += 1
1516 added.append(patchname)
1513 added.append(patchname)
1517 patchname = None
1514 patchname = None
1518 self.series_dirty = 1
1515 self.series_dirty = 1
1519 qrepo = self.qrepo()
1516 qrepo = self.qrepo()
1520 if qrepo:
1517 if qrepo:
1521 qrepo.add(added)
1518 qrepo.add(added)
1522
1519
1523 def delete(ui, repo, *patches, **opts):
1520 def delete(ui, repo, *patches, **opts):
1524 """remove patches from queue
1521 """remove patches from queue
1525
1522
1526 The patches must not be applied, unless they are arguments to
1523 The patches must not be applied, unless they are arguments to
1527 the --rev parameter. At least one patch or revision is required.
1524 the --rev parameter. At least one patch or revision is required.
1528
1525
1529 With --rev, mq will stop managing the named revisions (converting
1526 With --rev, mq will stop managing the named revisions (converting
1530 them to regular mercurial changesets). The qfinish command should be
1527 them to regular mercurial changesets). The qfinish command should be
1531 used as an alternative for qdel -r, as the latter option is deprecated.
1528 used as an alternative for qdel -r, as the latter option is deprecated.
1532
1529
1533 With --keep, the patch files are preserved in the patch directory."""
1530 With --keep, the patch files are preserved in the patch directory."""
1534 q = repo.mq
1531 q = repo.mq
1535 q.delete(repo, patches, opts)
1532 q.delete(repo, patches, opts)
1536 q.save_dirty()
1533 q.save_dirty()
1537 return 0
1534 return 0
1538
1535
1539 def applied(ui, repo, patch=None, **opts):
1536 def applied(ui, repo, patch=None, **opts):
1540 """print the patches already applied"""
1537 """print the patches already applied"""
1541 q = repo.mq
1538 q = repo.mq
1542 if patch:
1539 if patch:
1543 if patch not in q.series:
1540 if patch not in q.series:
1544 raise util.Abort(_("patch %s is not in series file") % patch)
1541 raise util.Abort(_("patch %s is not in series file") % patch)
1545 end = q.series.index(patch) + 1
1542 end = q.series.index(patch) + 1
1546 else:
1543 else:
1547 end = q.series_end(True)
1544 end = q.series_end(True)
1548 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1545 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1549
1546
1550 def unapplied(ui, repo, patch=None, **opts):
1547 def unapplied(ui, repo, patch=None, **opts):
1551 """print the patches not yet applied"""
1548 """print the patches not yet applied"""
1552 q = repo.mq
1549 q = repo.mq
1553 if patch:
1550 if patch:
1554 if patch not in q.series:
1551 if patch not in q.series:
1555 raise util.Abort(_("patch %s is not in series file") % patch)
1552 raise util.Abort(_("patch %s is not in series file") % patch)
1556 start = q.series.index(patch) + 1
1553 start = q.series.index(patch) + 1
1557 else:
1554 else:
1558 start = q.series_end(True)
1555 start = q.series_end(True)
1559 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1556 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1560
1557
1561 def qimport(ui, repo, *filename, **opts):
1558 def qimport(ui, repo, *filename, **opts):
1562 """import a patch
1559 """import a patch
1563
1560
1564 The patch is inserted into the series after the last applied patch.
1561 The patch is inserted into the series after the last applied patch.
1565 If no patches have been applied, qimport prepends the patch
1562 If no patches have been applied, qimport prepends the patch
1566 to the series.
1563 to the series.
1567
1564
1568 The patch will have the same name as its source file unless you
1565 The patch will have the same name as its source file unless you
1569 give it a new one with --name.
1566 give it a new one with --name.
1570
1567
1571 You can register an existing patch inside the patch directory
1568 You can register an existing patch inside the patch directory
1572 with the --existing flag.
1569 with the --existing flag.
1573
1570
1574 With --force, an existing patch of the same name will be overwritten.
1571 With --force, an existing patch of the same name will be overwritten.
1575
1572
1576 An existing changeset may be placed under mq control with --rev
1573 An existing changeset may be placed under mq control with --rev
1577 (e.g. qimport --rev tip -n patch will place tip under mq control).
1574 (e.g. qimport --rev tip -n patch will place tip under mq control).
1578 With --git, patches imported with --rev will use the git diff
1575 With --git, patches imported with --rev will use the git diff
1579 format.
1576 format.
1580 """
1577 """
1581 q = repo.mq
1578 q = repo.mq
1582 q.qimport(repo, filename, patchname=opts['name'],
1579 q.qimport(repo, filename, patchname=opts['name'],
1583 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1580 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1584 git=opts['git'])
1581 git=opts['git'])
1585 q.save_dirty()
1582 q.save_dirty()
1586 return 0
1583 return 0
1587
1584
1588 def init(ui, repo, **opts):
1585 def init(ui, repo, **opts):
1589 """init a new queue repository
1586 """init a new queue repository
1590
1587
1591 The queue repository is unversioned by default. If -c is
1588 The queue repository is unversioned by default. If -c is
1592 specified, qinit will create a separate nested repository
1589 specified, qinit will create a separate nested repository
1593 for patches (qinit -c may also be run later to convert
1590 for patches (qinit -c may also be run later to convert
1594 an unversioned patch repository into a versioned one).
1591 an unversioned patch repository into a versioned one).
1595 You can use qcommit to commit changes to this queue repository."""
1592 You can use qcommit to commit changes to this queue repository."""
1596 q = repo.mq
1593 q = repo.mq
1597 r = q.init(repo, create=opts['create_repo'])
1594 r = q.init(repo, create=opts['create_repo'])
1598 q.save_dirty()
1595 q.save_dirty()
1599 if r:
1596 if r:
1600 if not os.path.exists(r.wjoin('.hgignore')):
1597 if not os.path.exists(r.wjoin('.hgignore')):
1601 fp = r.wopener('.hgignore', 'w')
1598 fp = r.wopener('.hgignore', 'w')
1602 fp.write('^\\.hg\n')
1599 fp.write('^\\.hg\n')
1603 fp.write('^\\.mq\n')
1600 fp.write('^\\.mq\n')
1604 fp.write('syntax: glob\n')
1601 fp.write('syntax: glob\n')
1605 fp.write('status\n')
1602 fp.write('status\n')
1606 fp.write('guards\n')
1603 fp.write('guards\n')
1607 fp.close()
1604 fp.close()
1608 if not os.path.exists(r.wjoin('series')):
1605 if not os.path.exists(r.wjoin('series')):
1609 r.wopener('series', 'w').close()
1606 r.wopener('series', 'w').close()
1610 r.add(['.hgignore', 'series'])
1607 r.add(['.hgignore', 'series'])
1611 commands.add(ui, r)
1608 commands.add(ui, r)
1612 return 0
1609 return 0
1613
1610
1614 def clone(ui, source, dest=None, **opts):
1611 def clone(ui, source, dest=None, **opts):
1615 '''clone main and patch repository at same time
1612 '''clone main and patch repository at same time
1616
1613
1617 If source is local, destination will have no patches applied. If
1614 If source is local, destination will have no patches applied. If
1618 source is remote, this command can not check if patches are
1615 source is remote, this command can not check if patches are
1619 applied in source, so cannot guarantee that patches are not
1616 applied in source, so cannot guarantee that patches are not
1620 applied in destination. If you clone remote repository, be sure
1617 applied in destination. If you clone remote repository, be sure
1621 before that it has no patches applied.
1618 before that it has no patches applied.
1622
1619
1623 Source patch repository is looked for in <src>/.hg/patches by
1620 Source patch repository is looked for in <src>/.hg/patches by
1624 default. Use -p <url> to change.
1621 default. Use -p <url> to change.
1625
1622
1626 The patch directory must be a nested mercurial repository, as
1623 The patch directory must be a nested mercurial repository, as
1627 would be created by qinit -c.
1624 would be created by qinit -c.
1628 '''
1625 '''
1629 def patchdir(repo):
1626 def patchdir(repo):
1630 url = repo.url()
1627 url = repo.url()
1631 if url.endswith('/'):
1628 if url.endswith('/'):
1632 url = url[:-1]
1629 url = url[:-1]
1633 return url + '/.hg/patches'
1630 return url + '/.hg/patches'
1634 cmdutil.setremoteconfig(ui, opts)
1631 cmdutil.setremoteconfig(ui, opts)
1635 if dest is None:
1632 if dest is None:
1636 dest = hg.defaultdest(source)
1633 dest = hg.defaultdest(source)
1637 sr = hg.repository(ui, ui.expandpath(source))
1634 sr = hg.repository(ui, ui.expandpath(source))
1638 patchespath = opts['patches'] or patchdir(sr)
1635 patchespath = opts['patches'] or patchdir(sr)
1639 try:
1636 try:
1640 pr = hg.repository(ui, patchespath)
1637 pr = hg.repository(ui, patchespath)
1641 except RepoError:
1638 except RepoError:
1642 raise util.Abort(_('versioned patch repository not found'
1639 raise util.Abort(_('versioned patch repository not found'
1643 ' (see qinit -c)'))
1640 ' (see qinit -c)'))
1644 qbase, destrev = None, None
1641 qbase, destrev = None, None
1645 if sr.local():
1642 if sr.local():
1646 if sr.mq.applied:
1643 if sr.mq.applied:
1647 qbase = revlog.bin(sr.mq.applied[0].rev)
1644 qbase = revlog.bin(sr.mq.applied[0].rev)
1648 if not hg.islocal(dest):
1645 if not hg.islocal(dest):
1649 heads = dict.fromkeys(sr.heads())
1646 heads = dict.fromkeys(sr.heads())
1650 for h in sr.heads(qbase):
1647 for h in sr.heads(qbase):
1651 del heads[h]
1648 del heads[h]
1652 destrev = heads.keys()
1649 destrev = heads.keys()
1653 destrev.append(sr.changelog.parents(qbase)[0])
1650 destrev.append(sr.changelog.parents(qbase)[0])
1654 elif sr.capable('lookup'):
1651 elif sr.capable('lookup'):
1655 try:
1652 try:
1656 qbase = sr.lookup('qbase')
1653 qbase = sr.lookup('qbase')
1657 except RepoError:
1654 except RepoError:
1658 pass
1655 pass
1659 ui.note(_('cloning main repo\n'))
1656 ui.note(_('cloning main repo\n'))
1660 sr, dr = hg.clone(ui, sr.url(), dest,
1657 sr, dr = hg.clone(ui, sr.url(), dest,
1661 pull=opts['pull'],
1658 pull=opts['pull'],
1662 rev=destrev,
1659 rev=destrev,
1663 update=False,
1660 update=False,
1664 stream=opts['uncompressed'])
1661 stream=opts['uncompressed'])
1665 ui.note(_('cloning patch repo\n'))
1662 ui.note(_('cloning patch repo\n'))
1666 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1663 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1667 pull=opts['pull'], update=not opts['noupdate'],
1664 pull=opts['pull'], update=not opts['noupdate'],
1668 stream=opts['uncompressed'])
1665 stream=opts['uncompressed'])
1669 if dr.local():
1666 if dr.local():
1670 if qbase:
1667 if qbase:
1671 ui.note(_('stripping applied patches from destination repo\n'))
1668 ui.note(_('stripping applied patches from destination repo\n'))
1672 dr.mq.strip(dr, qbase, update=False, backup=None)
1669 dr.mq.strip(dr, qbase, update=False, backup=None)
1673 if not opts['noupdate']:
1670 if not opts['noupdate']:
1674 ui.note(_('updating destination repo\n'))
1671 ui.note(_('updating destination repo\n'))
1675 hg.update(dr, dr.changelog.tip())
1672 hg.update(dr, dr.changelog.tip())
1676
1673
1677 def commit(ui, repo, *pats, **opts):
1674 def commit(ui, repo, *pats, **opts):
1678 """commit changes in the queue repository"""
1675 """commit changes in the queue repository"""
1679 q = repo.mq
1676 q = repo.mq
1680 r = q.qrepo()
1677 r = q.qrepo()
1681 if not r: raise util.Abort('no queue repository')
1678 if not r: raise util.Abort('no queue repository')
1682 commands.commit(r.ui, r, *pats, **opts)
1679 commands.commit(r.ui, r, *pats, **opts)
1683
1680
1684 def series(ui, repo, **opts):
1681 def series(ui, repo, **opts):
1685 """print the entire series file"""
1682 """print the entire series file"""
1686 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1683 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1687 return 0
1684 return 0
1688
1685
1689 def top(ui, repo, **opts):
1686 def top(ui, repo, **opts):
1690 """print the name of the current patch"""
1687 """print the name of the current patch"""
1691 q = repo.mq
1688 q = repo.mq
1692 t = q.applied and q.series_end(True) or 0
1689 t = q.applied and q.series_end(True) or 0
1693 if t:
1690 if t:
1694 return q.qseries(repo, start=t-1, length=1, status='A',
1691 return q.qseries(repo, start=t-1, length=1, status='A',
1695 summary=opts.get('summary'))
1692 summary=opts.get('summary'))
1696 else:
1693 else:
1697 ui.write("No patches applied\n")
1694 ui.write("No patches applied\n")
1698 return 1
1695 return 1
1699
1696
1700 def next(ui, repo, **opts):
1697 def next(ui, repo, **opts):
1701 """print the name of the next patch"""
1698 """print the name of the next patch"""
1702 q = repo.mq
1699 q = repo.mq
1703 end = q.series_end()
1700 end = q.series_end()
1704 if end == len(q.series):
1701 if end == len(q.series):
1705 ui.write("All patches applied\n")
1702 ui.write("All patches applied\n")
1706 return 1
1703 return 1
1707 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1704 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1708
1705
1709 def prev(ui, repo, **opts):
1706 def prev(ui, repo, **opts):
1710 """print the name of the previous patch"""
1707 """print the name of the previous patch"""
1711 q = repo.mq
1708 q = repo.mq
1712 l = len(q.applied)
1709 l = len(q.applied)
1713 if l == 1:
1710 if l == 1:
1714 ui.write("Only one patch applied\n")
1711 ui.write("Only one patch applied\n")
1715 return 1
1712 return 1
1716 if not l:
1713 if not l:
1717 ui.write("No patches applied\n")
1714 ui.write("No patches applied\n")
1718 return 1
1715 return 1
1719 return q.qseries(repo, start=l-2, length=1, status='A',
1716 return q.qseries(repo, start=l-2, length=1, status='A',
1720 summary=opts.get('summary'))
1717 summary=opts.get('summary'))
1721
1718
1722 def setupheaderopts(ui, opts):
1719 def setupheaderopts(ui, opts):
1723 def do(opt,val):
1720 def do(opt,val):
1724 if not opts[opt] and opts['current' + opt]:
1721 if not opts[opt] and opts['current' + opt]:
1725 opts[opt] = val
1722 opts[opt] = val
1726 do('user', ui.username())
1723 do('user', ui.username())
1727 do('date', "%d %d" % util.makedate())
1724 do('date', "%d %d" % util.makedate())
1728
1725
1729 def new(ui, repo, patch, *args, **opts):
1726 def new(ui, repo, patch, *args, **opts):
1730 """create a new patch
1727 """create a new patch
1731
1728
1732 qnew creates a new patch on top of the currently-applied patch
1729 qnew creates a new patch on top of the currently-applied patch
1733 (if any). It will refuse to run if there are any outstanding
1730 (if any). It will refuse to run if there are any outstanding
1734 changes unless -f is specified, in which case the patch will
1731 changes unless -f is specified, in which case the patch will
1735 be initialised with them. You may also use -I, -X, and/or a list of
1732 be initialised with them. You may also use -I, -X, and/or a list of
1736 files after the patch name to add only changes to matching files
1733 files after the patch name to add only changes to matching files
1737 to the new patch, leaving the rest as uncommitted modifications.
1734 to the new patch, leaving the rest as uncommitted modifications.
1738
1735
1739 -e, -m or -l set the patch header as well as the commit message.
1736 -e, -m or -l set the patch header as well as the commit message.
1740 If none is specified, the patch header is empty and the
1737 If none is specified, the patch header is empty and the
1741 commit message is '[mq]: PATCH'"""
1738 commit message is '[mq]: PATCH'"""
1742 q = repo.mq
1739 q = repo.mq
1743 message = cmdutil.logmessage(opts)
1740 message = cmdutil.logmessage(opts)
1744 if opts['edit']:
1741 if opts['edit']:
1745 message = ui.edit(message, ui.username())
1742 message = ui.edit(message, ui.username())
1746 opts['msg'] = message
1743 opts['msg'] = message
1747 setupheaderopts(ui, opts)
1744 setupheaderopts(ui, opts)
1748 q.new(repo, patch, *args, **opts)
1745 q.new(repo, patch, *args, **opts)
1749 q.save_dirty()
1746 q.save_dirty()
1750 return 0
1747 return 0
1751
1748
1752 def refresh(ui, repo, *pats, **opts):
1749 def refresh(ui, repo, *pats, **opts):
1753 """update the current patch
1750 """update the current patch
1754
1751
1755 If any file patterns are provided, the refreshed patch will contain only
1752 If any file patterns are provided, the refreshed patch will contain only
1756 the modifications that match those patterns; the remaining modifications
1753 the modifications that match those patterns; the remaining modifications
1757 will remain in the working directory.
1754 will remain in the working directory.
1758
1755
1759 hg add/remove/copy/rename work as usual, though you might want to use
1756 hg add/remove/copy/rename work as usual, though you might want to use
1760 git-style patches (--git or [diff] git=1) to track copies and renames.
1757 git-style patches (--git or [diff] git=1) to track copies and renames.
1761 """
1758 """
1762 q = repo.mq
1759 q = repo.mq
1763 message = cmdutil.logmessage(opts)
1760 message = cmdutil.logmessage(opts)
1764 if opts['edit']:
1761 if opts['edit']:
1765 if not q.applied:
1762 if not q.applied:
1766 ui.write(_("No patches applied\n"))
1763 ui.write(_("No patches applied\n"))
1767 return 1
1764 return 1
1768 if message:
1765 if message:
1769 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1766 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1770 patch = q.applied[-1].name
1767 patch = q.applied[-1].name
1771 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1768 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1772 message = ui.edit('\n'.join(message), user or ui.username())
1769 message = ui.edit('\n'.join(message), user or ui.username())
1773 setupheaderopts(ui, opts)
1770 setupheaderopts(ui, opts)
1774 ret = q.refresh(repo, pats, msg=message, **opts)
1771 ret = q.refresh(repo, pats, msg=message, **opts)
1775 q.save_dirty()
1772 q.save_dirty()
1776 return ret
1773 return ret
1777
1774
1778 def diff(ui, repo, *pats, **opts):
1775 def diff(ui, repo, *pats, **opts):
1779 """diff of the current patch and subsequent modifications
1776 """diff of the current patch and subsequent modifications
1780
1777
1781 Shows a diff which includes the current patch as well as any changes which
1778 Shows a diff which includes the current patch as well as any changes which
1782 have been made in the working directory since the last refresh (thus
1779 have been made in the working directory since the last refresh (thus
1783 showing what the current patch would become after a qrefresh).
1780 showing what the current patch would become after a qrefresh).
1784
1781
1785 Use 'hg diff' if you only want to see the changes made since the last
1782 Use 'hg diff' if you only want to see the changes made since the last
1786 qrefresh, or 'hg export qtip' if you want to see changes made by the
1783 qrefresh, or 'hg export qtip' if you want to see changes made by the
1787 current patch without including changes made since the qrefresh.
1784 current patch without including changes made since the qrefresh.
1788 """
1785 """
1789 repo.mq.diff(repo, pats, opts)
1786 repo.mq.diff(repo, pats, opts)
1790 return 0
1787 return 0
1791
1788
1792 def fold(ui, repo, *files, **opts):
1789 def fold(ui, repo, *files, **opts):
1793 """fold the named patches into the current patch
1790 """fold the named patches into the current patch
1794
1791
1795 Patches must not yet be applied. Each patch will be successively
1792 Patches must not yet be applied. Each patch will be successively
1796 applied to the current patch in the order given. If all the
1793 applied to the current patch in the order given. If all the
1797 patches apply successfully, the current patch will be refreshed
1794 patches apply successfully, the current patch will be refreshed
1798 with the new cumulative patch, and the folded patches will
1795 with the new cumulative patch, and the folded patches will
1799 be deleted. With -k/--keep, the folded patch files will not
1796 be deleted. With -k/--keep, the folded patch files will not
1800 be removed afterwards.
1797 be removed afterwards.
1801
1798
1802 The header for each folded patch will be concatenated with
1799 The header for each folded patch will be concatenated with
1803 the current patch header, separated by a line of '* * *'."""
1800 the current patch header, separated by a line of '* * *'."""
1804
1801
1805 q = repo.mq
1802 q = repo.mq
1806
1803
1807 if not files:
1804 if not files:
1808 raise util.Abort(_('qfold requires at least one patch name'))
1805 raise util.Abort(_('qfold requires at least one patch name'))
1809 if not q.check_toppatch(repo):
1806 if not q.check_toppatch(repo):
1810 raise util.Abort(_('No patches applied'))
1807 raise util.Abort(_('No patches applied'))
1811
1808
1812 message = cmdutil.logmessage(opts)
1809 message = cmdutil.logmessage(opts)
1813 if opts['edit']:
1810 if opts['edit']:
1814 if message:
1811 if message:
1815 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1812 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1816
1813
1817 parent = q.lookup('qtip')
1814 parent = q.lookup('qtip')
1818 patches = []
1815 patches = []
1819 messages = []
1816 messages = []
1820 for f in files:
1817 for f in files:
1821 p = q.lookup(f)
1818 p = q.lookup(f)
1822 if p in patches or p == parent:
1819 if p in patches or p == parent:
1823 ui.warn(_('Skipping already folded patch %s') % p)
1820 ui.warn(_('Skipping already folded patch %s') % p)
1824 if q.isapplied(p):
1821 if q.isapplied(p):
1825 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1822 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1826 patches.append(p)
1823 patches.append(p)
1827
1824
1828 for p in patches:
1825 for p in patches:
1829 if not message:
1826 if not message:
1830 messages.append(q.readheaders(p)[0])
1827 messages.append(q.readheaders(p)[0])
1831 pf = q.join(p)
1828 pf = q.join(p)
1832 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1829 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1833 if not patchsuccess:
1830 if not patchsuccess:
1834 raise util.Abort(_('Error folding patch %s') % p)
1831 raise util.Abort(_('Error folding patch %s') % p)
1835 patch.updatedir(ui, repo, files)
1832 patch.updatedir(ui, repo, files)
1836
1833
1837 if not message:
1834 if not message:
1838 message, comments, user = q.readheaders(parent)[0:3]
1835 message, comments, user = q.readheaders(parent)[0:3]
1839 for msg in messages:
1836 for msg in messages:
1840 message.append('* * *')
1837 message.append('* * *')
1841 message.extend(msg)
1838 message.extend(msg)
1842 message = '\n'.join(message)
1839 message = '\n'.join(message)
1843
1840
1844 if opts['edit']:
1841 if opts['edit']:
1845 message = ui.edit(message, user or ui.username())
1842 message = ui.edit(message, user or ui.username())
1846
1843
1847 q.refresh(repo, msg=message)
1844 q.refresh(repo, msg=message)
1848 q.delete(repo, patches, opts)
1845 q.delete(repo, patches, opts)
1849 q.save_dirty()
1846 q.save_dirty()
1850
1847
1851 def goto(ui, repo, patch, **opts):
1848 def goto(ui, repo, patch, **opts):
1852 '''push or pop patches until named patch is at top of stack'''
1849 '''push or pop patches until named patch is at top of stack'''
1853 q = repo.mq
1850 q = repo.mq
1854 patch = q.lookup(patch)
1851 patch = q.lookup(patch)
1855 if q.isapplied(patch):
1852 if q.isapplied(patch):
1856 ret = q.pop(repo, patch, force=opts['force'])
1853 ret = q.pop(repo, patch, force=opts['force'])
1857 else:
1854 else:
1858 ret = q.push(repo, patch, force=opts['force'])
1855 ret = q.push(repo, patch, force=opts['force'])
1859 q.save_dirty()
1856 q.save_dirty()
1860 return ret
1857 return ret
1861
1858
1862 def guard(ui, repo, *args, **opts):
1859 def guard(ui, repo, *args, **opts):
1863 '''set or print guards for a patch
1860 '''set or print guards for a patch
1864
1861
1865 Guards control whether a patch can be pushed. A patch with no
1862 Guards control whether a patch can be pushed. A patch with no
1866 guards is always pushed. A patch with a positive guard ("+foo") is
1863 guards is always pushed. A patch with a positive guard ("+foo") is
1867 pushed only if the qselect command has activated it. A patch with
1864 pushed only if the qselect command has activated it. A patch with
1868 a negative guard ("-foo") is never pushed if the qselect command
1865 a negative guard ("-foo") is never pushed if the qselect command
1869 has activated it.
1866 has activated it.
1870
1867
1871 With no arguments, print the currently active guards.
1868 With no arguments, print the currently active guards.
1872 With arguments, set guards for the named patch.
1869 With arguments, set guards for the named patch.
1873
1870
1874 To set a negative guard "-foo" on topmost patch ("--" is needed so
1871 To set a negative guard "-foo" on topmost patch ("--" is needed so
1875 hg will not interpret "-foo" as an option):
1872 hg will not interpret "-foo" as an option):
1876 hg qguard -- -foo
1873 hg qguard -- -foo
1877
1874
1878 To set guards on another patch:
1875 To set guards on another patch:
1879 hg qguard other.patch +2.6.17 -stable
1876 hg qguard other.patch +2.6.17 -stable
1880 '''
1877 '''
1881 def status(idx):
1878 def status(idx):
1882 guards = q.series_guards[idx] or ['unguarded']
1879 guards = q.series_guards[idx] or ['unguarded']
1883 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1880 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1884 q = repo.mq
1881 q = repo.mq
1885 patch = None
1882 patch = None
1886 args = list(args)
1883 args = list(args)
1887 if opts['list']:
1884 if opts['list']:
1888 if args or opts['none']:
1885 if args or opts['none']:
1889 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1886 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1890 for i in xrange(len(q.series)):
1887 for i in xrange(len(q.series)):
1891 status(i)
1888 status(i)
1892 return
1889 return
1893 if not args or args[0][0:1] in '-+':
1890 if not args or args[0][0:1] in '-+':
1894 if not q.applied:
1891 if not q.applied:
1895 raise util.Abort(_('no patches applied'))
1892 raise util.Abort(_('no patches applied'))
1896 patch = q.applied[-1].name
1893 patch = q.applied[-1].name
1897 if patch is None and args[0][0:1] not in '-+':
1894 if patch is None and args[0][0:1] not in '-+':
1898 patch = args.pop(0)
1895 patch = args.pop(0)
1899 if patch is None:
1896 if patch is None:
1900 raise util.Abort(_('no patch to work with'))
1897 raise util.Abort(_('no patch to work with'))
1901 if args or opts['none']:
1898 if args or opts['none']:
1902 idx = q.find_series(patch)
1899 idx = q.find_series(patch)
1903 if idx is None:
1900 if idx is None:
1904 raise util.Abort(_('no patch named %s') % patch)
1901 raise util.Abort(_('no patch named %s') % patch)
1905 q.set_guards(idx, args)
1902 q.set_guards(idx, args)
1906 q.save_dirty()
1903 q.save_dirty()
1907 else:
1904 else:
1908 status(q.series.index(q.lookup(patch)))
1905 status(q.series.index(q.lookup(patch)))
1909
1906
1910 def header(ui, repo, patch=None):
1907 def header(ui, repo, patch=None):
1911 """Print the header of the topmost or specified patch"""
1908 """Print the header of the topmost or specified patch"""
1912 q = repo.mq
1909 q = repo.mq
1913
1910
1914 if patch:
1911 if patch:
1915 patch = q.lookup(patch)
1912 patch = q.lookup(patch)
1916 else:
1913 else:
1917 if not q.applied:
1914 if not q.applied:
1918 ui.write('No patches applied\n')
1915 ui.write('No patches applied\n')
1919 return 1
1916 return 1
1920 patch = q.lookup('qtip')
1917 patch = q.lookup('qtip')
1921 message = repo.mq.readheaders(patch)[0]
1918 message = repo.mq.readheaders(patch)[0]
1922
1919
1923 ui.write('\n'.join(message) + '\n')
1920 ui.write('\n'.join(message) + '\n')
1924
1921
1925 def lastsavename(path):
1922 def lastsavename(path):
1926 (directory, base) = os.path.split(path)
1923 (directory, base) = os.path.split(path)
1927 names = os.listdir(directory)
1924 names = os.listdir(directory)
1928 namere = re.compile("%s.([0-9]+)" % base)
1925 namere = re.compile("%s.([0-9]+)" % base)
1929 maxindex = None
1926 maxindex = None
1930 maxname = None
1927 maxname = None
1931 for f in names:
1928 for f in names:
1932 m = namere.match(f)
1929 m = namere.match(f)
1933 if m:
1930 if m:
1934 index = int(m.group(1))
1931 index = int(m.group(1))
1935 if maxindex == None or index > maxindex:
1932 if maxindex == None or index > maxindex:
1936 maxindex = index
1933 maxindex = index
1937 maxname = f
1934 maxname = f
1938 if maxname:
1935 if maxname:
1939 return (os.path.join(directory, maxname), maxindex)
1936 return (os.path.join(directory, maxname), maxindex)
1940 return (None, None)
1937 return (None, None)
1941
1938
1942 def savename(path):
1939 def savename(path):
1943 (last, index) = lastsavename(path)
1940 (last, index) = lastsavename(path)
1944 if last is None:
1941 if last is None:
1945 index = 0
1942 index = 0
1946 newpath = path + ".%d" % (index + 1)
1943 newpath = path + ".%d" % (index + 1)
1947 return newpath
1944 return newpath
1948
1945
1949 def push(ui, repo, patch=None, **opts):
1946 def push(ui, repo, patch=None, **opts):
1950 """push the next patch onto the stack
1947 """push the next patch onto the stack
1951
1948
1952 When --force is applied, all local changes in patched files will be lost.
1949 When --force is applied, all local changes in patched files will be lost.
1953 """
1950 """
1954 q = repo.mq
1951 q = repo.mq
1955 mergeq = None
1952 mergeq = None
1956
1953
1957 if opts['all']:
1954 if opts['all']:
1958 if not q.series:
1955 if not q.series:
1959 ui.warn(_('no patches in series\n'))
1956 ui.warn(_('no patches in series\n'))
1960 return 0
1957 return 0
1961 patch = q.series[-1]
1958 patch = q.series[-1]
1962 if opts['merge']:
1959 if opts['merge']:
1963 if opts['name']:
1960 if opts['name']:
1964 newpath = repo.join(opts['name'])
1961 newpath = repo.join(opts['name'])
1965 else:
1962 else:
1966 newpath, i = lastsavename(q.path)
1963 newpath, i = lastsavename(q.path)
1967 if not newpath:
1964 if not newpath:
1968 ui.warn("no saved queues found, please use -n\n")
1965 ui.warn("no saved queues found, please use -n\n")
1969 return 1
1966 return 1
1970 mergeq = queue(ui, repo.join(""), newpath)
1967 mergeq = queue(ui, repo.join(""), newpath)
1971 ui.warn("merging with queue at: %s\n" % mergeq.path)
1968 ui.warn("merging with queue at: %s\n" % mergeq.path)
1972 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1969 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1973 mergeq=mergeq)
1970 mergeq=mergeq)
1974 return ret
1971 return ret
1975
1972
1976 def pop(ui, repo, patch=None, **opts):
1973 def pop(ui, repo, patch=None, **opts):
1977 """pop the current patch off the stack
1974 """pop the current patch off the stack
1978
1975
1979 By default, pops off the top of the patch stack. If given a patch name,
1976 By default, pops off the top of the patch stack. If given a patch name,
1980 keeps popping off patches until the named patch is at the top of the stack.
1977 keeps popping off patches until the named patch is at the top of the stack.
1981 """
1978 """
1982 localupdate = True
1979 localupdate = True
1983 if opts['name']:
1980 if opts['name']:
1984 q = queue(ui, repo.join(""), repo.join(opts['name']))
1981 q = queue(ui, repo.join(""), repo.join(opts['name']))
1985 ui.warn('using patch queue: %s\n' % q.path)
1982 ui.warn('using patch queue: %s\n' % q.path)
1986 localupdate = False
1983 localupdate = False
1987 else:
1984 else:
1988 q = repo.mq
1985 q = repo.mq
1989 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1986 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1990 all=opts['all'])
1987 all=opts['all'])
1991 q.save_dirty()
1988 q.save_dirty()
1992 return ret
1989 return ret
1993
1990
1994 def rename(ui, repo, patch, name=None, **opts):
1991 def rename(ui, repo, patch, name=None, **opts):
1995 """rename a patch
1992 """rename a patch
1996
1993
1997 With one argument, renames the current patch to PATCH1.
1994 With one argument, renames the current patch to PATCH1.
1998 With two arguments, renames PATCH1 to PATCH2."""
1995 With two arguments, renames PATCH1 to PATCH2."""
1999
1996
2000 q = repo.mq
1997 q = repo.mq
2001
1998
2002 if not name:
1999 if not name:
2003 name = patch
2000 name = patch
2004 patch = None
2001 patch = None
2005
2002
2006 if patch:
2003 if patch:
2007 patch = q.lookup(patch)
2004 patch = q.lookup(patch)
2008 else:
2005 else:
2009 if not q.applied:
2006 if not q.applied:
2010 ui.write(_('No patches applied\n'))
2007 ui.write(_('No patches applied\n'))
2011 return
2008 return
2012 patch = q.lookup('qtip')
2009 patch = q.lookup('qtip')
2013 absdest = q.join(name)
2010 absdest = q.join(name)
2014 if os.path.isdir(absdest):
2011 if os.path.isdir(absdest):
2015 name = normname(os.path.join(name, os.path.basename(patch)))
2012 name = normname(os.path.join(name, os.path.basename(patch)))
2016 absdest = q.join(name)
2013 absdest = q.join(name)
2017 if os.path.exists(absdest):
2014 if os.path.exists(absdest):
2018 raise util.Abort(_('%s already exists') % absdest)
2015 raise util.Abort(_('%s already exists') % absdest)
2019
2016
2020 if name in q.series:
2017 if name in q.series:
2021 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2018 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2022
2019
2023 if ui.verbose:
2020 if ui.verbose:
2024 ui.write('Renaming %s to %s\n' % (patch, name))
2021 ui.write('Renaming %s to %s\n' % (patch, name))
2025 i = q.find_series(patch)
2022 i = q.find_series(patch)
2026 guards = q.guard_re.findall(q.full_series[i])
2023 guards = q.guard_re.findall(q.full_series[i])
2027 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2024 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2028 q.parse_series()
2025 q.parse_series()
2029 q.series_dirty = 1
2026 q.series_dirty = 1
2030
2027
2031 info = q.isapplied(patch)
2028 info = q.isapplied(patch)
2032 if info:
2029 if info:
2033 q.applied[info[0]] = statusentry(info[1], name)
2030 q.applied[info[0]] = statusentry(info[1], name)
2034 q.applied_dirty = 1
2031 q.applied_dirty = 1
2035
2032
2036 util.rename(q.join(patch), absdest)
2033 util.rename(q.join(patch), absdest)
2037 r = q.qrepo()
2034 r = q.qrepo()
2038 if r:
2035 if r:
2039 wlock = r.wlock()
2036 wlock = r.wlock()
2040 try:
2037 try:
2041 if r.dirstate[patch] == 'a':
2038 if r.dirstate[patch] == 'a':
2042 r.dirstate.forget(patch)
2039 r.dirstate.forget(patch)
2043 r.dirstate.add(name)
2040 r.dirstate.add(name)
2044 else:
2041 else:
2045 if r.dirstate[name] == 'r':
2042 if r.dirstate[name] == 'r':
2046 r.undelete([name])
2043 r.undelete([name])
2047 r.copy(patch, name)
2044 r.copy(patch, name)
2048 r.remove([patch], False)
2045 r.remove([patch], False)
2049 finally:
2046 finally:
2050 del wlock
2047 del wlock
2051
2048
2052 q.save_dirty()
2049 q.save_dirty()
2053
2050
2054 def restore(ui, repo, rev, **opts):
2051 def restore(ui, repo, rev, **opts):
2055 """restore the queue state saved by a rev"""
2052 """restore the queue state saved by a rev"""
2056 rev = repo.lookup(rev)
2053 rev = repo.lookup(rev)
2057 q = repo.mq
2054 q = repo.mq
2058 q.restore(repo, rev, delete=opts['delete'],
2055 q.restore(repo, rev, delete=opts['delete'],
2059 qupdate=opts['update'])
2056 qupdate=opts['update'])
2060 q.save_dirty()
2057 q.save_dirty()
2061 return 0
2058 return 0
2062
2059
2063 def save(ui, repo, **opts):
2060 def save(ui, repo, **opts):
2064 """save current queue state"""
2061 """save current queue state"""
2065 q = repo.mq
2062 q = repo.mq
2066 message = cmdutil.logmessage(opts)
2063 message = cmdutil.logmessage(opts)
2067 ret = q.save(repo, msg=message)
2064 ret = q.save(repo, msg=message)
2068 if ret:
2065 if ret:
2069 return ret
2066 return ret
2070 q.save_dirty()
2067 q.save_dirty()
2071 if opts['copy']:
2068 if opts['copy']:
2072 path = q.path
2069 path = q.path
2073 if opts['name']:
2070 if opts['name']:
2074 newpath = os.path.join(q.basepath, opts['name'])
2071 newpath = os.path.join(q.basepath, opts['name'])
2075 if os.path.exists(newpath):
2072 if os.path.exists(newpath):
2076 if not os.path.isdir(newpath):
2073 if not os.path.isdir(newpath):
2077 raise util.Abort(_('destination %s exists and is not '
2074 raise util.Abort(_('destination %s exists and is not '
2078 'a directory') % newpath)
2075 'a directory') % newpath)
2079 if not opts['force']:
2076 if not opts['force']:
2080 raise util.Abort(_('destination %s exists, '
2077 raise util.Abort(_('destination %s exists, '
2081 'use -f to force') % newpath)
2078 'use -f to force') % newpath)
2082 else:
2079 else:
2083 newpath = savename(path)
2080 newpath = savename(path)
2084 ui.warn("copy %s to %s\n" % (path, newpath))
2081 ui.warn("copy %s to %s\n" % (path, newpath))
2085 util.copyfiles(path, newpath)
2082 util.copyfiles(path, newpath)
2086 if opts['empty']:
2083 if opts['empty']:
2087 try:
2084 try:
2088 os.unlink(q.join(q.status_path))
2085 os.unlink(q.join(q.status_path))
2089 except:
2086 except:
2090 pass
2087 pass
2091 return 0
2088 return 0
2092
2089
2093 def strip(ui, repo, rev, **opts):
2090 def strip(ui, repo, rev, **opts):
2094 """strip a revision and all its descendants from the repository
2091 """strip a revision and all its descendants from the repository
2095
2092
2096 If one of the working dir's parent revisions is stripped, the working
2093 If one of the working dir's parent revisions is stripped, the working
2097 directory will be updated to the parent of the stripped revision.
2094 directory will be updated to the parent of the stripped revision.
2098 """
2095 """
2099 backup = 'all'
2096 backup = 'all'
2100 if opts['backup']:
2097 if opts['backup']:
2101 backup = 'strip'
2098 backup = 'strip'
2102 elif opts['nobackup']:
2099 elif opts['nobackup']:
2103 backup = 'none'
2100 backup = 'none'
2104
2101
2105 rev = repo.lookup(rev)
2102 rev = repo.lookup(rev)
2106 p = repo.dirstate.parents()
2103 p = repo.dirstate.parents()
2107 cl = repo.changelog
2104 cl = repo.changelog
2108 update = True
2105 update = True
2109 if p[0] == revlog.nullid:
2106 if p[0] == revlog.nullid:
2110 update = False
2107 update = False
2111 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2108 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2112 update = False
2109 update = False
2113 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2110 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2114 update = False
2111 update = False
2115
2112
2116 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2113 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2117 return 0
2114 return 0
2118
2115
2119 def select(ui, repo, *args, **opts):
2116 def select(ui, repo, *args, **opts):
2120 '''set or print guarded patches to push
2117 '''set or print guarded patches to push
2121
2118
2122 Use the qguard command to set or print guards on patch, then use
2119 Use the qguard command to set or print guards on patch, then use
2123 qselect to tell mq which guards to use. A patch will be pushed if it
2120 qselect to tell mq which guards to use. A patch will be pushed if it
2124 has no guards or any positive guards match the currently selected guard,
2121 has no guards or any positive guards match the currently selected guard,
2125 but will not be pushed if any negative guards match the current guard.
2122 but will not be pushed if any negative guards match the current guard.
2126 For example:
2123 For example:
2127
2124
2128 qguard foo.patch -stable (negative guard)
2125 qguard foo.patch -stable (negative guard)
2129 qguard bar.patch +stable (positive guard)
2126 qguard bar.patch +stable (positive guard)
2130 qselect stable
2127 qselect stable
2131
2128
2132 This activates the "stable" guard. mq will skip foo.patch (because
2129 This activates the "stable" guard. mq will skip foo.patch (because
2133 it has a negative match) but push bar.patch (because it
2130 it has a negative match) but push bar.patch (because it
2134 has a positive match).
2131 has a positive match).
2135
2132
2136 With no arguments, prints the currently active guards.
2133 With no arguments, prints the currently active guards.
2137 With one argument, sets the active guard.
2134 With one argument, sets the active guard.
2138
2135
2139 Use -n/--none to deactivate guards (no other arguments needed).
2136 Use -n/--none to deactivate guards (no other arguments needed).
2140 When no guards are active, patches with positive guards are skipped
2137 When no guards are active, patches with positive guards are skipped
2141 and patches with negative guards are pushed.
2138 and patches with negative guards are pushed.
2142
2139
2143 qselect can change the guards on applied patches. It does not pop
2140 qselect can change the guards on applied patches. It does not pop
2144 guarded patches by default. Use --pop to pop back to the last applied
2141 guarded patches by default. Use --pop to pop back to the last applied
2145 patch that is not guarded. Use --reapply (which implies --pop) to push
2142 patch that is not guarded. Use --reapply (which implies --pop) to push
2146 back to the current patch afterwards, but skip guarded patches.
2143 back to the current patch afterwards, but skip guarded patches.
2147
2144
2148 Use -s/--series to print a list of all guards in the series file (no
2145 Use -s/--series to print a list of all guards in the series file (no
2149 other arguments needed). Use -v for more information.'''
2146 other arguments needed). Use -v for more information.'''
2150
2147
2151 q = repo.mq
2148 q = repo.mq
2152 guards = q.active()
2149 guards = q.active()
2153 if args or opts['none']:
2150 if args or opts['none']:
2154 old_unapplied = q.unapplied(repo)
2151 old_unapplied = q.unapplied(repo)
2155 old_guarded = [i for i in xrange(len(q.applied)) if
2152 old_guarded = [i for i in xrange(len(q.applied)) if
2156 not q.pushable(i)[0]]
2153 not q.pushable(i)[0]]
2157 q.set_active(args)
2154 q.set_active(args)
2158 q.save_dirty()
2155 q.save_dirty()
2159 if not args:
2156 if not args:
2160 ui.status(_('guards deactivated\n'))
2157 ui.status(_('guards deactivated\n'))
2161 if not opts['pop'] and not opts['reapply']:
2158 if not opts['pop'] and not opts['reapply']:
2162 unapplied = q.unapplied(repo)
2159 unapplied = q.unapplied(repo)
2163 guarded = [i for i in xrange(len(q.applied))
2160 guarded = [i for i in xrange(len(q.applied))
2164 if not q.pushable(i)[0]]
2161 if not q.pushable(i)[0]]
2165 if len(unapplied) != len(old_unapplied):
2162 if len(unapplied) != len(old_unapplied):
2166 ui.status(_('number of unguarded, unapplied patches has '
2163 ui.status(_('number of unguarded, unapplied patches has '
2167 'changed from %d to %d\n') %
2164 'changed from %d to %d\n') %
2168 (len(old_unapplied), len(unapplied)))
2165 (len(old_unapplied), len(unapplied)))
2169 if len(guarded) != len(old_guarded):
2166 if len(guarded) != len(old_guarded):
2170 ui.status(_('number of guarded, applied patches has changed '
2167 ui.status(_('number of guarded, applied patches has changed '
2171 'from %d to %d\n') %
2168 'from %d to %d\n') %
2172 (len(old_guarded), len(guarded)))
2169 (len(old_guarded), len(guarded)))
2173 elif opts['series']:
2170 elif opts['series']:
2174 guards = {}
2171 guards = {}
2175 noguards = 0
2172 noguards = 0
2176 for gs in q.series_guards:
2173 for gs in q.series_guards:
2177 if not gs:
2174 if not gs:
2178 noguards += 1
2175 noguards += 1
2179 for g in gs:
2176 for g in gs:
2180 guards.setdefault(g, 0)
2177 guards.setdefault(g, 0)
2181 guards[g] += 1
2178 guards[g] += 1
2182 if ui.verbose:
2179 if ui.verbose:
2183 guards['NONE'] = noguards
2180 guards['NONE'] = noguards
2184 guards = guards.items()
2181 guards = guards.items()
2185 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2182 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2186 if guards:
2183 if guards:
2187 ui.note(_('guards in series file:\n'))
2184 ui.note(_('guards in series file:\n'))
2188 for guard, count in guards:
2185 for guard, count in guards:
2189 ui.note('%2d ' % count)
2186 ui.note('%2d ' % count)
2190 ui.write(guard, '\n')
2187 ui.write(guard, '\n')
2191 else:
2188 else:
2192 ui.note(_('no guards in series file\n'))
2189 ui.note(_('no guards in series file\n'))
2193 else:
2190 else:
2194 if guards:
2191 if guards:
2195 ui.note(_('active guards:\n'))
2192 ui.note(_('active guards:\n'))
2196 for g in guards:
2193 for g in guards:
2197 ui.write(g, '\n')
2194 ui.write(g, '\n')
2198 else:
2195 else:
2199 ui.write(_('no active guards\n'))
2196 ui.write(_('no active guards\n'))
2200 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2197 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2201 popped = False
2198 popped = False
2202 if opts['pop'] or opts['reapply']:
2199 if opts['pop'] or opts['reapply']:
2203 for i in xrange(len(q.applied)):
2200 for i in xrange(len(q.applied)):
2204 pushable, reason = q.pushable(i)
2201 pushable, reason = q.pushable(i)
2205 if not pushable:
2202 if not pushable:
2206 ui.status(_('popping guarded patches\n'))
2203 ui.status(_('popping guarded patches\n'))
2207 popped = True
2204 popped = True
2208 if i == 0:
2205 if i == 0:
2209 q.pop(repo, all=True)
2206 q.pop(repo, all=True)
2210 else:
2207 else:
2211 q.pop(repo, i-1)
2208 q.pop(repo, i-1)
2212 break
2209 break
2213 if popped:
2210 if popped:
2214 try:
2211 try:
2215 if reapply:
2212 if reapply:
2216 ui.status(_('reapplying unguarded patches\n'))
2213 ui.status(_('reapplying unguarded patches\n'))
2217 q.push(repo, reapply)
2214 q.push(repo, reapply)
2218 finally:
2215 finally:
2219 q.save_dirty()
2216 q.save_dirty()
2220
2217
2221 def finish(ui, repo, *revrange, **opts):
2218 def finish(ui, repo, *revrange, **opts):
2222 """move applied patches into repository history
2219 """move applied patches into repository history
2223
2220
2224 Finishes the specified revisions (corresponding to applied patches) by
2221 Finishes the specified revisions (corresponding to applied patches) by
2225 moving them out of mq control into regular repository history.
2222 moving them out of mq control into regular repository history.
2226
2223
2227 Accepts a revision range or the --all option. If --all is specified, all
2224 Accepts a revision range or the --all option. If --all is specified, all
2228 applied mq revisions are removed from mq control. Otherwise, the given
2225 applied mq revisions are removed from mq control. Otherwise, the given
2229 revisions must be at the base of the stack of applied patches.
2226 revisions must be at the base of the stack of applied patches.
2230
2227
2231 This can be especially useful if your changes have been applied to an
2228 This can be especially useful if your changes have been applied to an
2232 upstream repository, or if you are about to push your changes to upstream.
2229 upstream repository, or if you are about to push your changes to upstream.
2233 """
2230 """
2234 if not opts['applied'] and not revrange:
2231 if not opts['applied'] and not revrange:
2235 raise util.Abort(_('no revisions specified'))
2232 raise util.Abort(_('no revisions specified'))
2236 elif opts['applied']:
2233 elif opts['applied']:
2237 revrange = ('qbase:qtip',) + revrange
2234 revrange = ('qbase:qtip',) + revrange
2238
2235
2239 q = repo.mq
2236 q = repo.mq
2240 if not q.applied:
2237 if not q.applied:
2241 ui.status(_('no patches applied\n'))
2238 ui.status(_('no patches applied\n'))
2242 return 0
2239 return 0
2243
2240
2244 revs = cmdutil.revrange(repo, revrange)
2241 revs = cmdutil.revrange(repo, revrange)
2245 q.finish(repo, revs)
2242 q.finish(repo, revs)
2246 q.save_dirty()
2243 q.save_dirty()
2247 return 0
2244 return 0
2248
2245
2249 def reposetup(ui, repo):
2246 def reposetup(ui, repo):
2250 class mqrepo(repo.__class__):
2247 class mqrepo(repo.__class__):
2251 def abort_if_wdir_patched(self, errmsg, force=False):
2248 def abort_if_wdir_patched(self, errmsg, force=False):
2252 if self.mq.applied and not force:
2249 if self.mq.applied and not force:
2253 parent = revlog.hex(self.dirstate.parents()[0])
2250 parent = revlog.hex(self.dirstate.parents()[0])
2254 if parent in [s.rev for s in self.mq.applied]:
2251 if parent in [s.rev for s in self.mq.applied]:
2255 raise util.Abort(errmsg)
2252 raise util.Abort(errmsg)
2256
2253
2257 def commit(self, *args, **opts):
2254 def commit(self, *args, **opts):
2258 if len(args) >= 6:
2255 if len(args) >= 6:
2259 force = args[5]
2256 force = args[5]
2260 else:
2257 else:
2261 force = opts.get('force')
2258 force = opts.get('force')
2262 self.abort_if_wdir_patched(
2259 self.abort_if_wdir_patched(
2263 _('cannot commit over an applied mq patch'),
2260 _('cannot commit over an applied mq patch'),
2264 force)
2261 force)
2265
2262
2266 return super(mqrepo, self).commit(*args, **opts)
2263 return super(mqrepo, self).commit(*args, **opts)
2267
2264
2268 def push(self, remote, force=False, revs=None):
2265 def push(self, remote, force=False, revs=None):
2269 if self.mq.applied and not force and not revs:
2266 if self.mq.applied and not force and not revs:
2270 raise util.Abort(_('source has mq patches applied'))
2267 raise util.Abort(_('source has mq patches applied'))
2271 return super(mqrepo, self).push(remote, force, revs)
2268 return super(mqrepo, self).push(remote, force, revs)
2272
2269
2273 def tags(self):
2270 def tags(self):
2274 if self.tagscache:
2271 if self.tagscache:
2275 return self.tagscache
2272 return self.tagscache
2276
2273
2277 tagscache = super(mqrepo, self).tags()
2274 tagscache = super(mqrepo, self).tags()
2278
2275
2279 q = self.mq
2276 q = self.mq
2280 if not q.applied:
2277 if not q.applied:
2281 return tagscache
2278 return tagscache
2282
2279
2283 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2280 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2284
2281
2285 if mqtags[-1][0] not in self.changelog.nodemap:
2282 if mqtags[-1][0] not in self.changelog.nodemap:
2286 self.ui.warn('mq status file refers to unknown node %s\n'
2283 self.ui.warn('mq status file refers to unknown node %s\n'
2287 % revlog.short(mqtags[-1][0]))
2284 % revlog.short(mqtags[-1][0]))
2288 return tagscache
2285 return tagscache
2289
2286
2290 mqtags.append((mqtags[-1][0], 'qtip'))
2287 mqtags.append((mqtags[-1][0], 'qtip'))
2291 mqtags.append((mqtags[0][0], 'qbase'))
2288 mqtags.append((mqtags[0][0], 'qbase'))
2292 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2289 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2293 for patch in mqtags:
2290 for patch in mqtags:
2294 if patch[1] in tagscache:
2291 if patch[1] in tagscache:
2295 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2292 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2296 else:
2293 else:
2297 tagscache[patch[1]] = patch[0]
2294 tagscache[patch[1]] = patch[0]
2298
2295
2299 return tagscache
2296 return tagscache
2300
2297
2301 def _branchtags(self, partial, lrev):
2298 def _branchtags(self, partial, lrev):
2302 q = self.mq
2299 q = self.mq
2303 if not q.applied:
2300 if not q.applied:
2304 return super(mqrepo, self)._branchtags(partial, lrev)
2301 return super(mqrepo, self)._branchtags(partial, lrev)
2305
2302
2306 cl = self.changelog
2303 cl = self.changelog
2307 qbasenode = revlog.bin(q.applied[0].rev)
2304 qbasenode = revlog.bin(q.applied[0].rev)
2308 if qbasenode not in cl.nodemap:
2305 if qbasenode not in cl.nodemap:
2309 self.ui.warn('mq status file refers to unknown node %s\n'
2306 self.ui.warn('mq status file refers to unknown node %s\n'
2310 % revlog.short(qbasenode))
2307 % revlog.short(qbasenode))
2311 return super(mqrepo, self)._branchtags(partial, lrev)
2308 return super(mqrepo, self)._branchtags(partial, lrev)
2312
2309
2313 qbase = cl.rev(qbasenode)
2310 qbase = cl.rev(qbasenode)
2314 start = lrev + 1
2311 start = lrev + 1
2315 if start < qbase:
2312 if start < qbase:
2316 # update the cache (excluding the patches) and save it
2313 # update the cache (excluding the patches) and save it
2317 self._updatebranchcache(partial, lrev+1, qbase)
2314 self._updatebranchcache(partial, lrev+1, qbase)
2318 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2315 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2319 start = qbase
2316 start = qbase
2320 # if start = qbase, the cache is as updated as it should be.
2317 # if start = qbase, the cache is as updated as it should be.
2321 # if start > qbase, the cache includes (part of) the patches.
2318 # if start > qbase, the cache includes (part of) the patches.
2322 # we might as well use it, but we won't save it.
2319 # we might as well use it, but we won't save it.
2323
2320
2324 # update the cache up to the tip
2321 # update the cache up to the tip
2325 self._updatebranchcache(partial, start, cl.count())
2322 self._updatebranchcache(partial, start, cl.count())
2326
2323
2327 return partial
2324 return partial
2328
2325
2329 if repo.local():
2326 if repo.local():
2330 repo.__class__ = mqrepo
2327 repo.__class__ = mqrepo
2331 repo.mq = queue(ui, repo.join(""))
2328 repo.mq = queue(ui, repo.join(""))
2332
2329
2333 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2330 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2334
2331
2335 headeropts = [
2332 headeropts = [
2336 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2333 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2337 ('u', 'user', '', _('add "From: <given user>" to patch')),
2334 ('u', 'user', '', _('add "From: <given user>" to patch')),
2338 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2335 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2339 ('d', 'date', '', _('add "Date: <given date>" to patch'))]
2336 ('d', 'date', '', _('add "Date: <given date>" to patch'))]
2340
2337
2341 cmdtable = {
2338 cmdtable = {
2342 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2339 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2343 "qclone":
2340 "qclone":
2344 (clone,
2341 (clone,
2345 [('', 'pull', None, _('use pull protocol to copy metadata')),
2342 [('', 'pull', None, _('use pull protocol to copy metadata')),
2346 ('U', 'noupdate', None, _('do not update the new working directories')),
2343 ('U', 'noupdate', None, _('do not update the new working directories')),
2347 ('', 'uncompressed', None,
2344 ('', 'uncompressed', None,
2348 _('use uncompressed transfer (fast over LAN)')),
2345 _('use uncompressed transfer (fast over LAN)')),
2349 ('p', 'patches', '', _('location of source patch repo')),
2346 ('p', 'patches', '', _('location of source patch repo')),
2350 ] + commands.remoteopts,
2347 ] + commands.remoteopts,
2351 _('hg qclone [OPTION]... SOURCE [DEST]')),
2348 _('hg qclone [OPTION]... SOURCE [DEST]')),
2352 "qcommit|qci":
2349 "qcommit|qci":
2353 (commit,
2350 (commit,
2354 commands.table["^commit|ci"][1],
2351 commands.table["^commit|ci"][1],
2355 _('hg qcommit [OPTION]... [FILE]...')),
2352 _('hg qcommit [OPTION]... [FILE]...')),
2356 "^qdiff":
2353 "^qdiff":
2357 (diff,
2354 (diff,
2358 [('g', 'git', None, _('use git extended diff format')),
2355 commands.diffopts + commands.diffopts2 + commands.walkopts,
2359 ('U', 'unified', 3, _('number of lines of context to show')),
2356 _('hg qdiff [OPTION]... [FILE]...')),
2360 ] + commands.walkopts,
2361 _('hg qdiff [-I] [-X] [-U NUM] [-g] [FILE]...')),
2362 "qdelete|qremove|qrm":
2357 "qdelete|qremove|qrm":
2363 (delete,
2358 (delete,
2364 [('k', 'keep', None, _('keep patch file')),
2359 [('k', 'keep', None, _('keep patch file')),
2365 ('r', 'rev', [], _('stop managing a revision'))],
2360 ('r', 'rev', [], _('stop managing a revision'))],
2366 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2361 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2367 'qfold':
2362 'qfold':
2368 (fold,
2363 (fold,
2369 [('e', 'edit', None, _('edit patch header')),
2364 [('e', 'edit', None, _('edit patch header')),
2370 ('k', 'keep', None, _('keep folded patch files')),
2365 ('k', 'keep', None, _('keep folded patch files')),
2371 ] + commands.commitopts,
2366 ] + commands.commitopts,
2372 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2367 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2373 'qgoto':
2368 'qgoto':
2374 (goto,
2369 (goto,
2375 [('f', 'force', None, _('overwrite any local changes'))],
2370 [('f', 'force', None, _('overwrite any local changes'))],
2376 _('hg qgoto [OPTION]... PATCH')),
2371 _('hg qgoto [OPTION]... PATCH')),
2377 'qguard':
2372 'qguard':
2378 (guard,
2373 (guard,
2379 [('l', 'list', None, _('list all patches and guards')),
2374 [('l', 'list', None, _('list all patches and guards')),
2380 ('n', 'none', None, _('drop all guards'))],
2375 ('n', 'none', None, _('drop all guards'))],
2381 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2376 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2382 'qheader': (header, [], _('hg qheader [PATCH]')),
2377 'qheader': (header, [], _('hg qheader [PATCH]')),
2383 "^qimport":
2378 "^qimport":
2384 (qimport,
2379 (qimport,
2385 [('e', 'existing', None, 'import file in patch dir'),
2380 [('e', 'existing', None, 'import file in patch dir'),
2386 ('n', 'name', '', 'patch file name'),
2381 ('n', 'name', '', 'patch file name'),
2387 ('f', 'force', None, 'overwrite existing files'),
2382 ('f', 'force', None, 'overwrite existing files'),
2388 ('r', 'rev', [], 'place existing revisions under mq control'),
2383 ('r', 'rev', [], 'place existing revisions under mq control'),
2389 ('g', 'git', None, _('use git extended diff format'))],
2384 ('g', 'git', None, _('use git extended diff format'))],
2390 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2385 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2391 "^qinit":
2386 "^qinit":
2392 (init,
2387 (init,
2393 [('c', 'create-repo', None, 'create queue repository')],
2388 [('c', 'create-repo', None, 'create queue repository')],
2394 _('hg qinit [-c]')),
2389 _('hg qinit [-c]')),
2395 "qnew":
2390 "qnew":
2396 (new,
2391 (new,
2397 [('e', 'edit', None, _('edit commit message')),
2392 [('e', 'edit', None, _('edit commit message')),
2398 ('f', 'force', None, _('import uncommitted changes into patch')),
2393 ('f', 'force', None, _('import uncommitted changes into patch')),
2399 ('g', 'git', None, _('use git extended diff format')),
2394 ('g', 'git', None, _('use git extended diff format')),
2400 ] + commands.walkopts + commands.commitopts + headeropts,
2395 ] + commands.walkopts + commands.commitopts + headeropts,
2401 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2396 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2402 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2397 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2403 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2398 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2404 "^qpop":
2399 "^qpop":
2405 (pop,
2400 (pop,
2406 [('a', 'all', None, _('pop all patches')),
2401 [('a', 'all', None, _('pop all patches')),
2407 ('n', 'name', '', _('queue name to pop')),
2402 ('n', 'name', '', _('queue name to pop')),
2408 ('f', 'force', None, _('forget any local changes'))],
2403 ('f', 'force', None, _('forget any local changes'))],
2409 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2404 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2410 "^qpush":
2405 "^qpush":
2411 (push,
2406 (push,
2412 [('f', 'force', None, _('apply if the patch has rejects')),
2407 [('f', 'force', None, _('apply if the patch has rejects')),
2413 ('l', 'list', None, _('list patch name in commit text')),
2408 ('l', 'list', None, _('list patch name in commit text')),
2414 ('a', 'all', None, _('apply all patches')),
2409 ('a', 'all', None, _('apply all patches')),
2415 ('m', 'merge', None, _('merge from another queue')),
2410 ('m', 'merge', None, _('merge from another queue')),
2416 ('n', 'name', '', _('merge queue name'))],
2411 ('n', 'name', '', _('merge queue name'))],
2417 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2412 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2418 "^qrefresh":
2413 "^qrefresh":
2419 (refresh,
2414 (refresh,
2420 [('e', 'edit', None, _('edit commit message')),
2415 [('e', 'edit', None, _('edit commit message')),
2421 ('g', 'git', None, _('use git extended diff format')),
2416 ('g', 'git', None, _('use git extended diff format')),
2422 ('s', 'short', None, _('refresh only files already in the patch')),
2417 ('s', 'short', None, _('refresh only files already in the patch')),
2423 ] + commands.walkopts + commands.commitopts + headeropts,
2418 ] + commands.walkopts + commands.commitopts + headeropts,
2424 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2419 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2425 'qrename|qmv':
2420 'qrename|qmv':
2426 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2421 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2427 "qrestore":
2422 "qrestore":
2428 (restore,
2423 (restore,
2429 [('d', 'delete', None, _('delete save entry')),
2424 [('d', 'delete', None, _('delete save entry')),
2430 ('u', 'update', None, _('update queue working dir'))],
2425 ('u', 'update', None, _('update queue working dir'))],
2431 _('hg qrestore [-d] [-u] REV')),
2426 _('hg qrestore [-d] [-u] REV')),
2432 "qsave":
2427 "qsave":
2433 (save,
2428 (save,
2434 [('c', 'copy', None, _('copy patch directory')),
2429 [('c', 'copy', None, _('copy patch directory')),
2435 ('n', 'name', '', _('copy directory name')),
2430 ('n', 'name', '', _('copy directory name')),
2436 ('e', 'empty', None, _('clear queue status file')),
2431 ('e', 'empty', None, _('clear queue status file')),
2437 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2432 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2438 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2433 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2439 "qselect":
2434 "qselect":
2440 (select,
2435 (select,
2441 [('n', 'none', None, _('disable all guards')),
2436 [('n', 'none', None, _('disable all guards')),
2442 ('s', 'series', None, _('list all guards in series file')),
2437 ('s', 'series', None, _('list all guards in series file')),
2443 ('', 'pop', None, _('pop to before first guarded applied patch')),
2438 ('', 'pop', None, _('pop to before first guarded applied patch')),
2444 ('', 'reapply', None, _('pop, then reapply patches'))],
2439 ('', 'reapply', None, _('pop, then reapply patches'))],
2445 _('hg qselect [OPTION]... [GUARD]...')),
2440 _('hg qselect [OPTION]... [GUARD]...')),
2446 "qseries":
2441 "qseries":
2447 (series,
2442 (series,
2448 [('m', 'missing', None, _('print patches not in series')),
2443 [('m', 'missing', None, _('print patches not in series')),
2449 ] + seriesopts,
2444 ] + seriesopts,
2450 _('hg qseries [-ms]')),
2445 _('hg qseries [-ms]')),
2451 "^strip":
2446 "^strip":
2452 (strip,
2447 (strip,
2453 [('f', 'force', None, _('force removal with local changes')),
2448 [('f', 'force', None, _('force removal with local changes')),
2454 ('b', 'backup', None, _('bundle unrelated changesets')),
2449 ('b', 'backup', None, _('bundle unrelated changesets')),
2455 ('n', 'nobackup', None, _('no backups'))],
2450 ('n', 'nobackup', None, _('no backups'))],
2456 _('hg strip [-f] [-b] [-n] REV')),
2451 _('hg strip [-f] [-b] [-n] REV')),
2457 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2452 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2458 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2453 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2459 "qfinish":
2454 "qfinish":
2460 (finish,
2455 (finish,
2461 [('a', 'applied', None, _('finish all applied changesets'))],
2456 [('a', 'applied', None, _('finish all applied changesets'))],
2462 _('hg qfinish [-a] [REV...]')),
2457 _('hg qfinish [-a] [REV...]')),
2463 }
2458 }
@@ -1,3330 +1,3332 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 repository heads.
376 A branch is considered active if it contains repository 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 hexfunc = ui.debugflag and hex or short
380 hexfunc = ui.debugflag and hex or short
381 activebranches = [util.tolocal(repo.changectx(n).branch())
381 activebranches = [util.tolocal(repo.changectx(n).branch())
382 for n in repo.heads()]
382 for n in repo.heads()]
383 branches = [(tag in activebranches, repo.changelog.rev(node), tag)
383 branches = [(tag in activebranches, repo.changelog.rev(node), tag)
384 for tag, node in repo.branchtags().items()]
384 for tag, node in repo.branchtags().items()]
385 branches.sort(reverse=True)
385 branches.sort(reverse=True)
386
386
387 for isactive, node, tag in branches:
387 for isactive, node, tag in branches:
388 if (not active) or isactive:
388 if (not active) or isactive:
389 if ui.quiet:
389 if ui.quiet:
390 ui.write("%s\n" % tag)
390 ui.write("%s\n" % tag)
391 else:
391 else:
392 rev = str(node).rjust(32 - util.locallen(tag))
392 rev = str(node).rjust(32 - util.locallen(tag))
393 isinactive = ((not isactive) and " (inactive)") or ''
393 isinactive = ((not isactive) and " (inactive)") or ''
394 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
394 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
395 ui.write("%s%s:%s%s\n" % data)
395 ui.write("%s%s:%s%s\n" % data)
396
396
397 def bundle(ui, repo, fname, dest=None, **opts):
397 def bundle(ui, repo, fname, dest=None, **opts):
398 """create a changegroup file
398 """create a changegroup file
399
399
400 Generate a compressed changegroup file collecting changesets not
400 Generate a compressed changegroup file collecting changesets not
401 found in the other repository.
401 found in the other repository.
402
402
403 If no destination repository is specified the destination is
403 If no destination repository is specified the destination is
404 assumed to have all the nodes specified by one or more --base
404 assumed to have all the nodes specified by one or more --base
405 parameters. To create a bundle containing all changesets, use
405 parameters. To create a bundle containing all changesets, use
406 --all (or --base null). To change the compression method applied,
406 --all (or --base null). To change the compression method applied,
407 use the -t option (by default, bundles are compressed using bz2).
407 use the -t option (by default, bundles are compressed using bz2).
408
408
409 The bundle file can then be transferred using conventional means and
409 The bundle file can then be transferred using conventional means and
410 applied to another repository with the unbundle or pull command.
410 applied to another repository with the unbundle or pull command.
411 This is useful when direct push and pull are not available or when
411 This is useful when direct push and pull are not available or when
412 exporting an entire repository is undesirable.
412 exporting an entire repository is undesirable.
413
413
414 Applying bundles preserves all changeset contents including
414 Applying bundles preserves all changeset contents including
415 permissions, copy/rename information, and revision history.
415 permissions, copy/rename information, and revision history.
416 """
416 """
417 revs = opts.get('rev') or None
417 revs = opts.get('rev') or None
418 if revs:
418 if revs:
419 revs = [repo.lookup(rev) for rev in revs]
419 revs = [repo.lookup(rev) for rev in revs]
420 if opts.get('all'):
420 if opts.get('all'):
421 base = ['null']
421 base = ['null']
422 else:
422 else:
423 base = opts.get('base')
423 base = opts.get('base')
424 if base:
424 if base:
425 if dest:
425 if dest:
426 raise util.Abort(_("--base is incompatible with specifiying "
426 raise util.Abort(_("--base is incompatible with specifiying "
427 "a destination"))
427 "a destination"))
428 base = [repo.lookup(rev) for rev in base]
428 base = [repo.lookup(rev) for rev in base]
429 # create the right base
429 # create the right base
430 # XXX: nodesbetween / changegroup* should be "fixed" instead
430 # XXX: nodesbetween / changegroup* should be "fixed" instead
431 o = []
431 o = []
432 has = {nullid: None}
432 has = {nullid: None}
433 for n in base:
433 for n in base:
434 has.update(repo.changelog.reachable(n))
434 has.update(repo.changelog.reachable(n))
435 if revs:
435 if revs:
436 visit = list(revs)
436 visit = list(revs)
437 else:
437 else:
438 visit = repo.changelog.heads()
438 visit = repo.changelog.heads()
439 seen = {}
439 seen = {}
440 while visit:
440 while visit:
441 n = visit.pop(0)
441 n = visit.pop(0)
442 parents = [p for p in repo.changelog.parents(n) if p not in has]
442 parents = [p for p in repo.changelog.parents(n) if p not in has]
443 if len(parents) == 0:
443 if len(parents) == 0:
444 o.insert(0, n)
444 o.insert(0, n)
445 else:
445 else:
446 for p in parents:
446 for p in parents:
447 if p not in seen:
447 if p not in seen:
448 seen[p] = 1
448 seen[p] = 1
449 visit.append(p)
449 visit.append(p)
450 else:
450 else:
451 cmdutil.setremoteconfig(ui, opts)
451 cmdutil.setremoteconfig(ui, opts)
452 dest, revs, checkout = hg.parseurl(
452 dest, revs, checkout = hg.parseurl(
453 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
453 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
454 other = hg.repository(ui, dest)
454 other = hg.repository(ui, dest)
455 o = repo.findoutgoing(other, force=opts['force'])
455 o = repo.findoutgoing(other, force=opts['force'])
456
456
457 if revs:
457 if revs:
458 cg = repo.changegroupsubset(o, revs, 'bundle')
458 cg = repo.changegroupsubset(o, revs, 'bundle')
459 else:
459 else:
460 cg = repo.changegroup(o, 'bundle')
460 cg = repo.changegroup(o, 'bundle')
461
461
462 bundletype = opts.get('type', 'bzip2').lower()
462 bundletype = opts.get('type', 'bzip2').lower()
463 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
463 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
464 bundletype = btypes.get(bundletype)
464 bundletype = btypes.get(bundletype)
465 if bundletype not in changegroup.bundletypes:
465 if bundletype not in changegroup.bundletypes:
466 raise util.Abort(_('unknown bundle type specified with --type'))
466 raise util.Abort(_('unknown bundle type specified with --type'))
467
467
468 changegroup.writebundle(cg, fname, bundletype)
468 changegroup.writebundle(cg, fname, bundletype)
469
469
470 def cat(ui, repo, file1, *pats, **opts):
470 def cat(ui, repo, file1, *pats, **opts):
471 """output the current or given revision of files
471 """output the current or given revision of files
472
472
473 Print the specified files as they were at the given revision.
473 Print the specified files as they were at the given revision.
474 If no revision is given, the parent of the working directory is used,
474 If no revision is given, the parent of the working directory is used,
475 or tip if no revision is checked out.
475 or tip if no revision is checked out.
476
476
477 Output may be to a file, in which case the name of the file is
477 Output may be to a file, in which case the name of the file is
478 given using a format string. The formatting rules are the same as
478 given using a format string. The formatting rules are the same as
479 for the export command, with the following additions:
479 for the export command, with the following additions:
480
480
481 %s basename of file being printed
481 %s basename of file being printed
482 %d dirname of file being printed, or '.' if in repo root
482 %d dirname of file being printed, or '.' if in repo root
483 %p root-relative path name of file being printed
483 %p root-relative path name of file being printed
484 """
484 """
485 ctx = repo.changectx(opts['rev'])
485 ctx = repo.changectx(opts['rev'])
486 err = 1
486 err = 1
487 m = cmdutil.match(repo, (file1,) + pats, opts)
487 m = cmdutil.match(repo, (file1,) + pats, opts)
488 for abs in repo.walk(m, ctx.node()):
488 for abs in repo.walk(m, ctx.node()):
489 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
489 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
490 data = ctx.filectx(abs).data()
490 data = ctx.filectx(abs).data()
491 if opts.get('decode'):
491 if opts.get('decode'):
492 data = repo.wwritedata(abs, data)
492 data = repo.wwritedata(abs, data)
493 fp.write(data)
493 fp.write(data)
494 err = 0
494 err = 0
495 return err
495 return err
496
496
497 def clone(ui, source, dest=None, **opts):
497 def clone(ui, source, dest=None, **opts):
498 """make a copy of an existing repository
498 """make a copy of an existing repository
499
499
500 Create a copy of an existing repository in a new directory.
500 Create a copy of an existing repository in a new directory.
501
501
502 If no destination directory name is specified, it defaults to the
502 If no destination directory name is specified, it defaults to the
503 basename of the source.
503 basename of the source.
504
504
505 The location of the source is added to the new repository's
505 The location of the source is added to the new repository's
506 .hg/hgrc file, as the default to be used for future pulls.
506 .hg/hgrc file, as the default to be used for future pulls.
507
507
508 For efficiency, hardlinks are used for cloning whenever the source
508 For efficiency, hardlinks are used for cloning whenever the source
509 and destination are on the same filesystem (note this applies only
509 and destination are on the same filesystem (note this applies only
510 to the repository data, not to the checked out files). Some
510 to the repository data, not to the checked out files). Some
511 filesystems, such as AFS, implement hardlinking incorrectly, but
511 filesystems, such as AFS, implement hardlinking incorrectly, but
512 do not report errors. In these cases, use the --pull option to
512 do not report errors. In these cases, use the --pull option to
513 avoid hardlinking.
513 avoid hardlinking.
514
514
515 In some cases, you can clone repositories and checked out files
515 In some cases, you can clone repositories and checked out files
516 using full hardlinks with
516 using full hardlinks with
517
517
518 $ cp -al REPO REPOCLONE
518 $ cp -al REPO REPOCLONE
519
519
520 This is the fastest way to clone, but it is not always safe. The
520 This is the fastest way to clone, but it is not always safe. The
521 operation is not atomic (making sure REPO is not modified during
521 operation is not atomic (making sure REPO is not modified during
522 the operation is up to you) and you have to make sure your editor
522 the operation is up to you) and you have to make sure your editor
523 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
523 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
524 this is not compatible with certain extensions that place their
524 this is not compatible with certain extensions that place their
525 metadata under the .hg directory, such as mq.
525 metadata under the .hg directory, such as mq.
526
526
527 If you use the -r option to clone up to a specific revision, no
527 If you use the -r option to clone up to a specific revision, no
528 subsequent revisions will be present in the cloned repository.
528 subsequent revisions will be present in the cloned repository.
529 This option implies --pull, even on local repositories.
529 This option implies --pull, even on local repositories.
530
530
531 If the -U option is used, the new clone will contain only a repository
531 If the -U option is used, the new clone will contain only a repository
532 (.hg) and no working copy (the working copy parent is the null revision).
532 (.hg) and no working copy (the working copy parent is the null revision).
533
533
534 See pull for valid source format details.
534 See pull for valid source format details.
535
535
536 It is possible to specify an ssh:// URL as the destination, but no
536 It is possible to specify an ssh:// URL as the destination, but no
537 .hg/hgrc and working directory will be created on the remote side.
537 .hg/hgrc and working directory will be created on the remote side.
538 Look at the help text for the pull command for important details
538 Look at the help text for the pull command for important details
539 about ssh:// URLs.
539 about ssh:// URLs.
540 """
540 """
541 cmdutil.setremoteconfig(ui, opts)
541 cmdutil.setremoteconfig(ui, opts)
542 hg.clone(ui, source, dest,
542 hg.clone(ui, source, dest,
543 pull=opts['pull'],
543 pull=opts['pull'],
544 stream=opts['uncompressed'],
544 stream=opts['uncompressed'],
545 rev=opts['rev'],
545 rev=opts['rev'],
546 update=not opts['noupdate'])
546 update=not opts['noupdate'])
547
547
548 def commit(ui, repo, *pats, **opts):
548 def commit(ui, repo, *pats, **opts):
549 """commit the specified files or all outstanding changes
549 """commit the specified files or all outstanding changes
550
550
551 Commit changes to the given files into the repository.
551 Commit changes to the given files into the repository.
552
552
553 If a list of files is omitted, all changes reported by "hg status"
553 If a list of files is omitted, all changes reported by "hg status"
554 will be committed.
554 will be committed.
555
555
556 If you are committing the result of a merge, do not provide any
556 If you are committing the result of a merge, do not provide any
557 file names or -I/-X filters.
557 file names or -I/-X filters.
558
558
559 If no commit message is specified, the configured editor is started to
559 If no commit message is specified, the configured editor is started to
560 enter a message.
560 enter a message.
561
561
562 See 'hg help dates' for a list of formats valid for -d/--date.
562 See 'hg help dates' for a list of formats valid for -d/--date.
563 """
563 """
564 def commitfunc(ui, repo, message, match, opts):
564 def commitfunc(ui, repo, message, match, opts):
565 return repo.commit(match.files(), message, opts['user'], opts['date'],
565 return repo.commit(match.files(), message, opts['user'], opts['date'],
566 match, force_editor=opts.get('force_editor'))
566 match, force_editor=opts.get('force_editor'))
567
567
568 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
568 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
569 if not node:
569 if not node:
570 return
570 return
571 cl = repo.changelog
571 cl = repo.changelog
572 rev = cl.rev(node)
572 rev = cl.rev(node)
573 parents = cl.parentrevs(rev)
573 parents = cl.parentrevs(rev)
574 if rev - 1 in parents:
574 if rev - 1 in parents:
575 # one of the parents was the old tip
575 # one of the parents was the old tip
576 return
576 return
577 if (parents == (nullrev, nullrev) or
577 if (parents == (nullrev, nullrev) or
578 len(cl.heads(cl.node(parents[0]))) > 1 and
578 len(cl.heads(cl.node(parents[0]))) > 1 and
579 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
579 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
580 ui.status(_('created new head\n'))
580 ui.status(_('created new head\n'))
581
581
582 def copy(ui, repo, *pats, **opts):
582 def copy(ui, repo, *pats, **opts):
583 """mark files as copied for the next commit
583 """mark files as copied for the next commit
584
584
585 Mark dest as having copies of source files. If dest is a
585 Mark dest as having copies of source files. If dest is a
586 directory, copies are put in that directory. If dest is a file,
586 directory, copies are put in that directory. If dest is a file,
587 there can only be one source.
587 there can only be one source.
588
588
589 By default, this command copies the contents of files as they
589 By default, this command copies the contents of files as they
590 stand in the working directory. If invoked with --after, the
590 stand in the working directory. If invoked with --after, the
591 operation is recorded, but no copying is performed.
591 operation is recorded, but no copying is performed.
592
592
593 This command takes effect in the next commit. To undo a copy
593 This command takes effect in the next commit. To undo a copy
594 before that, see hg revert.
594 before that, see hg revert.
595 """
595 """
596 wlock = repo.wlock(False)
596 wlock = repo.wlock(False)
597 try:
597 try:
598 return cmdutil.copy(ui, repo, pats, opts)
598 return cmdutil.copy(ui, repo, pats, opts)
599 finally:
599 finally:
600 del wlock
600 del wlock
601
601
602 def debugancestor(ui, repo, *args):
602 def debugancestor(ui, repo, *args):
603 """find the ancestor revision of two revisions in a given index"""
603 """find the ancestor revision of two revisions in a given index"""
604 if len(args) == 3:
604 if len(args) == 3:
605 index, rev1, rev2 = args
605 index, rev1, rev2 = args
606 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
606 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
607 lookup = r.lookup
607 lookup = r.lookup
608 elif len(args) == 2:
608 elif len(args) == 2:
609 if not repo:
609 if not repo:
610 raise util.Abort(_("There is no Mercurial repository here "
610 raise util.Abort(_("There is no Mercurial repository here "
611 "(.hg not found)"))
611 "(.hg not found)"))
612 rev1, rev2 = args
612 rev1, rev2 = args
613 r = repo.changelog
613 r = repo.changelog
614 lookup = repo.lookup
614 lookup = repo.lookup
615 else:
615 else:
616 raise util.Abort(_('either two or three arguments required'))
616 raise util.Abort(_('either two or three arguments required'))
617 a = r.ancestor(lookup(rev1), lookup(rev2))
617 a = r.ancestor(lookup(rev1), lookup(rev2))
618 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
618 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
619
619
620 def debugcomplete(ui, cmd='', **opts):
620 def debugcomplete(ui, cmd='', **opts):
621 """returns the completion list associated with the given command"""
621 """returns the completion list associated with the given command"""
622
622
623 if opts['options']:
623 if opts['options']:
624 options = []
624 options = []
625 otables = [globalopts]
625 otables = [globalopts]
626 if cmd:
626 if cmd:
627 aliases, entry = cmdutil.findcmd(ui, cmd, table)
627 aliases, entry = cmdutil.findcmd(ui, cmd, table)
628 otables.append(entry[1])
628 otables.append(entry[1])
629 for t in otables:
629 for t in otables:
630 for o in t:
630 for o in t:
631 if o[0]:
631 if o[0]:
632 options.append('-%s' % o[0])
632 options.append('-%s' % o[0])
633 options.append('--%s' % o[1])
633 options.append('--%s' % o[1])
634 ui.write("%s\n" % "\n".join(options))
634 ui.write("%s\n" % "\n".join(options))
635 return
635 return
636
636
637 clist = cmdutil.findpossible(ui, cmd, table).keys()
637 clist = cmdutil.findpossible(ui, cmd, table).keys()
638 clist.sort()
638 clist.sort()
639 ui.write("%s\n" % "\n".join(clist))
639 ui.write("%s\n" % "\n".join(clist))
640
640
641 def debugfsinfo(ui, path = "."):
641 def debugfsinfo(ui, path = "."):
642 file('.debugfsinfo', 'w').write('')
642 file('.debugfsinfo', 'w').write('')
643 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
643 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
644 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
644 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
645 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
645 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
646 and 'yes' or 'no'))
646 and 'yes' or 'no'))
647 os.unlink('.debugfsinfo')
647 os.unlink('.debugfsinfo')
648
648
649 def debugrebuildstate(ui, repo, rev=""):
649 def debugrebuildstate(ui, repo, rev=""):
650 """rebuild the dirstate as it would look like for the given revision"""
650 """rebuild the dirstate as it would look like for the given revision"""
651 if rev == "":
651 if rev == "":
652 rev = repo.changelog.tip()
652 rev = repo.changelog.tip()
653 ctx = repo.changectx(rev)
653 ctx = repo.changectx(rev)
654 files = ctx.manifest()
654 files = ctx.manifest()
655 wlock = repo.wlock()
655 wlock = repo.wlock()
656 try:
656 try:
657 repo.dirstate.rebuild(rev, files)
657 repo.dirstate.rebuild(rev, files)
658 finally:
658 finally:
659 del wlock
659 del wlock
660
660
661 def debugcheckstate(ui, repo):
661 def debugcheckstate(ui, repo):
662 """validate the correctness of the current dirstate"""
662 """validate the correctness of the current dirstate"""
663 parent1, parent2 = repo.dirstate.parents()
663 parent1, parent2 = repo.dirstate.parents()
664 m1 = repo.changectx(parent1).manifest()
664 m1 = repo.changectx(parent1).manifest()
665 m2 = repo.changectx(parent2).manifest()
665 m2 = repo.changectx(parent2).manifest()
666 errors = 0
666 errors = 0
667 for f in repo.dirstate:
667 for f in repo.dirstate:
668 state = repo.dirstate[f]
668 state = repo.dirstate[f]
669 if state in "nr" and f not in m1:
669 if state in "nr" and f not in m1:
670 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
670 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
671 errors += 1
671 errors += 1
672 if state in "a" and f in m1:
672 if state in "a" and f in m1:
673 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
673 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
674 errors += 1
674 errors += 1
675 if state in "m" and f not in m1 and f not in m2:
675 if state in "m" and f not in m1 and f not in m2:
676 ui.warn(_("%s in state %s, but not in either manifest\n") %
676 ui.warn(_("%s in state %s, but not in either manifest\n") %
677 (f, state))
677 (f, state))
678 errors += 1
678 errors += 1
679 for f in m1:
679 for f in m1:
680 state = repo.dirstate[f]
680 state = repo.dirstate[f]
681 if state not in "nrm":
681 if state not in "nrm":
682 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
682 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
683 errors += 1
683 errors += 1
684 if errors:
684 if errors:
685 error = _(".hg/dirstate inconsistent with current parent's manifest")
685 error = _(".hg/dirstate inconsistent with current parent's manifest")
686 raise util.Abort(error)
686 raise util.Abort(error)
687
687
688 def showconfig(ui, repo, *values, **opts):
688 def showconfig(ui, repo, *values, **opts):
689 """show combined config settings from all hgrc files
689 """show combined config settings from all hgrc files
690
690
691 With no args, print names and values of all config items.
691 With no args, print names and values of all config items.
692
692
693 With one arg of the form section.name, print just the value of
693 With one arg of the form section.name, print just the value of
694 that config item.
694 that config item.
695
695
696 With multiple args, print names and values of all config items
696 With multiple args, print names and values of all config items
697 with matching section names."""
697 with matching section names."""
698
698
699 untrusted = bool(opts.get('untrusted'))
699 untrusted = bool(opts.get('untrusted'))
700 if values:
700 if values:
701 if len([v for v in values if '.' in v]) > 1:
701 if len([v for v in values if '.' in v]) > 1:
702 raise util.Abort(_('only one config item permitted'))
702 raise util.Abort(_('only one config item permitted'))
703 for section, name, value in ui.walkconfig(untrusted=untrusted):
703 for section, name, value in ui.walkconfig(untrusted=untrusted):
704 sectname = section + '.' + name
704 sectname = section + '.' + name
705 if values:
705 if values:
706 for v in values:
706 for v in values:
707 if v == section:
707 if v == section:
708 ui.write('%s=%s\n' % (sectname, value))
708 ui.write('%s=%s\n' % (sectname, value))
709 elif v == sectname:
709 elif v == sectname:
710 ui.write(value, '\n')
710 ui.write(value, '\n')
711 else:
711 else:
712 ui.write('%s=%s\n' % (sectname, value))
712 ui.write('%s=%s\n' % (sectname, value))
713
713
714 def debugsetparents(ui, repo, rev1, rev2=None):
714 def debugsetparents(ui, repo, rev1, rev2=None):
715 """manually set the parents of the current working directory
715 """manually set the parents of the current working directory
716
716
717 This is useful for writing repository conversion tools, but should
717 This is useful for writing repository conversion tools, but should
718 be used with care.
718 be used with care.
719 """
719 """
720
720
721 if not rev2:
721 if not rev2:
722 rev2 = hex(nullid)
722 rev2 = hex(nullid)
723
723
724 wlock = repo.wlock()
724 wlock = repo.wlock()
725 try:
725 try:
726 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
726 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
727 finally:
727 finally:
728 del wlock
728 del wlock
729
729
730 def debugstate(ui, repo, nodates=None):
730 def debugstate(ui, repo, nodates=None):
731 """show the contents of the current dirstate"""
731 """show the contents of the current dirstate"""
732 k = repo.dirstate._map.items()
732 k = repo.dirstate._map.items()
733 k.sort()
733 k.sort()
734 timestr = ""
734 timestr = ""
735 showdate = not nodates
735 showdate = not nodates
736 for file_, ent in k:
736 for file_, ent in k:
737 if showdate:
737 if showdate:
738 if ent[3] == -1:
738 if ent[3] == -1:
739 # Pad or slice to locale representation
739 # Pad or slice to locale representation
740 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
740 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
741 timestr = 'unset'
741 timestr = 'unset'
742 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
742 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
743 else:
743 else:
744 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
744 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
745 if ent[1] & 020000:
745 if ent[1] & 020000:
746 mode = 'lnk'
746 mode = 'lnk'
747 else:
747 else:
748 mode = '%3o' % (ent[1] & 0777)
748 mode = '%3o' % (ent[1] & 0777)
749 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
749 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
750 for f in repo.dirstate.copies():
750 for f in repo.dirstate.copies():
751 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
751 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
752
752
753 def debugdata(ui, file_, rev):
753 def debugdata(ui, file_, rev):
754 """dump the contents of a data file revision"""
754 """dump the contents of a data file revision"""
755 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
755 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
756 try:
756 try:
757 ui.write(r.revision(r.lookup(rev)))
757 ui.write(r.revision(r.lookup(rev)))
758 except KeyError:
758 except KeyError:
759 raise util.Abort(_('invalid revision identifier %s') % rev)
759 raise util.Abort(_('invalid revision identifier %s') % rev)
760
760
761 def debugdate(ui, date, range=None, **opts):
761 def debugdate(ui, date, range=None, **opts):
762 """parse and display a date"""
762 """parse and display a date"""
763 if opts["extended"]:
763 if opts["extended"]:
764 d = util.parsedate(date, util.extendeddateformats)
764 d = util.parsedate(date, util.extendeddateformats)
765 else:
765 else:
766 d = util.parsedate(date)
766 d = util.parsedate(date)
767 ui.write("internal: %s %s\n" % d)
767 ui.write("internal: %s %s\n" % d)
768 ui.write("standard: %s\n" % util.datestr(d))
768 ui.write("standard: %s\n" % util.datestr(d))
769 if range:
769 if range:
770 m = util.matchdate(range)
770 m = util.matchdate(range)
771 ui.write("match: %s\n" % m(d[0]))
771 ui.write("match: %s\n" % m(d[0]))
772
772
773 def debugindex(ui, file_):
773 def debugindex(ui, file_):
774 """dump the contents of an index file"""
774 """dump the contents of an index file"""
775 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
775 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
776 ui.write(" rev offset length base linkrev" +
776 ui.write(" rev offset length base linkrev" +
777 " nodeid p1 p2\n")
777 " nodeid p1 p2\n")
778 for i in xrange(r.count()):
778 for i in xrange(r.count()):
779 node = r.node(i)
779 node = r.node(i)
780 try:
780 try:
781 pp = r.parents(node)
781 pp = r.parents(node)
782 except:
782 except:
783 pp = [nullid, nullid]
783 pp = [nullid, nullid]
784 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
784 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
785 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
785 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
786 short(node), short(pp[0]), short(pp[1])))
786 short(node), short(pp[0]), short(pp[1])))
787
787
788 def debugindexdot(ui, file_):
788 def debugindexdot(ui, file_):
789 """dump an index DAG as a .dot file"""
789 """dump an index DAG as a .dot file"""
790 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
790 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
791 ui.write("digraph G {\n")
791 ui.write("digraph G {\n")
792 for i in xrange(r.count()):
792 for i in xrange(r.count()):
793 node = r.node(i)
793 node = r.node(i)
794 pp = r.parents(node)
794 pp = r.parents(node)
795 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
795 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
796 if pp[1] != nullid:
796 if pp[1] != nullid:
797 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
797 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
798 ui.write("}\n")
798 ui.write("}\n")
799
799
800 def debuginstall(ui):
800 def debuginstall(ui):
801 '''test Mercurial installation'''
801 '''test Mercurial installation'''
802
802
803 def writetemp(contents):
803 def writetemp(contents):
804 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
804 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
805 f = os.fdopen(fd, "wb")
805 f = os.fdopen(fd, "wb")
806 f.write(contents)
806 f.write(contents)
807 f.close()
807 f.close()
808 return name
808 return name
809
809
810 problems = 0
810 problems = 0
811
811
812 # encoding
812 # encoding
813 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
813 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
814 try:
814 try:
815 util.fromlocal("test")
815 util.fromlocal("test")
816 except util.Abort, inst:
816 except util.Abort, inst:
817 ui.write(" %s\n" % inst)
817 ui.write(" %s\n" % inst)
818 ui.write(_(" (check that your locale is properly set)\n"))
818 ui.write(_(" (check that your locale is properly set)\n"))
819 problems += 1
819 problems += 1
820
820
821 # compiled modules
821 # compiled modules
822 ui.status(_("Checking extensions...\n"))
822 ui.status(_("Checking extensions...\n"))
823 try:
823 try:
824 import bdiff, mpatch, base85
824 import bdiff, mpatch, base85
825 except Exception, inst:
825 except Exception, inst:
826 ui.write(" %s\n" % inst)
826 ui.write(" %s\n" % inst)
827 ui.write(_(" One or more extensions could not be found"))
827 ui.write(_(" One or more extensions could not be found"))
828 ui.write(_(" (check that you compiled the extensions)\n"))
828 ui.write(_(" (check that you compiled the extensions)\n"))
829 problems += 1
829 problems += 1
830
830
831 # templates
831 # templates
832 ui.status(_("Checking templates...\n"))
832 ui.status(_("Checking templates...\n"))
833 try:
833 try:
834 import templater
834 import templater
835 t = templater.templater(templater.templatepath("map-cmdline.default"))
835 t = templater.templater(templater.templatepath("map-cmdline.default"))
836 except Exception, inst:
836 except Exception, inst:
837 ui.write(" %s\n" % inst)
837 ui.write(" %s\n" % inst)
838 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
838 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
839 problems += 1
839 problems += 1
840
840
841 # patch
841 # patch
842 ui.status(_("Checking patch...\n"))
842 ui.status(_("Checking patch...\n"))
843 patchproblems = 0
843 patchproblems = 0
844 a = "1\n2\n3\n4\n"
844 a = "1\n2\n3\n4\n"
845 b = "1\n2\n3\ninsert\n4\n"
845 b = "1\n2\n3\ninsert\n4\n"
846 fa = writetemp(a)
846 fa = writetemp(a)
847 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
847 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
848 os.path.basename(fa))
848 os.path.basename(fa))
849 fd = writetemp(d)
849 fd = writetemp(d)
850
850
851 files = {}
851 files = {}
852 try:
852 try:
853 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
853 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
854 except util.Abort, e:
854 except util.Abort, e:
855 ui.write(_(" patch call failed:\n"))
855 ui.write(_(" patch call failed:\n"))
856 ui.write(" " + str(e) + "\n")
856 ui.write(" " + str(e) + "\n")
857 patchproblems += 1
857 patchproblems += 1
858 else:
858 else:
859 if list(files) != [os.path.basename(fa)]:
859 if list(files) != [os.path.basename(fa)]:
860 ui.write(_(" unexpected patch output!\n"))
860 ui.write(_(" unexpected patch output!\n"))
861 patchproblems += 1
861 patchproblems += 1
862 a = file(fa).read()
862 a = file(fa).read()
863 if a != b:
863 if a != b:
864 ui.write(_(" patch test failed!\n"))
864 ui.write(_(" patch test failed!\n"))
865 patchproblems += 1
865 patchproblems += 1
866
866
867 if patchproblems:
867 if patchproblems:
868 if ui.config('ui', 'patch'):
868 if ui.config('ui', 'patch'):
869 ui.write(_(" (Current patch tool may be incompatible with patch,"
869 ui.write(_(" (Current patch tool may be incompatible with patch,"
870 " or misconfigured. Please check your .hgrc file)\n"))
870 " or misconfigured. Please check your .hgrc file)\n"))
871 else:
871 else:
872 ui.write(_(" Internal patcher failure, please report this error"
872 ui.write(_(" Internal patcher failure, please report this error"
873 " to http://www.selenic.com/mercurial/bts\n"))
873 " to http://www.selenic.com/mercurial/bts\n"))
874 problems += patchproblems
874 problems += patchproblems
875
875
876 os.unlink(fa)
876 os.unlink(fa)
877 os.unlink(fd)
877 os.unlink(fd)
878
878
879 # editor
879 # editor
880 ui.status(_("Checking commit editor...\n"))
880 ui.status(_("Checking commit editor...\n"))
881 editor = ui.geteditor()
881 editor = ui.geteditor()
882 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
882 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
883 if not cmdpath:
883 if not cmdpath:
884 if editor == 'vi':
884 if editor == 'vi':
885 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
885 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
886 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
886 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
887 else:
887 else:
888 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
888 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
889 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
889 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
890 problems += 1
890 problems += 1
891
891
892 # check username
892 # check username
893 ui.status(_("Checking username...\n"))
893 ui.status(_("Checking username...\n"))
894 user = os.environ.get("HGUSER")
894 user = os.environ.get("HGUSER")
895 if user is None:
895 if user is None:
896 user = ui.config("ui", "username")
896 user = ui.config("ui", "username")
897 if user is None:
897 if user is None:
898 user = os.environ.get("EMAIL")
898 user = os.environ.get("EMAIL")
899 if not user:
899 if not user:
900 ui.warn(" ")
900 ui.warn(" ")
901 ui.username()
901 ui.username()
902 ui.write(_(" (specify a username in your .hgrc file)\n"))
902 ui.write(_(" (specify a username in your .hgrc file)\n"))
903
903
904 if not problems:
904 if not problems:
905 ui.status(_("No problems detected\n"))
905 ui.status(_("No problems detected\n"))
906 else:
906 else:
907 ui.write(_("%s problems detected,"
907 ui.write(_("%s problems detected,"
908 " please check your install!\n") % problems)
908 " please check your install!\n") % problems)
909
909
910 return problems
910 return problems
911
911
912 def debugrename(ui, repo, file1, *pats, **opts):
912 def debugrename(ui, repo, file1, *pats, **opts):
913 """dump rename information"""
913 """dump rename information"""
914
914
915 ctx = repo.changectx(opts.get('rev', 'tip'))
915 ctx = repo.changectx(opts.get('rev', 'tip'))
916 m = cmdutil.match(repo, (file1,) + pats, opts)
916 m = cmdutil.match(repo, (file1,) + pats, opts)
917 for abs in repo.walk(m, ctx.node()):
917 for abs in repo.walk(m, ctx.node()):
918 fctx = ctx.filectx(abs)
918 fctx = ctx.filectx(abs)
919 o = fctx.filelog().renamed(fctx.filenode())
919 o = fctx.filelog().renamed(fctx.filenode())
920 rel = m.rel(abs)
920 rel = m.rel(abs)
921 if o:
921 if o:
922 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
922 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
923 else:
923 else:
924 ui.write(_("%s not renamed\n") % rel)
924 ui.write(_("%s not renamed\n") % rel)
925
925
926 def debugwalk(ui, repo, *pats, **opts):
926 def debugwalk(ui, repo, *pats, **opts):
927 """show how files match on given patterns"""
927 """show how files match on given patterns"""
928 m = cmdutil.match(repo, pats, opts)
928 m = cmdutil.match(repo, pats, opts)
929 items = list(repo.walk(m))
929 items = list(repo.walk(m))
930 if not items:
930 if not items:
931 return
931 return
932 fmt = 'f %%-%ds %%-%ds %%s' % (
932 fmt = 'f %%-%ds %%-%ds %%s' % (
933 max([len(abs) for abs in items]),
933 max([len(abs) for abs in items]),
934 max([len(m.rel(abs)) for abs in items]))
934 max([len(m.rel(abs)) for abs in items]))
935 for abs in items:
935 for abs in items:
936 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
936 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
937 ui.write("%s\n" % line.rstrip())
937 ui.write("%s\n" % line.rstrip())
938
938
939 def diff(ui, repo, *pats, **opts):
939 def diff(ui, repo, *pats, **opts):
940 """diff repository (or selected files)
940 """diff repository (or selected files)
941
941
942 Show differences between revisions for the specified files.
942 Show differences between revisions for the specified files.
943
943
944 Differences between files are shown using the unified diff format.
944 Differences between files are shown using the unified diff format.
945
945
946 NOTE: diff may generate unexpected results for merges, as it will
946 NOTE: diff may generate unexpected results for merges, as it will
947 default to comparing against the working directory's first parent
947 default to comparing against the working directory's first parent
948 changeset if no revisions are specified.
948 changeset if no revisions are specified.
949
949
950 When two revision arguments are given, then changes are shown
950 When two revision arguments are given, then changes are shown
951 between those revisions. If only one revision is specified then
951 between those revisions. If only one revision is specified then
952 that revision is compared to the working directory, and, when no
952 that revision is compared to the working directory, and, when no
953 revisions are specified, the working directory files are compared
953 revisions are specified, the working directory files are compared
954 to its parent.
954 to its parent.
955
955
956 Without the -a option, diff will avoid generating diffs of files
956 Without the -a option, diff will avoid generating diffs of files
957 it detects as binary. With -a, diff will generate a diff anyway,
957 it detects as binary. With -a, diff will generate a diff anyway,
958 probably with undesirable results.
958 probably with undesirable results.
959 """
959 """
960 node1, node2 = cmdutil.revpair(repo, opts['rev'])
960 node1, node2 = cmdutil.revpair(repo, opts['rev'])
961
961
962 m = cmdutil.match(repo, pats, opts)
962 m = cmdutil.match(repo, pats, opts)
963 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
963 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
964
964
965 def export(ui, repo, *changesets, **opts):
965 def export(ui, repo, *changesets, **opts):
966 """dump the header and diffs for one or more changesets
966 """dump the header and diffs for one or more changesets
967
967
968 Print the changeset header and diffs for one or more revisions.
968 Print the changeset header and diffs for one or more revisions.
969
969
970 The information shown in the changeset header is: author,
970 The information shown in the changeset header is: author,
971 changeset hash, parent(s) and commit comment.
971 changeset hash, parent(s) and commit comment.
972
972
973 NOTE: export may generate unexpected diff output for merge changesets,
973 NOTE: export may generate unexpected diff output for merge changesets,
974 as it will compare the merge changeset against its first parent only.
974 as it will compare the merge changeset against its first parent only.
975
975
976 Output may be to a file, in which case the name of the file is
976 Output may be to a file, in which case the name of the file is
977 given using a format string. The formatting rules are as follows:
977 given using a format string. The formatting rules are as follows:
978
978
979 %% literal "%" character
979 %% literal "%" character
980 %H changeset hash (40 bytes of hexadecimal)
980 %H changeset hash (40 bytes of hexadecimal)
981 %N number of patches being generated
981 %N number of patches being generated
982 %R changeset revision number
982 %R changeset revision number
983 %b basename of the exporting repository
983 %b basename of the exporting repository
984 %h short-form changeset hash (12 bytes of hexadecimal)
984 %h short-form changeset hash (12 bytes of hexadecimal)
985 %n zero-padded sequence number, starting at 1
985 %n zero-padded sequence number, starting at 1
986 %r zero-padded changeset revision number
986 %r zero-padded changeset revision number
987
987
988 Without the -a option, export will avoid generating diffs of files
988 Without the -a option, export will avoid generating diffs of files
989 it detects as binary. With -a, export will generate a diff anyway,
989 it detects as binary. With -a, export will generate a diff anyway,
990 probably with undesirable results.
990 probably with undesirable results.
991
991
992 With the --switch-parent option, the diff will be against the second
992 With the --switch-parent option, the diff will be against the second
993 parent. It can be useful to review a merge.
993 parent. It can be useful to review a merge.
994 """
994 """
995 if not changesets:
995 if not changesets:
996 raise util.Abort(_("export requires at least one changeset"))
996 raise util.Abort(_("export requires at least one changeset"))
997 revs = cmdutil.revrange(repo, changesets)
997 revs = cmdutil.revrange(repo, changesets)
998 if len(revs) > 1:
998 if len(revs) > 1:
999 ui.note(_('exporting patches:\n'))
999 ui.note(_('exporting patches:\n'))
1000 else:
1000 else:
1001 ui.note(_('exporting patch:\n'))
1001 ui.note(_('exporting patch:\n'))
1002 patch.export(repo, revs, template=opts['output'],
1002 patch.export(repo, revs, template=opts['output'],
1003 switch_parent=opts['switch_parent'],
1003 switch_parent=opts['switch_parent'],
1004 opts=patch.diffopts(ui, opts))
1004 opts=patch.diffopts(ui, opts))
1005
1005
1006 def grep(ui, repo, pattern, *pats, **opts):
1006 def grep(ui, repo, pattern, *pats, **opts):
1007 """search for a pattern in specified files and revisions
1007 """search for a pattern in specified files and revisions
1008
1008
1009 Search revisions of files for a regular expression.
1009 Search revisions of files for a regular expression.
1010
1010
1011 This command behaves differently than Unix grep. It only accepts
1011 This command behaves differently than Unix grep. It only accepts
1012 Python/Perl regexps. It searches repository history, not the
1012 Python/Perl regexps. It searches repository history, not the
1013 working directory. It always prints the revision number in which
1013 working directory. It always prints the revision number in which
1014 a match appears.
1014 a match appears.
1015
1015
1016 By default, grep only prints output for the first revision of a
1016 By default, grep only prints output for the first revision of a
1017 file in which it finds a match. To get it to print every revision
1017 file in which it finds a match. To get it to print every revision
1018 that contains a change in match status ("-" for a match that
1018 that contains a change in match status ("-" for a match that
1019 becomes a non-match, or "+" for a non-match that becomes a match),
1019 becomes a non-match, or "+" for a non-match that becomes a match),
1020 use the --all flag.
1020 use the --all flag.
1021 """
1021 """
1022 reflags = 0
1022 reflags = 0
1023 if opts['ignore_case']:
1023 if opts['ignore_case']:
1024 reflags |= re.I
1024 reflags |= re.I
1025 try:
1025 try:
1026 regexp = re.compile(pattern, reflags)
1026 regexp = re.compile(pattern, reflags)
1027 except Exception, inst:
1027 except Exception, inst:
1028 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1028 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1029 return None
1029 return None
1030 sep, eol = ':', '\n'
1030 sep, eol = ':', '\n'
1031 if opts['print0']:
1031 if opts['print0']:
1032 sep = eol = '\0'
1032 sep = eol = '\0'
1033
1033
1034 fcache = {}
1034 fcache = {}
1035 def getfile(fn):
1035 def getfile(fn):
1036 if fn not in fcache:
1036 if fn not in fcache:
1037 fcache[fn] = repo.file(fn)
1037 fcache[fn] = repo.file(fn)
1038 return fcache[fn]
1038 return fcache[fn]
1039
1039
1040 def matchlines(body):
1040 def matchlines(body):
1041 begin = 0
1041 begin = 0
1042 linenum = 0
1042 linenum = 0
1043 while True:
1043 while True:
1044 match = regexp.search(body, begin)
1044 match = regexp.search(body, begin)
1045 if not match:
1045 if not match:
1046 break
1046 break
1047 mstart, mend = match.span()
1047 mstart, mend = match.span()
1048 linenum += body.count('\n', begin, mstart) + 1
1048 linenum += body.count('\n', begin, mstart) + 1
1049 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1049 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1050 lend = body.find('\n', mend)
1050 lend = body.find('\n', mend)
1051 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1051 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1052 begin = lend + 1
1052 begin = lend + 1
1053
1053
1054 class linestate(object):
1054 class linestate(object):
1055 def __init__(self, line, linenum, colstart, colend):
1055 def __init__(self, line, linenum, colstart, colend):
1056 self.line = line
1056 self.line = line
1057 self.linenum = linenum
1057 self.linenum = linenum
1058 self.colstart = colstart
1058 self.colstart = colstart
1059 self.colend = colend
1059 self.colend = colend
1060
1060
1061 def __hash__(self):
1061 def __hash__(self):
1062 return hash((self.linenum, self.line))
1062 return hash((self.linenum, self.line))
1063
1063
1064 def __eq__(self, other):
1064 def __eq__(self, other):
1065 return self.line == other.line
1065 return self.line == other.line
1066
1066
1067 matches = {}
1067 matches = {}
1068 copies = {}
1068 copies = {}
1069 def grepbody(fn, rev, body):
1069 def grepbody(fn, rev, body):
1070 matches[rev].setdefault(fn, [])
1070 matches[rev].setdefault(fn, [])
1071 m = matches[rev][fn]
1071 m = matches[rev][fn]
1072 for lnum, cstart, cend, line in matchlines(body):
1072 for lnum, cstart, cend, line in matchlines(body):
1073 s = linestate(line, lnum, cstart, cend)
1073 s = linestate(line, lnum, cstart, cend)
1074 m.append(s)
1074 m.append(s)
1075
1075
1076 def difflinestates(a, b):
1076 def difflinestates(a, b):
1077 sm = difflib.SequenceMatcher(None, a, b)
1077 sm = difflib.SequenceMatcher(None, a, b)
1078 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1078 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1079 if tag == 'insert':
1079 if tag == 'insert':
1080 for i in xrange(blo, bhi):
1080 for i in xrange(blo, bhi):
1081 yield ('+', b[i])
1081 yield ('+', b[i])
1082 elif tag == 'delete':
1082 elif tag == 'delete':
1083 for i in xrange(alo, ahi):
1083 for i in xrange(alo, ahi):
1084 yield ('-', a[i])
1084 yield ('-', a[i])
1085 elif tag == 'replace':
1085 elif tag == 'replace':
1086 for i in xrange(alo, ahi):
1086 for i in xrange(alo, ahi):
1087 yield ('-', a[i])
1087 yield ('-', a[i])
1088 for i in xrange(blo, bhi):
1088 for i in xrange(blo, bhi):
1089 yield ('+', b[i])
1089 yield ('+', b[i])
1090
1090
1091 prev = {}
1091 prev = {}
1092 def display(fn, rev, states, prevstates):
1092 def display(fn, rev, states, prevstates):
1093 datefunc = ui.quiet and util.shortdate or util.datestr
1093 datefunc = ui.quiet and util.shortdate or util.datestr
1094 found = False
1094 found = False
1095 filerevmatches = {}
1095 filerevmatches = {}
1096 r = prev.get(fn, -1)
1096 r = prev.get(fn, -1)
1097 if opts['all']:
1097 if opts['all']:
1098 iter = difflinestates(states, prevstates)
1098 iter = difflinestates(states, prevstates)
1099 else:
1099 else:
1100 iter = [('', l) for l in prevstates]
1100 iter = [('', l) for l in prevstates]
1101 for change, l in iter:
1101 for change, l in iter:
1102 cols = [fn, str(r)]
1102 cols = [fn, str(r)]
1103 if opts['line_number']:
1103 if opts['line_number']:
1104 cols.append(str(l.linenum))
1104 cols.append(str(l.linenum))
1105 if opts['all']:
1105 if opts['all']:
1106 cols.append(change)
1106 cols.append(change)
1107 if opts['user']:
1107 if opts['user']:
1108 cols.append(ui.shortuser(get(r)[1]))
1108 cols.append(ui.shortuser(get(r)[1]))
1109 if opts.get('date'):
1109 if opts.get('date'):
1110 cols.append(datefunc(get(r)[2]))
1110 cols.append(datefunc(get(r)[2]))
1111 if opts['files_with_matches']:
1111 if opts['files_with_matches']:
1112 c = (fn, r)
1112 c = (fn, r)
1113 if c in filerevmatches:
1113 if c in filerevmatches:
1114 continue
1114 continue
1115 filerevmatches[c] = 1
1115 filerevmatches[c] = 1
1116 else:
1116 else:
1117 cols.append(l.line)
1117 cols.append(l.line)
1118 ui.write(sep.join(cols), eol)
1118 ui.write(sep.join(cols), eol)
1119 found = True
1119 found = True
1120 return found
1120 return found
1121
1121
1122 fstate = {}
1122 fstate = {}
1123 skip = {}
1123 skip = {}
1124 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1124 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1125 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1125 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1126 found = False
1126 found = False
1127 follow = opts.get('follow')
1127 follow = opts.get('follow')
1128 for st, rev, fns in changeiter:
1128 for st, rev, fns in changeiter:
1129 if st == 'window':
1129 if st == 'window':
1130 matches.clear()
1130 matches.clear()
1131 elif st == 'add':
1131 elif st == 'add':
1132 ctx = repo.changectx(rev)
1132 ctx = repo.changectx(rev)
1133 matches[rev] = {}
1133 matches[rev] = {}
1134 for fn in fns:
1134 for fn in fns:
1135 if fn in skip:
1135 if fn in skip:
1136 continue
1136 continue
1137 try:
1137 try:
1138 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1138 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1139 fstate.setdefault(fn, [])
1139 fstate.setdefault(fn, [])
1140 if follow:
1140 if follow:
1141 copied = getfile(fn).renamed(ctx.filenode(fn))
1141 copied = getfile(fn).renamed(ctx.filenode(fn))
1142 if copied:
1142 if copied:
1143 copies.setdefault(rev, {})[fn] = copied[0]
1143 copies.setdefault(rev, {})[fn] = copied[0]
1144 except revlog.LookupError:
1144 except revlog.LookupError:
1145 pass
1145 pass
1146 elif st == 'iter':
1146 elif st == 'iter':
1147 states = matches[rev].items()
1147 states = matches[rev].items()
1148 states.sort()
1148 states.sort()
1149 for fn, m in states:
1149 for fn, m in states:
1150 copy = copies.get(rev, {}).get(fn)
1150 copy = copies.get(rev, {}).get(fn)
1151 if fn in skip:
1151 if fn in skip:
1152 if copy:
1152 if copy:
1153 skip[copy] = True
1153 skip[copy] = True
1154 continue
1154 continue
1155 if fn in prev or fstate[fn]:
1155 if fn in prev or fstate[fn]:
1156 r = display(fn, rev, m, fstate[fn])
1156 r = display(fn, rev, m, fstate[fn])
1157 found = found or r
1157 found = found or r
1158 if r and not opts['all']:
1158 if r and not opts['all']:
1159 skip[fn] = True
1159 skip[fn] = True
1160 if copy:
1160 if copy:
1161 skip[copy] = True
1161 skip[copy] = True
1162 fstate[fn] = m
1162 fstate[fn] = m
1163 if copy:
1163 if copy:
1164 fstate[copy] = m
1164 fstate[copy] = m
1165 prev[fn] = rev
1165 prev[fn] = rev
1166
1166
1167 fstate = fstate.items()
1167 fstate = fstate.items()
1168 fstate.sort()
1168 fstate.sort()
1169 for fn, state in fstate:
1169 for fn, state in fstate:
1170 if fn in skip:
1170 if fn in skip:
1171 continue
1171 continue
1172 if fn not in copies.get(prev[fn], {}):
1172 if fn not in copies.get(prev[fn], {}):
1173 found = display(fn, rev, {}, state) or found
1173 found = display(fn, rev, {}, state) or found
1174 return (not found and 1) or 0
1174 return (not found and 1) or 0
1175
1175
1176 def heads(ui, repo, *branchrevs, **opts):
1176 def heads(ui, repo, *branchrevs, **opts):
1177 """show current repository heads or show branch heads
1177 """show current repository heads or show branch heads
1178
1178
1179 With no arguments, show all repository head changesets.
1179 With no arguments, show all repository head changesets.
1180
1180
1181 If branch or revisions names are given this will show the heads of
1181 If branch or revisions names are given this will show the heads of
1182 the specified branches or the branches those revisions are tagged
1182 the specified branches or the branches those revisions are tagged
1183 with.
1183 with.
1184
1184
1185 Repository "heads" are changesets that don't have child
1185 Repository "heads" are changesets that don't have child
1186 changesets. They are where development generally takes place and
1186 changesets. They are where development generally takes place and
1187 are the usual targets for update and merge operations.
1187 are the usual targets for update and merge operations.
1188
1188
1189 Branch heads are changesets that have a given branch tag, but have
1189 Branch heads are changesets that have a given branch tag, but have
1190 no child changesets with that tag. They are usually where
1190 no child changesets with that tag. They are usually where
1191 development on the given branch takes place.
1191 development on the given branch takes place.
1192 """
1192 """
1193 if opts['rev']:
1193 if opts['rev']:
1194 start = repo.lookup(opts['rev'])
1194 start = repo.lookup(opts['rev'])
1195 else:
1195 else:
1196 start = None
1196 start = None
1197 if not branchrevs:
1197 if not branchrevs:
1198 # Assume we're looking repo-wide heads if no revs were specified.
1198 # Assume we're looking repo-wide heads if no revs were specified.
1199 heads = repo.heads(start)
1199 heads = repo.heads(start)
1200 else:
1200 else:
1201 heads = []
1201 heads = []
1202 visitedset = util.set()
1202 visitedset = util.set()
1203 for branchrev in branchrevs:
1203 for branchrev in branchrevs:
1204 branch = repo.changectx(branchrev).branch()
1204 branch = repo.changectx(branchrev).branch()
1205 if branch in visitedset:
1205 if branch in visitedset:
1206 continue
1206 continue
1207 visitedset.add(branch)
1207 visitedset.add(branch)
1208 bheads = repo.branchheads(branch, start)
1208 bheads = repo.branchheads(branch, start)
1209 if not bheads:
1209 if not bheads:
1210 if branch != branchrev:
1210 if branch != branchrev:
1211 ui.warn(_("no changes on branch %s containing %s are "
1211 ui.warn(_("no changes on branch %s containing %s are "
1212 "reachable from %s\n")
1212 "reachable from %s\n")
1213 % (branch, branchrev, opts['rev']))
1213 % (branch, branchrev, opts['rev']))
1214 else:
1214 else:
1215 ui.warn(_("no changes on branch %s are reachable from %s\n")
1215 ui.warn(_("no changes on branch %s are reachable from %s\n")
1216 % (branch, opts['rev']))
1216 % (branch, opts['rev']))
1217 heads.extend(bheads)
1217 heads.extend(bheads)
1218 if not heads:
1218 if not heads:
1219 return 1
1219 return 1
1220 displayer = cmdutil.show_changeset(ui, repo, opts)
1220 displayer = cmdutil.show_changeset(ui, repo, opts)
1221 for n in heads:
1221 for n in heads:
1222 displayer.show(changenode=n)
1222 displayer.show(changenode=n)
1223
1223
1224 def help_(ui, name=None, with_version=False):
1224 def help_(ui, name=None, with_version=False):
1225 """show help for a command, extension, or list of commands
1225 """show help for a command, extension, or list of commands
1226
1226
1227 With no arguments, print a list of commands and short help.
1227 With no arguments, print a list of commands and short help.
1228
1228
1229 Given a command name, print help for that command.
1229 Given a command name, print help for that command.
1230
1230
1231 Given an extension name, print help for that extension, and the
1231 Given an extension name, print help for that extension, and the
1232 commands it provides."""
1232 commands it provides."""
1233 option_lists = []
1233 option_lists = []
1234
1234
1235 def addglobalopts(aliases):
1235 def addglobalopts(aliases):
1236 if ui.verbose:
1236 if ui.verbose:
1237 option_lists.append((_("global options:"), globalopts))
1237 option_lists.append((_("global options:"), globalopts))
1238 if name == 'shortlist':
1238 if name == 'shortlist':
1239 option_lists.append((_('use "hg help" for the full list '
1239 option_lists.append((_('use "hg help" for the full list '
1240 'of commands'), ()))
1240 'of commands'), ()))
1241 else:
1241 else:
1242 if name == 'shortlist':
1242 if name == 'shortlist':
1243 msg = _('use "hg help" for the full list of commands '
1243 msg = _('use "hg help" for the full list of commands '
1244 'or "hg -v" for details')
1244 'or "hg -v" for details')
1245 elif aliases:
1245 elif aliases:
1246 msg = _('use "hg -v help%s" to show aliases and '
1246 msg = _('use "hg -v help%s" to show aliases and '
1247 'global options') % (name and " " + name or "")
1247 'global options') % (name and " " + name or "")
1248 else:
1248 else:
1249 msg = _('use "hg -v help %s" to show global options') % name
1249 msg = _('use "hg -v help %s" to show global options') % name
1250 option_lists.append((msg, ()))
1250 option_lists.append((msg, ()))
1251
1251
1252 def helpcmd(name):
1252 def helpcmd(name):
1253 if with_version:
1253 if with_version:
1254 version_(ui)
1254 version_(ui)
1255 ui.write('\n')
1255 ui.write('\n')
1256
1256
1257 try:
1257 try:
1258 aliases, i = cmdutil.findcmd(ui, name, table)
1258 aliases, i = cmdutil.findcmd(ui, name, table)
1259 except cmdutil.AmbiguousCommand, inst:
1259 except cmdutil.AmbiguousCommand, inst:
1260 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1260 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1261 helplist(_('list of commands:\n\n'), select)
1261 helplist(_('list of commands:\n\n'), select)
1262 return
1262 return
1263
1263
1264 # synopsis
1264 # synopsis
1265 ui.write("%s\n" % i[2])
1265 ui.write("%s\n" % i[2])
1266
1266
1267 # aliases
1267 # aliases
1268 if not ui.quiet and len(aliases) > 1:
1268 if not ui.quiet and len(aliases) > 1:
1269 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1269 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1270
1270
1271 # description
1271 # description
1272 doc = i[0].__doc__
1272 doc = i[0].__doc__
1273 if not doc:
1273 if not doc:
1274 doc = _("(No help text available)")
1274 doc = _("(No help text available)")
1275 if ui.quiet:
1275 if ui.quiet:
1276 doc = doc.splitlines(0)[0]
1276 doc = doc.splitlines(0)[0]
1277 ui.write("\n%s\n" % doc.rstrip())
1277 ui.write("\n%s\n" % doc.rstrip())
1278
1278
1279 if not ui.quiet:
1279 if not ui.quiet:
1280 # options
1280 # options
1281 if i[1]:
1281 if i[1]:
1282 option_lists.append((_("options:\n"), i[1]))
1282 option_lists.append((_("options:\n"), i[1]))
1283
1283
1284 addglobalopts(False)
1284 addglobalopts(False)
1285
1285
1286 def helplist(header, select=None):
1286 def helplist(header, select=None):
1287 h = {}
1287 h = {}
1288 cmds = {}
1288 cmds = {}
1289 for c, e in table.items():
1289 for c, e in table.items():
1290 f = c.split("|", 1)[0]
1290 f = c.split("|", 1)[0]
1291 if select and not select(f):
1291 if select and not select(f):
1292 continue
1292 continue
1293 if name == "shortlist" and not f.startswith("^"):
1293 if name == "shortlist" and not f.startswith("^"):
1294 continue
1294 continue
1295 f = f.lstrip("^")
1295 f = f.lstrip("^")
1296 if not ui.debugflag and f.startswith("debug"):
1296 if not ui.debugflag and f.startswith("debug"):
1297 continue
1297 continue
1298 doc = e[0].__doc__
1298 doc = e[0].__doc__
1299 if not doc:
1299 if not doc:
1300 doc = _("(No help text available)")
1300 doc = _("(No help text available)")
1301 h[f] = doc.splitlines(0)[0].rstrip()
1301 h[f] = doc.splitlines(0)[0].rstrip()
1302 cmds[f] = c.lstrip("^")
1302 cmds[f] = c.lstrip("^")
1303
1303
1304 if not h:
1304 if not h:
1305 ui.status(_('no commands defined\n'))
1305 ui.status(_('no commands defined\n'))
1306 return
1306 return
1307
1307
1308 ui.status(header)
1308 ui.status(header)
1309 fns = h.keys()
1309 fns = h.keys()
1310 fns.sort()
1310 fns.sort()
1311 m = max(map(len, fns))
1311 m = max(map(len, fns))
1312 for f in fns:
1312 for f in fns:
1313 if ui.verbose:
1313 if ui.verbose:
1314 commands = cmds[f].replace("|",", ")
1314 commands = cmds[f].replace("|",", ")
1315 ui.write(" %s:\n %s\n"%(commands, h[f]))
1315 ui.write(" %s:\n %s\n"%(commands, h[f]))
1316 else:
1316 else:
1317 ui.write(' %-*s %s\n' % (m, f, h[f]))
1317 ui.write(' %-*s %s\n' % (m, f, h[f]))
1318
1318
1319 if not ui.quiet:
1319 if not ui.quiet:
1320 addglobalopts(True)
1320 addglobalopts(True)
1321
1321
1322 def helptopic(name):
1322 def helptopic(name):
1323 v = None
1323 v = None
1324 for i, d in help.helptable:
1324 for i, d in help.helptable:
1325 l = i.split('|')
1325 l = i.split('|')
1326 if name in l:
1326 if name in l:
1327 v = i
1327 v = i
1328 header = l[-1]
1328 header = l[-1]
1329 doc = d
1329 doc = d
1330 if not v:
1330 if not v:
1331 raise cmdutil.UnknownCommand(name)
1331 raise cmdutil.UnknownCommand(name)
1332
1332
1333 # description
1333 # description
1334 if not doc:
1334 if not doc:
1335 doc = _("(No help text available)")
1335 doc = _("(No help text available)")
1336 if callable(doc):
1336 if callable(doc):
1337 doc = doc()
1337 doc = doc()
1338
1338
1339 ui.write("%s\n" % header)
1339 ui.write("%s\n" % header)
1340 ui.write("%s\n" % doc.rstrip())
1340 ui.write("%s\n" % doc.rstrip())
1341
1341
1342 def helpext(name):
1342 def helpext(name):
1343 try:
1343 try:
1344 mod = extensions.find(name)
1344 mod = extensions.find(name)
1345 except KeyError:
1345 except KeyError:
1346 raise cmdutil.UnknownCommand(name)
1346 raise cmdutil.UnknownCommand(name)
1347
1347
1348 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1348 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1349 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1349 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1350 for d in doc[1:]:
1350 for d in doc[1:]:
1351 ui.write(d, '\n')
1351 ui.write(d, '\n')
1352
1352
1353 ui.status('\n')
1353 ui.status('\n')
1354
1354
1355 try:
1355 try:
1356 ct = mod.cmdtable
1356 ct = mod.cmdtable
1357 except AttributeError:
1357 except AttributeError:
1358 ct = {}
1358 ct = {}
1359
1359
1360 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1360 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1361 helplist(_('list of commands:\n\n'), modcmds.has_key)
1361 helplist(_('list of commands:\n\n'), modcmds.has_key)
1362
1362
1363 if name and name != 'shortlist':
1363 if name and name != 'shortlist':
1364 i = None
1364 i = None
1365 for f in (helpcmd, helptopic, helpext):
1365 for f in (helpcmd, helptopic, helpext):
1366 try:
1366 try:
1367 f(name)
1367 f(name)
1368 i = None
1368 i = None
1369 break
1369 break
1370 except cmdutil.UnknownCommand, inst:
1370 except cmdutil.UnknownCommand, inst:
1371 i = inst
1371 i = inst
1372 if i:
1372 if i:
1373 raise i
1373 raise i
1374
1374
1375 else:
1375 else:
1376 # program name
1376 # program name
1377 if ui.verbose or with_version:
1377 if ui.verbose or with_version:
1378 version_(ui)
1378 version_(ui)
1379 else:
1379 else:
1380 ui.status(_("Mercurial Distributed SCM\n"))
1380 ui.status(_("Mercurial Distributed SCM\n"))
1381 ui.status('\n')
1381 ui.status('\n')
1382
1382
1383 # list of commands
1383 # list of commands
1384 if name == "shortlist":
1384 if name == "shortlist":
1385 header = _('basic commands:\n\n')
1385 header = _('basic commands:\n\n')
1386 else:
1386 else:
1387 header = _('list of commands:\n\n')
1387 header = _('list of commands:\n\n')
1388
1388
1389 helplist(header)
1389 helplist(header)
1390
1390
1391 # list all option lists
1391 # list all option lists
1392 opt_output = []
1392 opt_output = []
1393 for title, options in option_lists:
1393 for title, options in option_lists:
1394 opt_output.append(("\n%s" % title, None))
1394 opt_output.append(("\n%s" % title, None))
1395 for shortopt, longopt, default, desc in options:
1395 for shortopt, longopt, default, desc in options:
1396 if "DEPRECATED" in desc and not ui.verbose: continue
1396 if "DEPRECATED" in desc and not ui.verbose: continue
1397 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1397 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1398 longopt and " --%s" % longopt),
1398 longopt and " --%s" % longopt),
1399 "%s%s" % (desc,
1399 "%s%s" % (desc,
1400 default
1400 default
1401 and _(" (default: %s)") % default
1401 and _(" (default: %s)") % default
1402 or "")))
1402 or "")))
1403
1403
1404 if ui.verbose:
1404 if ui.verbose:
1405 ui.write(_("\nspecial help topics:\n"))
1405 ui.write(_("\nspecial help topics:\n"))
1406 topics = []
1406 topics = []
1407 for i, d in help.helptable:
1407 for i, d in help.helptable:
1408 l = i.split('|')
1408 l = i.split('|')
1409 topics.append((", ".join(l[:-1]), l[-1]))
1409 topics.append((", ".join(l[:-1]), l[-1]))
1410 topics_len = max([len(s[0]) for s in topics])
1410 topics_len = max([len(s[0]) for s in topics])
1411 for t, desc in topics:
1411 for t, desc in topics:
1412 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1412 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1413
1413
1414 if opt_output:
1414 if opt_output:
1415 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1415 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1416 for first, second in opt_output:
1416 for first, second in opt_output:
1417 if second:
1417 if second:
1418 ui.write(" %-*s %s\n" % (opts_len, first, second))
1418 ui.write(" %-*s %s\n" % (opts_len, first, second))
1419 else:
1419 else:
1420 ui.write("%s\n" % first)
1420 ui.write("%s\n" % first)
1421
1421
1422 def identify(ui, repo, source=None,
1422 def identify(ui, repo, source=None,
1423 rev=None, num=None, id=None, branch=None, tags=None):
1423 rev=None, num=None, id=None, branch=None, tags=None):
1424 """identify the working copy or specified revision
1424 """identify the working copy or specified revision
1425
1425
1426 With no revision, print a summary of the current state of the repo.
1426 With no revision, print a summary of the current state of the repo.
1427
1427
1428 With a path, do a lookup in another repository.
1428 With a path, do a lookup in another repository.
1429
1429
1430 This summary identifies the repository state using one or two parent
1430 This summary identifies the repository state using one or two parent
1431 hash identifiers, followed by a "+" if there are uncommitted changes
1431 hash identifiers, followed by a "+" if there are uncommitted changes
1432 in the working directory, a list of tags for this revision and a branch
1432 in the working directory, a list of tags for this revision and a branch
1433 name for non-default branches.
1433 name for non-default branches.
1434 """
1434 """
1435
1435
1436 if not repo and not source:
1436 if not repo and not source:
1437 raise util.Abort(_("There is no Mercurial repository here "
1437 raise util.Abort(_("There is no Mercurial repository here "
1438 "(.hg not found)"))
1438 "(.hg not found)"))
1439
1439
1440 hexfunc = ui.debugflag and hex or short
1440 hexfunc = ui.debugflag and hex or short
1441 default = not (num or id or branch or tags)
1441 default = not (num or id or branch or tags)
1442 output = []
1442 output = []
1443
1443
1444 if source:
1444 if source:
1445 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1445 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1446 srepo = hg.repository(ui, source)
1446 srepo = hg.repository(ui, source)
1447 if not rev and revs:
1447 if not rev and revs:
1448 rev = revs[0]
1448 rev = revs[0]
1449 if not rev:
1449 if not rev:
1450 rev = "tip"
1450 rev = "tip"
1451 if num or branch or tags:
1451 if num or branch or tags:
1452 raise util.Abort(
1452 raise util.Abort(
1453 "can't query remote revision number, branch, or tags")
1453 "can't query remote revision number, branch, or tags")
1454 output = [hexfunc(srepo.lookup(rev))]
1454 output = [hexfunc(srepo.lookup(rev))]
1455 elif not rev:
1455 elif not rev:
1456 ctx = repo.workingctx()
1456 ctx = repo.workingctx()
1457 parents = ctx.parents()
1457 parents = ctx.parents()
1458 changed = False
1458 changed = False
1459 if default or id or num:
1459 if default or id or num:
1460 changed = ctx.files() + ctx.deleted()
1460 changed = ctx.files() + ctx.deleted()
1461 if default or id:
1461 if default or id:
1462 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1462 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1463 (changed) and "+" or "")]
1463 (changed) and "+" or "")]
1464 if num:
1464 if num:
1465 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1465 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1466 (changed) and "+" or ""))
1466 (changed) and "+" or ""))
1467 else:
1467 else:
1468 ctx = repo.changectx(rev)
1468 ctx = repo.changectx(rev)
1469 if default or id:
1469 if default or id:
1470 output = [hexfunc(ctx.node())]
1470 output = [hexfunc(ctx.node())]
1471 if num:
1471 if num:
1472 output.append(str(ctx.rev()))
1472 output.append(str(ctx.rev()))
1473
1473
1474 if not source and default and not ui.quiet:
1474 if not source and default and not ui.quiet:
1475 b = util.tolocal(ctx.branch())
1475 b = util.tolocal(ctx.branch())
1476 if b != 'default':
1476 if b != 'default':
1477 output.append("(%s)" % b)
1477 output.append("(%s)" % b)
1478
1478
1479 # multiple tags for a single parent separated by '/'
1479 # multiple tags for a single parent separated by '/'
1480 t = "/".join(ctx.tags())
1480 t = "/".join(ctx.tags())
1481 if t:
1481 if t:
1482 output.append(t)
1482 output.append(t)
1483
1483
1484 if branch:
1484 if branch:
1485 output.append(util.tolocal(ctx.branch()))
1485 output.append(util.tolocal(ctx.branch()))
1486
1486
1487 if tags:
1487 if tags:
1488 output.extend(ctx.tags())
1488 output.extend(ctx.tags())
1489
1489
1490 ui.write("%s\n" % ' '.join(output))
1490 ui.write("%s\n" % ' '.join(output))
1491
1491
1492 def import_(ui, repo, patch1, *patches, **opts):
1492 def import_(ui, repo, patch1, *patches, **opts):
1493 """import an ordered set of patches
1493 """import an ordered set of patches
1494
1494
1495 Import a list of patches and commit them individually.
1495 Import a list of patches and commit them individually.
1496
1496
1497 If there are outstanding changes in the working directory, import
1497 If there are outstanding changes in the working directory, import
1498 will abort unless given the -f flag.
1498 will abort unless given the -f flag.
1499
1499
1500 You can import a patch straight from a mail message. Even patches
1500 You can import a patch straight from a mail message. Even patches
1501 as attachments work (body part must be type text/plain or
1501 as attachments work (body part must be type text/plain or
1502 text/x-patch to be used). From and Subject headers of email
1502 text/x-patch to be used). From and Subject headers of email
1503 message are used as default committer and commit message. All
1503 message are used as default committer and commit message. All
1504 text/plain body parts before first diff are added to commit
1504 text/plain body parts before first diff are added to commit
1505 message.
1505 message.
1506
1506
1507 If the imported patch was generated by hg export, user and description
1507 If the imported patch was generated by hg export, user and description
1508 from patch override values from message headers and body. Values
1508 from patch override values from message headers and body. Values
1509 given on command line with -m and -u override these.
1509 given on command line with -m and -u override these.
1510
1510
1511 If --exact is specified, import will set the working directory
1511 If --exact is specified, import will set the working directory
1512 to the parent of each patch before applying it, and will abort
1512 to the parent of each patch before applying it, and will abort
1513 if the resulting changeset has a different ID than the one
1513 if the resulting changeset has a different ID than the one
1514 recorded in the patch. This may happen due to character set
1514 recorded in the patch. This may happen due to character set
1515 problems or other deficiencies in the text patch format.
1515 problems or other deficiencies in the text patch format.
1516
1516
1517 To read a patch from standard input, use patch name "-".
1517 To read a patch from standard input, use patch name "-".
1518 See 'hg help dates' for a list of formats valid for -d/--date.
1518 See 'hg help dates' for a list of formats valid for -d/--date.
1519 """
1519 """
1520 patches = (patch1,) + patches
1520 patches = (patch1,) + patches
1521
1521
1522 date = opts.get('date')
1522 date = opts.get('date')
1523 if date:
1523 if date:
1524 opts['date'] = util.parsedate(date)
1524 opts['date'] = util.parsedate(date)
1525
1525
1526 if opts.get('exact') or not opts['force']:
1526 if opts.get('exact') or not opts['force']:
1527 cmdutil.bail_if_changed(repo)
1527 cmdutil.bail_if_changed(repo)
1528
1528
1529 d = opts["base"]
1529 d = opts["base"]
1530 strip = opts["strip"]
1530 strip = opts["strip"]
1531 wlock = lock = None
1531 wlock = lock = None
1532 try:
1532 try:
1533 wlock = repo.wlock()
1533 wlock = repo.wlock()
1534 lock = repo.lock()
1534 lock = repo.lock()
1535 for p in patches:
1535 for p in patches:
1536 pf = os.path.join(d, p)
1536 pf = os.path.join(d, p)
1537
1537
1538 if pf == '-':
1538 if pf == '-':
1539 ui.status(_("applying patch from stdin\n"))
1539 ui.status(_("applying patch from stdin\n"))
1540 data = patch.extract(ui, sys.stdin)
1540 data = patch.extract(ui, sys.stdin)
1541 else:
1541 else:
1542 ui.status(_("applying %s\n") % p)
1542 ui.status(_("applying %s\n") % p)
1543 if os.path.exists(pf):
1543 if os.path.exists(pf):
1544 data = patch.extract(ui, file(pf, 'rb'))
1544 data = patch.extract(ui, file(pf, 'rb'))
1545 else:
1545 else:
1546 data = patch.extract(ui, urllib.urlopen(pf))
1546 data = patch.extract(ui, urllib.urlopen(pf))
1547 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1547 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1548
1548
1549 if tmpname is None:
1549 if tmpname is None:
1550 raise util.Abort(_('no diffs found'))
1550 raise util.Abort(_('no diffs found'))
1551
1551
1552 try:
1552 try:
1553 cmdline_message = cmdutil.logmessage(opts)
1553 cmdline_message = cmdutil.logmessage(opts)
1554 if cmdline_message:
1554 if cmdline_message:
1555 # pickup the cmdline msg
1555 # pickup the cmdline msg
1556 message = cmdline_message
1556 message = cmdline_message
1557 elif message:
1557 elif message:
1558 # pickup the patch msg
1558 # pickup the patch msg
1559 message = message.strip()
1559 message = message.strip()
1560 else:
1560 else:
1561 # launch the editor
1561 # launch the editor
1562 message = None
1562 message = None
1563 ui.debug(_('message:\n%s\n') % message)
1563 ui.debug(_('message:\n%s\n') % message)
1564
1564
1565 wp = repo.workingctx().parents()
1565 wp = repo.workingctx().parents()
1566 if opts.get('exact'):
1566 if opts.get('exact'):
1567 if not nodeid or not p1:
1567 if not nodeid or not p1:
1568 raise util.Abort(_('not a mercurial patch'))
1568 raise util.Abort(_('not a mercurial patch'))
1569 p1 = repo.lookup(p1)
1569 p1 = repo.lookup(p1)
1570 p2 = repo.lookup(p2 or hex(nullid))
1570 p2 = repo.lookup(p2 or hex(nullid))
1571
1571
1572 if p1 != wp[0].node():
1572 if p1 != wp[0].node():
1573 hg.clean(repo, p1)
1573 hg.clean(repo, p1)
1574 repo.dirstate.setparents(p1, p2)
1574 repo.dirstate.setparents(p1, p2)
1575 elif p2:
1575 elif p2:
1576 try:
1576 try:
1577 p1 = repo.lookup(p1)
1577 p1 = repo.lookup(p1)
1578 p2 = repo.lookup(p2)
1578 p2 = repo.lookup(p2)
1579 if p1 == wp[0].node():
1579 if p1 == wp[0].node():
1580 repo.dirstate.setparents(p1, p2)
1580 repo.dirstate.setparents(p1, p2)
1581 except RepoError:
1581 except RepoError:
1582 pass
1582 pass
1583 if opts.get('exact') or opts.get('import_branch'):
1583 if opts.get('exact') or opts.get('import_branch'):
1584 repo.dirstate.setbranch(branch or 'default')
1584 repo.dirstate.setbranch(branch or 'default')
1585
1585
1586 files = {}
1586 files = {}
1587 try:
1587 try:
1588 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1588 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1589 files=files)
1589 files=files)
1590 finally:
1590 finally:
1591 files = patch.updatedir(ui, repo, files)
1591 files = patch.updatedir(ui, repo, files)
1592 if not opts.get('no_commit'):
1592 if not opts.get('no_commit'):
1593 n = repo.commit(files, message, opts.get('user') or user,
1593 n = repo.commit(files, message, opts.get('user') or user,
1594 opts.get('date') or date)
1594 opts.get('date') or date)
1595 if opts.get('exact'):
1595 if opts.get('exact'):
1596 if hex(n) != nodeid:
1596 if hex(n) != nodeid:
1597 repo.rollback()
1597 repo.rollback()
1598 raise util.Abort(_('patch is damaged'
1598 raise util.Abort(_('patch is damaged'
1599 ' or loses information'))
1599 ' or loses information'))
1600 # Force a dirstate write so that the next transaction
1600 # Force a dirstate write so that the next transaction
1601 # backups an up-do-date file.
1601 # backups an up-do-date file.
1602 repo.dirstate.write()
1602 repo.dirstate.write()
1603 finally:
1603 finally:
1604 os.unlink(tmpname)
1604 os.unlink(tmpname)
1605 finally:
1605 finally:
1606 del lock, wlock
1606 del lock, wlock
1607
1607
1608 def incoming(ui, repo, source="default", **opts):
1608 def incoming(ui, repo, source="default", **opts):
1609 """show new changesets found in source
1609 """show new changesets found in source
1610
1610
1611 Show new changesets found in the specified path/URL or the default
1611 Show new changesets found in the specified path/URL or the default
1612 pull location. These are the changesets that would be pulled if a pull
1612 pull location. These are the changesets that would be pulled if a pull
1613 was requested.
1613 was requested.
1614
1614
1615 For remote repository, using --bundle avoids downloading the changesets
1615 For remote repository, using --bundle avoids downloading the changesets
1616 twice if the incoming is followed by a pull.
1616 twice if the incoming is followed by a pull.
1617
1617
1618 See pull for valid source format details.
1618 See pull for valid source format details.
1619 """
1619 """
1620 limit = cmdutil.loglimit(opts)
1620 limit = cmdutil.loglimit(opts)
1621 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1621 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1622 cmdutil.setremoteconfig(ui, opts)
1622 cmdutil.setremoteconfig(ui, opts)
1623
1623
1624 other = hg.repository(ui, source)
1624 other = hg.repository(ui, source)
1625 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1625 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1626 if revs:
1626 if revs:
1627 revs = [other.lookup(rev) for rev in revs]
1627 revs = [other.lookup(rev) for rev in revs]
1628 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1628 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1629 if not incoming:
1629 if not incoming:
1630 try:
1630 try:
1631 os.unlink(opts["bundle"])
1631 os.unlink(opts["bundle"])
1632 except:
1632 except:
1633 pass
1633 pass
1634 ui.status(_("no changes found\n"))
1634 ui.status(_("no changes found\n"))
1635 return 1
1635 return 1
1636
1636
1637 cleanup = None
1637 cleanup = None
1638 try:
1638 try:
1639 fname = opts["bundle"]
1639 fname = opts["bundle"]
1640 if fname or not other.local():
1640 if fname or not other.local():
1641 # create a bundle (uncompressed if other repo is not local)
1641 # create a bundle (uncompressed if other repo is not local)
1642 if revs is None:
1642 if revs is None:
1643 cg = other.changegroup(incoming, "incoming")
1643 cg = other.changegroup(incoming, "incoming")
1644 else:
1644 else:
1645 cg = other.changegroupsubset(incoming, revs, 'incoming')
1645 cg = other.changegroupsubset(incoming, revs, 'incoming')
1646 bundletype = other.local() and "HG10BZ" or "HG10UN"
1646 bundletype = other.local() and "HG10BZ" or "HG10UN"
1647 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1647 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1648 # keep written bundle?
1648 # keep written bundle?
1649 if opts["bundle"]:
1649 if opts["bundle"]:
1650 cleanup = None
1650 cleanup = None
1651 if not other.local():
1651 if not other.local():
1652 # use the created uncompressed bundlerepo
1652 # use the created uncompressed bundlerepo
1653 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1653 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1654
1654
1655 o = other.changelog.nodesbetween(incoming, revs)[0]
1655 o = other.changelog.nodesbetween(incoming, revs)[0]
1656 if opts['newest_first']:
1656 if opts['newest_first']:
1657 o.reverse()
1657 o.reverse()
1658 displayer = cmdutil.show_changeset(ui, other, opts)
1658 displayer = cmdutil.show_changeset(ui, other, opts)
1659 count = 0
1659 count = 0
1660 for n in o:
1660 for n in o:
1661 if count >= limit:
1661 if count >= limit:
1662 break
1662 break
1663 parents = [p for p in other.changelog.parents(n) if p != nullid]
1663 parents = [p for p in other.changelog.parents(n) if p != nullid]
1664 if opts['no_merges'] and len(parents) == 2:
1664 if opts['no_merges'] and len(parents) == 2:
1665 continue
1665 continue
1666 count += 1
1666 count += 1
1667 displayer.show(changenode=n)
1667 displayer.show(changenode=n)
1668 finally:
1668 finally:
1669 if hasattr(other, 'close'):
1669 if hasattr(other, 'close'):
1670 other.close()
1670 other.close()
1671 if cleanup:
1671 if cleanup:
1672 os.unlink(cleanup)
1672 os.unlink(cleanup)
1673
1673
1674 def init(ui, dest=".", **opts):
1674 def init(ui, dest=".", **opts):
1675 """create a new repository in the given directory
1675 """create a new repository in the given directory
1676
1676
1677 Initialize a new repository in the given directory. If the given
1677 Initialize a new repository in the given directory. If the given
1678 directory does not exist, it is created.
1678 directory does not exist, it is created.
1679
1679
1680 If no directory is given, the current directory is used.
1680 If no directory is given, the current directory is used.
1681
1681
1682 It is possible to specify an ssh:// URL as the destination.
1682 It is possible to specify an ssh:// URL as the destination.
1683 Look at the help text for the pull command for important details
1683 Look at the help text for the pull command for important details
1684 about ssh:// URLs.
1684 about ssh:// URLs.
1685 """
1685 """
1686 cmdutil.setremoteconfig(ui, opts)
1686 cmdutil.setremoteconfig(ui, opts)
1687 hg.repository(ui, dest, create=1)
1687 hg.repository(ui, dest, create=1)
1688
1688
1689 def locate(ui, repo, *pats, **opts):
1689 def locate(ui, repo, *pats, **opts):
1690 """locate files matching specific patterns
1690 """locate files matching specific patterns
1691
1691
1692 Print all files under Mercurial control whose names match the
1692 Print all files under Mercurial control whose names match the
1693 given patterns.
1693 given patterns.
1694
1694
1695 This command searches the entire repository by default. To search
1695 This command searches the entire repository by default. To search
1696 just the current directory and its subdirectories, use
1696 just the current directory and its subdirectories, use
1697 "--include .".
1697 "--include .".
1698
1698
1699 If no patterns are given to match, this command prints all file
1699 If no patterns are given to match, this command prints all file
1700 names.
1700 names.
1701
1701
1702 If you want to feed the output of this command into the "xargs"
1702 If you want to feed the output of this command into the "xargs"
1703 command, use the "-0" option to both this command and "xargs".
1703 command, use the "-0" option to both this command and "xargs".
1704 This will avoid the problem of "xargs" treating single filenames
1704 This will avoid the problem of "xargs" treating single filenames
1705 that contain white space as multiple filenames.
1705 that contain white space as multiple filenames.
1706 """
1706 """
1707 end = opts['print0'] and '\0' or '\n'
1707 end = opts['print0'] and '\0' or '\n'
1708 rev = opts['rev']
1708 rev = opts['rev']
1709 if rev:
1709 if rev:
1710 node = repo.lookup(rev)
1710 node = repo.lookup(rev)
1711 else:
1711 else:
1712 node = None
1712 node = None
1713
1713
1714 ret = 1
1714 ret = 1
1715 m = cmdutil.match(repo, pats, opts, default='relglob')
1715 m = cmdutil.match(repo, pats, opts, default='relglob')
1716 m.bad = lambda x,y: False
1716 m.bad = lambda x,y: False
1717 for abs in repo.walk(m, node):
1717 for abs in repo.walk(m, node):
1718 if not node and abs not in repo.dirstate:
1718 if not node and abs not in repo.dirstate:
1719 continue
1719 continue
1720 if opts['fullpath']:
1720 if opts['fullpath']:
1721 ui.write(os.path.join(repo.root, abs), end)
1721 ui.write(os.path.join(repo.root, abs), end)
1722 else:
1722 else:
1723 ui.write(((pats and m.rel(abs)) or abs), end)
1723 ui.write(((pats and m.rel(abs)) or abs), end)
1724 ret = 0
1724 ret = 0
1725
1725
1726 return ret
1726 return ret
1727
1727
1728 def log(ui, repo, *pats, **opts):
1728 def log(ui, repo, *pats, **opts):
1729 """show revision history of entire repository or files
1729 """show revision history of entire repository or files
1730
1730
1731 Print the revision history of the specified files or the entire
1731 Print the revision history of the specified files or the entire
1732 project.
1732 project.
1733
1733
1734 File history is shown without following rename or copy history of
1734 File history is shown without following rename or copy history of
1735 files. Use -f/--follow with a file name to follow history across
1735 files. Use -f/--follow with a file name to follow history across
1736 renames and copies. --follow without a file name will only show
1736 renames and copies. --follow without a file name will only show
1737 ancestors or descendants of the starting revision. --follow-first
1737 ancestors or descendants of the starting revision. --follow-first
1738 only follows the first parent of merge revisions.
1738 only follows the first parent of merge revisions.
1739
1739
1740 If no revision range is specified, the default is tip:0 unless
1740 If no revision range is specified, the default is tip:0 unless
1741 --follow is set, in which case the working directory parent is
1741 --follow is set, in which case the working directory parent is
1742 used as the starting revision.
1742 used as the starting revision.
1743
1743
1744 See 'hg help dates' for a list of formats valid for -d/--date.
1744 See 'hg help dates' for a list of formats valid for -d/--date.
1745
1745
1746 By default this command outputs: changeset id and hash, tags,
1746 By default this command outputs: changeset id and hash, tags,
1747 non-trivial parents, user, date and time, and a summary for each
1747 non-trivial parents, user, date and time, and a summary for each
1748 commit. When the -v/--verbose switch is used, the list of changed
1748 commit. When the -v/--verbose switch is used, the list of changed
1749 files and full commit message is shown.
1749 files and full commit message is shown.
1750
1750
1751 NOTE: log -p may generate unexpected diff output for merge
1751 NOTE: log -p may generate unexpected diff output for merge
1752 changesets, as it will compare the merge changeset against its
1752 changesets, as it will compare the merge changeset against its
1753 first parent only. Also, the files: list will only reflect files
1753 first parent only. Also, the files: list will only reflect files
1754 that are different from BOTH parents.
1754 that are different from BOTH parents.
1755
1755
1756 """
1756 """
1757
1757
1758 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1758 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1759 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1759 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1760
1760
1761 limit = cmdutil.loglimit(opts)
1761 limit = cmdutil.loglimit(opts)
1762 count = 0
1762 count = 0
1763
1763
1764 if opts['copies'] and opts['rev']:
1764 if opts['copies'] and opts['rev']:
1765 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1765 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1766 else:
1766 else:
1767 endrev = repo.changelog.count()
1767 endrev = repo.changelog.count()
1768 rcache = {}
1768 rcache = {}
1769 ncache = {}
1769 ncache = {}
1770 def getrenamed(fn, rev):
1770 def getrenamed(fn, rev):
1771 '''looks up all renames for a file (up to endrev) the first
1771 '''looks up all renames for a file (up to endrev) the first
1772 time the file is given. It indexes on the changerev and only
1772 time the file is given. It indexes on the changerev and only
1773 parses the manifest if linkrev != changerev.
1773 parses the manifest if linkrev != changerev.
1774 Returns rename info for fn at changerev rev.'''
1774 Returns rename info for fn at changerev rev.'''
1775 if fn not in rcache:
1775 if fn not in rcache:
1776 rcache[fn] = {}
1776 rcache[fn] = {}
1777 ncache[fn] = {}
1777 ncache[fn] = {}
1778 fl = repo.file(fn)
1778 fl = repo.file(fn)
1779 for i in xrange(fl.count()):
1779 for i in xrange(fl.count()):
1780 node = fl.node(i)
1780 node = fl.node(i)
1781 lr = fl.linkrev(node)
1781 lr = fl.linkrev(node)
1782 renamed = fl.renamed(node)
1782 renamed = fl.renamed(node)
1783 rcache[fn][lr] = renamed
1783 rcache[fn][lr] = renamed
1784 if renamed:
1784 if renamed:
1785 ncache[fn][node] = renamed
1785 ncache[fn][node] = renamed
1786 if lr >= endrev:
1786 if lr >= endrev:
1787 break
1787 break
1788 if rev in rcache[fn]:
1788 if rev in rcache[fn]:
1789 return rcache[fn][rev]
1789 return rcache[fn][rev]
1790
1790
1791 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1791 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1792 # filectx logic.
1792 # filectx logic.
1793
1793
1794 try:
1794 try:
1795 return repo.changectx(rev).filectx(fn).renamed()
1795 return repo.changectx(rev).filectx(fn).renamed()
1796 except revlog.LookupError:
1796 except revlog.LookupError:
1797 pass
1797 pass
1798 return None
1798 return None
1799
1799
1800 df = False
1800 df = False
1801 if opts["date"]:
1801 if opts["date"]:
1802 df = util.matchdate(opts["date"])
1802 df = util.matchdate(opts["date"])
1803
1803
1804 only_branches = opts['only_branch']
1804 only_branches = opts['only_branch']
1805
1805
1806 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1806 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1807 for st, rev, fns in changeiter:
1807 for st, rev, fns in changeiter:
1808 if st == 'add':
1808 if st == 'add':
1809 changenode = repo.changelog.node(rev)
1809 changenode = repo.changelog.node(rev)
1810 parents = [p for p in repo.changelog.parentrevs(rev)
1810 parents = [p for p in repo.changelog.parentrevs(rev)
1811 if p != nullrev]
1811 if p != nullrev]
1812 if opts['no_merges'] and len(parents) == 2:
1812 if opts['no_merges'] and len(parents) == 2:
1813 continue
1813 continue
1814 if opts['only_merges'] and len(parents) != 2:
1814 if opts['only_merges'] and len(parents) != 2:
1815 continue
1815 continue
1816
1816
1817 if only_branches:
1817 if only_branches:
1818 revbranch = get(rev)[5]['branch']
1818 revbranch = get(rev)[5]['branch']
1819 if revbranch not in only_branches:
1819 if revbranch not in only_branches:
1820 continue
1820 continue
1821
1821
1822 if df:
1822 if df:
1823 changes = get(rev)
1823 changes = get(rev)
1824 if not df(changes[2][0]):
1824 if not df(changes[2][0]):
1825 continue
1825 continue
1826
1826
1827 if opts['keyword']:
1827 if opts['keyword']:
1828 changes = get(rev)
1828 changes = get(rev)
1829 miss = 0
1829 miss = 0
1830 for k in [kw.lower() for kw in opts['keyword']]:
1830 for k in [kw.lower() for kw in opts['keyword']]:
1831 if not (k in changes[1].lower() or
1831 if not (k in changes[1].lower() or
1832 k in changes[4].lower() or
1832 k in changes[4].lower() or
1833 k in " ".join(changes[3]).lower()):
1833 k in " ".join(changes[3]).lower()):
1834 miss = 1
1834 miss = 1
1835 break
1835 break
1836 if miss:
1836 if miss:
1837 continue
1837 continue
1838
1838
1839 copies = []
1839 copies = []
1840 if opts.get('copies') and rev:
1840 if opts.get('copies') and rev:
1841 for fn in get(rev)[3]:
1841 for fn in get(rev)[3]:
1842 rename = getrenamed(fn, rev)
1842 rename = getrenamed(fn, rev)
1843 if rename:
1843 if rename:
1844 copies.append((fn, rename[0]))
1844 copies.append((fn, rename[0]))
1845 displayer.show(rev, changenode, copies=copies)
1845 displayer.show(rev, changenode, copies=copies)
1846 elif st == 'iter':
1846 elif st == 'iter':
1847 if count == limit: break
1847 if count == limit: break
1848 if displayer.flush(rev):
1848 if displayer.flush(rev):
1849 count += 1
1849 count += 1
1850
1850
1851 def manifest(ui, repo, node=None, rev=None):
1851 def manifest(ui, repo, node=None, rev=None):
1852 """output the current or given revision of the project manifest
1852 """output the current or given revision of the project manifest
1853
1853
1854 Print a list of version controlled files for the given revision.
1854 Print a list of version controlled files for the given revision.
1855 If no revision is given, the parent of the working directory is used,
1855 If no revision is given, the parent of the working directory is used,
1856 or tip if no revision is checked out.
1856 or tip if no revision is checked out.
1857
1857
1858 The manifest is the list of files being version controlled. If no revision
1858 The manifest is the list of files being version controlled. If no revision
1859 is given then the first parent of the working directory is used.
1859 is given then the first parent of the working directory is used.
1860
1860
1861 With -v flag, print file permissions, symlink and executable bits. With
1861 With -v flag, print file permissions, symlink and executable bits. With
1862 --debug flag, print file revision hashes.
1862 --debug flag, print file revision hashes.
1863 """
1863 """
1864
1864
1865 if rev and node:
1865 if rev and node:
1866 raise util.Abort(_("please specify just one revision"))
1866 raise util.Abort(_("please specify just one revision"))
1867
1867
1868 if not node:
1868 if not node:
1869 node = rev
1869 node = rev
1870
1870
1871 m = repo.changectx(node).manifest()
1871 m = repo.changectx(node).manifest()
1872 files = m.keys()
1872 files = m.keys()
1873 files.sort()
1873 files.sort()
1874
1874
1875 for f in files:
1875 for f in files:
1876 if ui.debugflag:
1876 if ui.debugflag:
1877 ui.write("%40s " % hex(m[f]))
1877 ui.write("%40s " % hex(m[f]))
1878 if ui.verbose:
1878 if ui.verbose:
1879 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1879 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1880 perm = m.execf(f) and "755" or "644"
1880 perm = m.execf(f) and "755" or "644"
1881 ui.write("%3s %1s " % (perm, type))
1881 ui.write("%3s %1s " % (perm, type))
1882 ui.write("%s\n" % f)
1882 ui.write("%s\n" % f)
1883
1883
1884 def merge(ui, repo, node=None, force=None, rev=None):
1884 def merge(ui, repo, node=None, force=None, rev=None):
1885 """merge working directory with another revision
1885 """merge working directory with another revision
1886
1886
1887 Merge the contents of the current working directory and the
1887 Merge the contents of the current working directory and the
1888 requested revision. Files that changed between either parent are
1888 requested revision. Files that changed between either parent are
1889 marked as changed for the next commit and a commit must be
1889 marked as changed for the next commit and a commit must be
1890 performed before any further updates are allowed.
1890 performed before any further updates are allowed.
1891
1891
1892 If no revision is specified, the working directory's parent is a
1892 If no revision is specified, the working directory's parent is a
1893 head revision, and the repository contains exactly one other head,
1893 head revision, and the repository contains exactly one other head,
1894 the other head is merged with by default. Otherwise, an explicit
1894 the other head is merged with by default. Otherwise, an explicit
1895 revision to merge with must be provided.
1895 revision to merge with must be provided.
1896 """
1896 """
1897
1897
1898 if rev and node:
1898 if rev and node:
1899 raise util.Abort(_("please specify just one revision"))
1899 raise util.Abort(_("please specify just one revision"))
1900 if not node:
1900 if not node:
1901 node = rev
1901 node = rev
1902
1902
1903 if not node:
1903 if not node:
1904 heads = repo.heads()
1904 heads = repo.heads()
1905 if len(heads) > 2:
1905 if len(heads) > 2:
1906 raise util.Abort(_('repo has %d heads - '
1906 raise util.Abort(_('repo has %d heads - '
1907 'please merge with an explicit rev') %
1907 'please merge with an explicit rev') %
1908 len(heads))
1908 len(heads))
1909 parent = repo.dirstate.parents()[0]
1909 parent = repo.dirstate.parents()[0]
1910 if len(heads) == 1:
1910 if len(heads) == 1:
1911 msg = _('there is nothing to merge')
1911 msg = _('there is nothing to merge')
1912 if parent != repo.lookup(repo.workingctx().branch()):
1912 if parent != repo.lookup(repo.workingctx().branch()):
1913 msg = _('%s - use "hg update" instead') % msg
1913 msg = _('%s - use "hg update" instead') % msg
1914 raise util.Abort(msg)
1914 raise util.Abort(msg)
1915
1915
1916 if parent not in heads:
1916 if parent not in heads:
1917 raise util.Abort(_('working dir not at a head rev - '
1917 raise util.Abort(_('working dir not at a head rev - '
1918 'use "hg update" or merge with an explicit rev'))
1918 'use "hg update" or merge with an explicit rev'))
1919 node = parent == heads[0] and heads[-1] or heads[0]
1919 node = parent == heads[0] and heads[-1] or heads[0]
1920 return hg.merge(repo, node, force=force)
1920 return hg.merge(repo, node, force=force)
1921
1921
1922 def outgoing(ui, repo, dest=None, **opts):
1922 def outgoing(ui, repo, dest=None, **opts):
1923 """show changesets not found in destination
1923 """show changesets not found in destination
1924
1924
1925 Show changesets not found in the specified destination repository or
1925 Show changesets not found in the specified destination repository or
1926 the default push location. These are the changesets that would be pushed
1926 the default push location. These are the changesets that would be pushed
1927 if a push was requested.
1927 if a push was requested.
1928
1928
1929 See pull for valid destination format details.
1929 See pull for valid destination format details.
1930 """
1930 """
1931 limit = cmdutil.loglimit(opts)
1931 limit = cmdutil.loglimit(opts)
1932 dest, revs, checkout = hg.parseurl(
1932 dest, revs, checkout = hg.parseurl(
1933 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1933 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1934 cmdutil.setremoteconfig(ui, opts)
1934 cmdutil.setremoteconfig(ui, opts)
1935 if revs:
1935 if revs:
1936 revs = [repo.lookup(rev) for rev in revs]
1936 revs = [repo.lookup(rev) for rev in revs]
1937
1937
1938 other = hg.repository(ui, dest)
1938 other = hg.repository(ui, dest)
1939 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1939 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1940 o = repo.findoutgoing(other, force=opts['force'])
1940 o = repo.findoutgoing(other, force=opts['force'])
1941 if not o:
1941 if not o:
1942 ui.status(_("no changes found\n"))
1942 ui.status(_("no changes found\n"))
1943 return 1
1943 return 1
1944 o = repo.changelog.nodesbetween(o, revs)[0]
1944 o = repo.changelog.nodesbetween(o, revs)[0]
1945 if opts['newest_first']:
1945 if opts['newest_first']:
1946 o.reverse()
1946 o.reverse()
1947 displayer = cmdutil.show_changeset(ui, repo, opts)
1947 displayer = cmdutil.show_changeset(ui, repo, opts)
1948 count = 0
1948 count = 0
1949 for n in o:
1949 for n in o:
1950 if count >= limit:
1950 if count >= limit:
1951 break
1951 break
1952 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1952 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1953 if opts['no_merges'] and len(parents) == 2:
1953 if opts['no_merges'] and len(parents) == 2:
1954 continue
1954 continue
1955 count += 1
1955 count += 1
1956 displayer.show(changenode=n)
1956 displayer.show(changenode=n)
1957
1957
1958 def parents(ui, repo, file_=None, **opts):
1958 def parents(ui, repo, file_=None, **opts):
1959 """show the parents of the working dir or revision
1959 """show the parents of the working dir or revision
1960
1960
1961 Print the working directory's parent revisions. If a
1961 Print the working directory's parent revisions. If a
1962 revision is given via --rev, the parent of that revision
1962 revision is given via --rev, the parent of that revision
1963 will be printed. If a file argument is given, revision in
1963 will be printed. If a file argument is given, revision in
1964 which the file was last changed (before the working directory
1964 which the file was last changed (before the working directory
1965 revision or the argument to --rev if given) is printed.
1965 revision or the argument to --rev if given) is printed.
1966 """
1966 """
1967 rev = opts.get('rev')
1967 rev = opts.get('rev')
1968 if rev:
1968 if rev:
1969 ctx = repo.changectx(rev)
1969 ctx = repo.changectx(rev)
1970 else:
1970 else:
1971 ctx = repo.workingctx()
1971 ctx = repo.workingctx()
1972
1972
1973 if file_:
1973 if file_:
1974 m = cmdutil.match(repo, (file_,), opts)
1974 m = cmdutil.match(repo, (file_,), opts)
1975 if m.anypats() or len(m.files()) != 1:
1975 if m.anypats() or len(m.files()) != 1:
1976 raise util.Abort(_('can only specify an explicit file name'))
1976 raise util.Abort(_('can only specify an explicit file name'))
1977 file_ = m.files()[0]
1977 file_ = m.files()[0]
1978 filenodes = []
1978 filenodes = []
1979 for cp in ctx.parents():
1979 for cp in ctx.parents():
1980 if not cp:
1980 if not cp:
1981 continue
1981 continue
1982 try:
1982 try:
1983 filenodes.append(cp.filenode(file_))
1983 filenodes.append(cp.filenode(file_))
1984 except revlog.LookupError:
1984 except revlog.LookupError:
1985 pass
1985 pass
1986 if not filenodes:
1986 if not filenodes:
1987 raise util.Abort(_("'%s' not found in manifest!") % file_)
1987 raise util.Abort(_("'%s' not found in manifest!") % file_)
1988 fl = repo.file(file_)
1988 fl = repo.file(file_)
1989 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1989 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1990 else:
1990 else:
1991 p = [cp.node() for cp in ctx.parents()]
1991 p = [cp.node() for cp in ctx.parents()]
1992
1992
1993 displayer = cmdutil.show_changeset(ui, repo, opts)
1993 displayer = cmdutil.show_changeset(ui, repo, opts)
1994 for n in p:
1994 for n in p:
1995 if n != nullid:
1995 if n != nullid:
1996 displayer.show(changenode=n)
1996 displayer.show(changenode=n)
1997
1997
1998 def paths(ui, repo, search=None):
1998 def paths(ui, repo, search=None):
1999 """show definition of symbolic path names
1999 """show definition of symbolic path names
2000
2000
2001 Show definition of symbolic path name NAME. If no name is given, show
2001 Show definition of symbolic path name NAME. If no name is given, show
2002 definition of available names.
2002 definition of available names.
2003
2003
2004 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2004 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2005 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2005 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2006 """
2006 """
2007 if search:
2007 if search:
2008 for name, path in ui.configitems("paths"):
2008 for name, path in ui.configitems("paths"):
2009 if name == search:
2009 if name == search:
2010 ui.write("%s\n" % util.hidepassword(path))
2010 ui.write("%s\n" % util.hidepassword(path))
2011 return
2011 return
2012 ui.warn(_("not found!\n"))
2012 ui.warn(_("not found!\n"))
2013 return 1
2013 return 1
2014 else:
2014 else:
2015 for name, path in ui.configitems("paths"):
2015 for name, path in ui.configitems("paths"):
2016 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2016 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2017
2017
2018 def postincoming(ui, repo, modheads, optupdate, checkout):
2018 def postincoming(ui, repo, modheads, optupdate, checkout):
2019 if modheads == 0:
2019 if modheads == 0:
2020 return
2020 return
2021 if optupdate:
2021 if optupdate:
2022 if modheads <= 1 or checkout:
2022 if modheads <= 1 or checkout:
2023 return hg.update(repo, checkout)
2023 return hg.update(repo, checkout)
2024 else:
2024 else:
2025 ui.status(_("not updating, since new heads added\n"))
2025 ui.status(_("not updating, since new heads added\n"))
2026 if modheads > 1:
2026 if modheads > 1:
2027 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2027 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2028 else:
2028 else:
2029 ui.status(_("(run 'hg update' to get a working copy)\n"))
2029 ui.status(_("(run 'hg update' to get a working copy)\n"))
2030
2030
2031 def pull(ui, repo, source="default", **opts):
2031 def pull(ui, repo, source="default", **opts):
2032 """pull changes from the specified source
2032 """pull changes from the specified source
2033
2033
2034 Pull changes from a remote repository to a local one.
2034 Pull changes from a remote repository to a local one.
2035
2035
2036 This finds all changes from the repository at the specified path
2036 This finds all changes from the repository at the specified path
2037 or URL and adds them to the local repository. By default, this
2037 or URL and adds them to the local repository. By default, this
2038 does not update the copy of the project in the working directory.
2038 does not update the copy of the project in the working directory.
2039
2039
2040 Valid URLs are of the form:
2040 Valid URLs are of the form:
2041
2041
2042 local/filesystem/path (or file://local/filesystem/path)
2042 local/filesystem/path (or file://local/filesystem/path)
2043 http://[user@]host[:port]/[path]
2043 http://[user@]host[:port]/[path]
2044 https://[user@]host[:port]/[path]
2044 https://[user@]host[:port]/[path]
2045 ssh://[user@]host[:port]/[path]
2045 ssh://[user@]host[:port]/[path]
2046 static-http://host[:port]/[path]
2046 static-http://host[:port]/[path]
2047
2047
2048 Paths in the local filesystem can either point to Mercurial
2048 Paths in the local filesystem can either point to Mercurial
2049 repositories or to bundle files (as created by 'hg bundle' or
2049 repositories or to bundle files (as created by 'hg bundle' or
2050 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2050 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2051 allows access to a Mercurial repository where you simply use a web
2051 allows access to a Mercurial repository where you simply use a web
2052 server to publish the .hg directory as static content.
2052 server to publish the .hg directory as static content.
2053
2053
2054 An optional identifier after # indicates a particular branch, tag,
2054 An optional identifier after # indicates a particular branch, tag,
2055 or changeset to pull.
2055 or changeset to pull.
2056
2056
2057 Some notes about using SSH with Mercurial:
2057 Some notes about using SSH with Mercurial:
2058 - SSH requires an accessible shell account on the destination machine
2058 - SSH requires an accessible shell account on the destination machine
2059 and a copy of hg in the remote path or specified with as remotecmd.
2059 and a copy of hg in the remote path or specified with as remotecmd.
2060 - path is relative to the remote user's home directory by default.
2060 - path is relative to the remote user's home directory by default.
2061 Use an extra slash at the start of a path to specify an absolute path:
2061 Use an extra slash at the start of a path to specify an absolute path:
2062 ssh://example.com//tmp/repository
2062 ssh://example.com//tmp/repository
2063 - Mercurial doesn't use its own compression via SSH; the right thing
2063 - Mercurial doesn't use its own compression via SSH; the right thing
2064 to do is to configure it in your ~/.ssh/config, e.g.:
2064 to do is to configure it in your ~/.ssh/config, e.g.:
2065 Host *.mylocalnetwork.example.com
2065 Host *.mylocalnetwork.example.com
2066 Compression no
2066 Compression no
2067 Host *
2067 Host *
2068 Compression yes
2068 Compression yes
2069 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2069 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2070 with the --ssh command line option.
2070 with the --ssh command line option.
2071 """
2071 """
2072 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2072 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2073 cmdutil.setremoteconfig(ui, opts)
2073 cmdutil.setremoteconfig(ui, opts)
2074
2074
2075 other = hg.repository(ui, source)
2075 other = hg.repository(ui, source)
2076 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2076 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2077 if revs:
2077 if revs:
2078 try:
2078 try:
2079 revs = [other.lookup(rev) for rev in revs]
2079 revs = [other.lookup(rev) for rev in revs]
2080 except NoCapability:
2080 except NoCapability:
2081 error = _("Other repository doesn't support revision lookup, "
2081 error = _("Other repository doesn't support revision lookup, "
2082 "so a rev cannot be specified.")
2082 "so a rev cannot be specified.")
2083 raise util.Abort(error)
2083 raise util.Abort(error)
2084
2084
2085 modheads = repo.pull(other, heads=revs, force=opts['force'])
2085 modheads = repo.pull(other, heads=revs, force=opts['force'])
2086 return postincoming(ui, repo, modheads, opts['update'], checkout)
2086 return postincoming(ui, repo, modheads, opts['update'], checkout)
2087
2087
2088 def push(ui, repo, dest=None, **opts):
2088 def push(ui, repo, dest=None, **opts):
2089 """push changes to the specified destination
2089 """push changes to the specified destination
2090
2090
2091 Push changes from the local repository to the given destination.
2091 Push changes from the local repository to the given destination.
2092
2092
2093 This is the symmetrical operation for pull. It helps to move
2093 This is the symmetrical operation for pull. It helps to move
2094 changes from the current repository to a different one. If the
2094 changes from the current repository to a different one. If the
2095 destination is local this is identical to a pull in that directory
2095 destination is local this is identical to a pull in that directory
2096 from the current one.
2096 from the current one.
2097
2097
2098 By default, push will refuse to run if it detects the result would
2098 By default, push will refuse to run if it detects the result would
2099 increase the number of remote heads. This generally indicates the
2099 increase the number of remote heads. This generally indicates the
2100 the client has forgotten to pull and merge before pushing.
2100 the client has forgotten to pull and merge before pushing.
2101
2101
2102 Valid URLs are of the form:
2102 Valid URLs are of the form:
2103
2103
2104 local/filesystem/path (or file://local/filesystem/path)
2104 local/filesystem/path (or file://local/filesystem/path)
2105 ssh://[user@]host[:port]/[path]
2105 ssh://[user@]host[:port]/[path]
2106 http://[user@]host[:port]/[path]
2106 http://[user@]host[:port]/[path]
2107 https://[user@]host[:port]/[path]
2107 https://[user@]host[:port]/[path]
2108
2108
2109 An optional identifier after # indicates a particular branch, tag,
2109 An optional identifier after # indicates a particular branch, tag,
2110 or changeset to push. If -r is used, the named changeset and all its
2110 or changeset to push. If -r is used, the named changeset and all its
2111 ancestors will be pushed to the remote repository.
2111 ancestors will be pushed to the remote repository.
2112
2112
2113 Look at the help text for the pull command for important details
2113 Look at the help text for the pull command for important details
2114 about ssh:// URLs.
2114 about ssh:// URLs.
2115
2115
2116 Pushing to http:// and https:// URLs is only possible, if this
2116 Pushing to http:// and https:// URLs is only possible, if this
2117 feature is explicitly enabled on the remote Mercurial server.
2117 feature is explicitly enabled on the remote Mercurial server.
2118 """
2118 """
2119 dest, revs, checkout = hg.parseurl(
2119 dest, revs, checkout = hg.parseurl(
2120 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2120 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2121 cmdutil.setremoteconfig(ui, opts)
2121 cmdutil.setremoteconfig(ui, opts)
2122
2122
2123 other = hg.repository(ui, dest)
2123 other = hg.repository(ui, dest)
2124 ui.status('pushing to %s\n' % util.hidepassword(dest))
2124 ui.status('pushing to %s\n' % util.hidepassword(dest))
2125 if revs:
2125 if revs:
2126 revs = [repo.lookup(rev) for rev in revs]
2126 revs = [repo.lookup(rev) for rev in revs]
2127 r = repo.push(other, opts['force'], revs=revs)
2127 r = repo.push(other, opts['force'], revs=revs)
2128 return r == 0
2128 return r == 0
2129
2129
2130 def rawcommit(ui, repo, *pats, **opts):
2130 def rawcommit(ui, repo, *pats, **opts):
2131 """raw commit interface (DEPRECATED)
2131 """raw commit interface (DEPRECATED)
2132
2132
2133 (DEPRECATED)
2133 (DEPRECATED)
2134 Lowlevel commit, for use in helper scripts.
2134 Lowlevel commit, for use in helper scripts.
2135
2135
2136 This command is not intended to be used by normal users, as it is
2136 This command is not intended to be used by normal users, as it is
2137 primarily useful for importing from other SCMs.
2137 primarily useful for importing from other SCMs.
2138
2138
2139 This command is now deprecated and will be removed in a future
2139 This command is now deprecated and will be removed in a future
2140 release, please use debugsetparents and commit instead.
2140 release, please use debugsetparents and commit instead.
2141 """
2141 """
2142
2142
2143 ui.warn(_("(the rawcommit command is deprecated)\n"))
2143 ui.warn(_("(the rawcommit command is deprecated)\n"))
2144
2144
2145 message = cmdutil.logmessage(opts)
2145 message = cmdutil.logmessage(opts)
2146
2146
2147 files = cmdutil.match(repo, pats, opts).files()
2147 files = cmdutil.match(repo, pats, opts).files()
2148 if opts['files']:
2148 if opts['files']:
2149 files += open(opts['files']).read().splitlines()
2149 files += open(opts['files']).read().splitlines()
2150
2150
2151 parents = [repo.lookup(p) for p in opts['parent']]
2151 parents = [repo.lookup(p) for p in opts['parent']]
2152
2152
2153 try:
2153 try:
2154 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2154 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2155 except ValueError, inst:
2155 except ValueError, inst:
2156 raise util.Abort(str(inst))
2156 raise util.Abort(str(inst))
2157
2157
2158 def recover(ui, repo):
2158 def recover(ui, repo):
2159 """roll back an interrupted transaction
2159 """roll back an interrupted transaction
2160
2160
2161 Recover from an interrupted commit or pull.
2161 Recover from an interrupted commit or pull.
2162
2162
2163 This command tries to fix the repository status after an interrupted
2163 This command tries to fix the repository status after an interrupted
2164 operation. It should only be necessary when Mercurial suggests it.
2164 operation. It should only be necessary when Mercurial suggests it.
2165 """
2165 """
2166 if repo.recover():
2166 if repo.recover():
2167 return hg.verify(repo)
2167 return hg.verify(repo)
2168 return 1
2168 return 1
2169
2169
2170 def remove(ui, repo, *pats, **opts):
2170 def remove(ui, repo, *pats, **opts):
2171 """remove the specified files on the next commit
2171 """remove the specified files on the next commit
2172
2172
2173 Schedule the indicated files for removal from the repository.
2173 Schedule the indicated files for removal from the repository.
2174
2174
2175 This only removes files from the current branch, not from the entire
2175 This only removes files from the current branch, not from the entire
2176 project history. -A can be used to remove only files that have already
2176 project history. -A can be used to remove only files that have already
2177 been deleted, -f can be used to force deletion, and -Af can be used
2177 been deleted, -f can be used to force deletion, and -Af can be used
2178 to remove files from the next revision without deleting them.
2178 to remove files from the next revision without deleting them.
2179
2179
2180 The following table details the behavior of remove for different file
2180 The following table details the behavior of remove for different file
2181 states (columns) and option combinations (rows). The file states are
2181 states (columns) and option combinations (rows). The file states are
2182 Added, Clean, Modified and Missing (as reported by hg status). The
2182 Added, Clean, Modified and Missing (as reported by hg status). The
2183 actions are Warn, Remove (from branch) and Delete (from disk).
2183 actions are Warn, Remove (from branch) and Delete (from disk).
2184
2184
2185 A C M !
2185 A C M !
2186 none W RD W R
2186 none W RD W R
2187 -f R RD RD R
2187 -f R RD RD R
2188 -A W W W R
2188 -A W W W R
2189 -Af R R R R
2189 -Af R R R R
2190
2190
2191 This command schedules the files to be removed at the next commit.
2191 This command schedules the files to be removed at the next commit.
2192 To undo a remove before that, see hg revert.
2192 To undo a remove before that, see hg revert.
2193 """
2193 """
2194
2194
2195 after, force = opts.get('after'), opts.get('force')
2195 after, force = opts.get('after'), opts.get('force')
2196 if not pats and not after:
2196 if not pats and not after:
2197 raise util.Abort(_('no files specified'))
2197 raise util.Abort(_('no files specified'))
2198
2198
2199 m = cmdutil.match(repo, pats, opts)
2199 m = cmdutil.match(repo, pats, opts)
2200 mardu = map(dict.fromkeys, repo.status(match=m))[:5]
2200 mardu = map(dict.fromkeys, repo.status(match=m))[:5]
2201 modified, added, removed, deleted, unknown = mardu
2201 modified, added, removed, deleted, unknown = mardu
2202
2202
2203 remove, forget = [], []
2203 remove, forget = [], []
2204 for abs in repo.walk(m):
2204 for abs in repo.walk(m):
2205
2205
2206 reason = None
2206 reason = None
2207 if abs in removed or abs in unknown:
2207 if abs in removed or abs in unknown:
2208 continue
2208 continue
2209
2209
2210 # last column
2210 # last column
2211 elif abs in deleted:
2211 elif abs in deleted:
2212 remove.append(abs)
2212 remove.append(abs)
2213
2213
2214 # rest of the third row
2214 # rest of the third row
2215 elif after and not force:
2215 elif after and not force:
2216 reason = _('still exists (use -f to force removal)')
2216 reason = _('still exists (use -f to force removal)')
2217
2217
2218 # rest of the first column
2218 # rest of the first column
2219 elif abs in added:
2219 elif abs in added:
2220 if not force:
2220 if not force:
2221 reason = _('has been marked for add (use -f to force removal)')
2221 reason = _('has been marked for add (use -f to force removal)')
2222 else:
2222 else:
2223 forget.append(abs)
2223 forget.append(abs)
2224
2224
2225 # rest of the third column
2225 # rest of the third column
2226 elif abs in modified:
2226 elif abs in modified:
2227 if not force:
2227 if not force:
2228 reason = _('is modified (use -f to force removal)')
2228 reason = _('is modified (use -f to force removal)')
2229 else:
2229 else:
2230 remove.append(abs)
2230 remove.append(abs)
2231
2231
2232 # rest of the second column
2232 # rest of the second column
2233 elif not reason:
2233 elif not reason:
2234 remove.append(abs)
2234 remove.append(abs)
2235
2235
2236 if reason:
2236 if reason:
2237 ui.warn(_('not removing %s: file %s\n') % (m.rel(abs), reason))
2237 ui.warn(_('not removing %s: file %s\n') % (m.rel(abs), reason))
2238 elif ui.verbose or not m.exact(abs):
2238 elif ui.verbose or not m.exact(abs):
2239 ui.status(_('removing %s\n') % m.rel(abs))
2239 ui.status(_('removing %s\n') % m.rel(abs))
2240
2240
2241 repo.forget(forget)
2241 repo.forget(forget)
2242 repo.remove(remove, unlink=not after)
2242 repo.remove(remove, unlink=not after)
2243
2243
2244 def rename(ui, repo, *pats, **opts):
2244 def rename(ui, repo, *pats, **opts):
2245 """rename files; equivalent of copy + remove
2245 """rename files; equivalent of copy + remove
2246
2246
2247 Mark dest as copies of sources; mark sources for deletion. If
2247 Mark dest as copies of sources; mark sources for deletion. If
2248 dest is a directory, copies are put in that directory. If dest is
2248 dest is a directory, copies are put in that directory. If dest is
2249 a file, there can only be one source.
2249 a file, there can only be one source.
2250
2250
2251 By default, this command copies the contents of files as they
2251 By default, this command copies the contents of files as they
2252 stand in the working directory. If invoked with --after, the
2252 stand in the working directory. If invoked with --after, the
2253 operation is recorded, but no copying is performed.
2253 operation is recorded, but no copying is performed.
2254
2254
2255 This command takes effect in the next commit. To undo a rename
2255 This command takes effect in the next commit. To undo a rename
2256 before that, see hg revert.
2256 before that, see hg revert.
2257 """
2257 """
2258 wlock = repo.wlock(False)
2258 wlock = repo.wlock(False)
2259 try:
2259 try:
2260 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2260 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2261 finally:
2261 finally:
2262 del wlock
2262 del wlock
2263
2263
2264 def resolve(ui, repo, *pats, **opts):
2264 def resolve(ui, repo, *pats, **opts):
2265 """resolve file merges from a branch merge or update
2265 """resolve file merges from a branch merge or update
2266
2266
2267 This command will attempt to resolve unresolved merges from the
2267 This command will attempt to resolve unresolved merges from the
2268 last update or merge command. This will use the local file
2268 last update or merge command. This will use the local file
2269 revision preserved at the last update or merge to cleanly retry
2269 revision preserved at the last update or merge to cleanly retry
2270 the file merge attempt. With no file or options specified, this
2270 the file merge attempt. With no file or options specified, this
2271 command will attempt to resolve all unresolved files.
2271 command will attempt to resolve all unresolved files.
2272
2272
2273 The codes used to show the status of files are:
2273 The codes used to show the status of files are:
2274 U = unresolved
2274 U = unresolved
2275 R = resolved
2275 R = resolved
2276 """
2276 """
2277
2277
2278 if len([x for x in opts if opts[x]]) > 1:
2278 if len([x for x in opts if opts[x]]) > 1:
2279 raise util.Abort(_("too many options specified"))
2279 raise util.Abort(_("too many options specified"))
2280
2280
2281 ms = merge_.mergestate(repo)
2281 ms = merge_.mergestate(repo)
2282 m = cmdutil.match(repo, pats, opts)
2282 m = cmdutil.match(repo, pats, opts)
2283
2283
2284 for f in ms:
2284 for f in ms:
2285 if m(f):
2285 if m(f):
2286 if opts.get("list"):
2286 if opts.get("list"):
2287 ui.write("%s %s\n" % (ms[f].upper(), f))
2287 ui.write("%s %s\n" % (ms[f].upper(), f))
2288 elif opts.get("mark"):
2288 elif opts.get("mark"):
2289 ms.mark(f, "r")
2289 ms.mark(f, "r")
2290 elif opts.get("unmark"):
2290 elif opts.get("unmark"):
2291 ms.mark(f, "u")
2291 ms.mark(f, "u")
2292 else:
2292 else:
2293 wctx = repo.workingctx()
2293 wctx = repo.workingctx()
2294 mctx = wctx.parents()[-1]
2294 mctx = wctx.parents()[-1]
2295 ms.resolve(f, wctx, mctx)
2295 ms.resolve(f, wctx, mctx)
2296
2296
2297 def revert(ui, repo, *pats, **opts):
2297 def revert(ui, repo, *pats, **opts):
2298 """restore individual files or dirs to an earlier state
2298 """restore individual files or dirs to an earlier state
2299
2299
2300 (use update -r to check out earlier revisions, revert does not
2300 (use update -r to check out earlier revisions, revert does not
2301 change the working dir parents)
2301 change the working dir parents)
2302
2302
2303 With no revision specified, revert the named files or directories
2303 With no revision specified, revert the named files or directories
2304 to the contents they had in the parent of the working directory.
2304 to the contents they had in the parent of the working directory.
2305 This restores the contents of the affected files to an unmodified
2305 This restores the contents of the affected files to an unmodified
2306 state and unschedules adds, removes, copies, and renames. If the
2306 state and unschedules adds, removes, copies, and renames. If the
2307 working directory has two parents, you must explicitly specify the
2307 working directory has two parents, you must explicitly specify the
2308 revision to revert to.
2308 revision to revert to.
2309
2309
2310 Using the -r option, revert the given files or directories to their
2310 Using the -r option, revert the given files or directories to their
2311 contents as of a specific revision. This can be helpful to "roll
2311 contents as of a specific revision. This can be helpful to "roll
2312 back" some or all of an earlier change.
2312 back" some or all of an earlier change.
2313 See 'hg help dates' for a list of formats valid for -d/--date.
2313 See 'hg help dates' for a list of formats valid for -d/--date.
2314
2314
2315 Revert modifies the working directory. It does not commit any
2315 Revert modifies the working directory. It does not commit any
2316 changes, or change the parent of the working directory. If you
2316 changes, or change the parent of the working directory. If you
2317 revert to a revision other than the parent of the working
2317 revert to a revision other than the parent of the working
2318 directory, the reverted files will thus appear modified
2318 directory, the reverted files will thus appear modified
2319 afterwards.
2319 afterwards.
2320
2320
2321 If a file has been deleted, it is restored. If the executable
2321 If a file has been deleted, it is restored. If the executable
2322 mode of a file was changed, it is reset.
2322 mode of a file was changed, it is reset.
2323
2323
2324 If names are given, all files matching the names are reverted.
2324 If names are given, all files matching the names are reverted.
2325 If no arguments are given, no files are reverted.
2325 If no arguments are given, no files are reverted.
2326
2326
2327 Modified files are saved with a .orig suffix before reverting.
2327 Modified files are saved with a .orig suffix before reverting.
2328 To disable these backups, use --no-backup.
2328 To disable these backups, use --no-backup.
2329 """
2329 """
2330
2330
2331 if opts["date"]:
2331 if opts["date"]:
2332 if opts["rev"]:
2332 if opts["rev"]:
2333 raise util.Abort(_("you can't specify a revision and a date"))
2333 raise util.Abort(_("you can't specify a revision and a date"))
2334 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2334 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2335
2335
2336 if not pats and not opts['all']:
2336 if not pats and not opts['all']:
2337 raise util.Abort(_('no files or directories specified; '
2337 raise util.Abort(_('no files or directories specified; '
2338 'use --all to revert the whole repo'))
2338 'use --all to revert the whole repo'))
2339
2339
2340 parent, p2 = repo.dirstate.parents()
2340 parent, p2 = repo.dirstate.parents()
2341 if not opts['rev'] and p2 != nullid:
2341 if not opts['rev'] and p2 != nullid:
2342 raise util.Abort(_('uncommitted merge - please provide a '
2342 raise util.Abort(_('uncommitted merge - please provide a '
2343 'specific revision'))
2343 'specific revision'))
2344 ctx = repo.changectx(opts['rev'])
2344 ctx = repo.changectx(opts['rev'])
2345 node = ctx.node()
2345 node = ctx.node()
2346 mf = ctx.manifest()
2346 mf = ctx.manifest()
2347 if node == parent:
2347 if node == parent:
2348 pmf = mf
2348 pmf = mf
2349 else:
2349 else:
2350 pmf = None
2350 pmf = None
2351
2351
2352 # need all matching names in dirstate and manifest of target rev,
2352 # need all matching names in dirstate and manifest of target rev,
2353 # so have to walk both. do not print errors if files exist in one
2353 # so have to walk both. do not print errors if files exist in one
2354 # but not other.
2354 # but not other.
2355
2355
2356 names = {}
2356 names = {}
2357
2357
2358 wlock = repo.wlock()
2358 wlock = repo.wlock()
2359 try:
2359 try:
2360 # walk dirstate.
2360 # walk dirstate.
2361 files = []
2361 files = []
2362
2362
2363 m = cmdutil.match(repo, pats, opts)
2363 m = cmdutil.match(repo, pats, opts)
2364 m.bad = lambda x,y: False
2364 m.bad = lambda x,y: False
2365 for abs in repo.walk(m):
2365 for abs in repo.walk(m):
2366 names[abs] = m.rel(abs), m.exact(abs)
2366 names[abs] = m.rel(abs), m.exact(abs)
2367
2367
2368 # walk target manifest.
2368 # walk target manifest.
2369
2369
2370 def badfn(path, msg):
2370 def badfn(path, msg):
2371 if path in names:
2371 if path in names:
2372 return False
2372 return False
2373 path_ = path + '/'
2373 path_ = path + '/'
2374 for f in names:
2374 for f in names:
2375 if f.startswith(path_):
2375 if f.startswith(path_):
2376 return False
2376 return False
2377 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2377 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2378 return False
2378 return False
2379
2379
2380 m = cmdutil.match(repo, pats, opts)
2380 m = cmdutil.match(repo, pats, opts)
2381 m.bad = badfn
2381 m.bad = badfn
2382 for abs in repo.walk(m, node=node):
2382 for abs in repo.walk(m, node=node):
2383 if abs not in names:
2383 if abs not in names:
2384 names[abs] = m.rel(abs), m.exact(abs)
2384 names[abs] = m.rel(abs), m.exact(abs)
2385
2385
2386 m = cmdutil.matchfiles(repo, names)
2386 m = cmdutil.matchfiles(repo, names)
2387 changes = repo.status(match=m)[:4]
2387 changes = repo.status(match=m)[:4]
2388 modified, added, removed, deleted = map(dict.fromkeys, changes)
2388 modified, added, removed, deleted = map(dict.fromkeys, changes)
2389
2389
2390 # if f is a rename, also revert the source
2390 # if f is a rename, also revert the source
2391 cwd = repo.getcwd()
2391 cwd = repo.getcwd()
2392 for f in added:
2392 for f in added:
2393 src = repo.dirstate.copied(f)
2393 src = repo.dirstate.copied(f)
2394 if src and src not in names and repo.dirstate[src] == 'r':
2394 if src and src not in names and repo.dirstate[src] == 'r':
2395 removed[src] = None
2395 removed[src] = None
2396 names[src] = (repo.pathto(src, cwd), True)
2396 names[src] = (repo.pathto(src, cwd), True)
2397
2397
2398 def removeforget(abs):
2398 def removeforget(abs):
2399 if repo.dirstate[abs] == 'a':
2399 if repo.dirstate[abs] == 'a':
2400 return _('forgetting %s\n')
2400 return _('forgetting %s\n')
2401 return _('removing %s\n')
2401 return _('removing %s\n')
2402
2402
2403 revert = ([], _('reverting %s\n'))
2403 revert = ([], _('reverting %s\n'))
2404 add = ([], _('adding %s\n'))
2404 add = ([], _('adding %s\n'))
2405 remove = ([], removeforget)
2405 remove = ([], removeforget)
2406 undelete = ([], _('undeleting %s\n'))
2406 undelete = ([], _('undeleting %s\n'))
2407
2407
2408 disptable = (
2408 disptable = (
2409 # dispatch table:
2409 # dispatch table:
2410 # file state
2410 # file state
2411 # action if in target manifest
2411 # action if in target manifest
2412 # action if not in target manifest
2412 # action if not in target manifest
2413 # make backup if in target manifest
2413 # make backup if in target manifest
2414 # make backup if not in target manifest
2414 # make backup if not in target manifest
2415 (modified, revert, remove, True, True),
2415 (modified, revert, remove, True, True),
2416 (added, revert, remove, True, False),
2416 (added, revert, remove, True, False),
2417 (removed, undelete, None, False, False),
2417 (removed, undelete, None, False, False),
2418 (deleted, revert, remove, False, False),
2418 (deleted, revert, remove, False, False),
2419 )
2419 )
2420
2420
2421 entries = names.items()
2421 entries = names.items()
2422 entries.sort()
2422 entries.sort()
2423
2423
2424 for abs, (rel, exact) in entries:
2424 for abs, (rel, exact) in entries:
2425 mfentry = mf.get(abs)
2425 mfentry = mf.get(abs)
2426 target = repo.wjoin(abs)
2426 target = repo.wjoin(abs)
2427 def handle(xlist, dobackup):
2427 def handle(xlist, dobackup):
2428 xlist[0].append(abs)
2428 xlist[0].append(abs)
2429 if dobackup and not opts['no_backup'] and util.lexists(target):
2429 if dobackup and not opts['no_backup'] and util.lexists(target):
2430 bakname = "%s.orig" % rel
2430 bakname = "%s.orig" % rel
2431 ui.note(_('saving current version of %s as %s\n') %
2431 ui.note(_('saving current version of %s as %s\n') %
2432 (rel, bakname))
2432 (rel, bakname))
2433 if not opts.get('dry_run'):
2433 if not opts.get('dry_run'):
2434 util.copyfile(target, bakname)
2434 util.copyfile(target, bakname)
2435 if ui.verbose or not exact:
2435 if ui.verbose or not exact:
2436 msg = xlist[1]
2436 msg = xlist[1]
2437 if not isinstance(msg, basestring):
2437 if not isinstance(msg, basestring):
2438 msg = msg(abs)
2438 msg = msg(abs)
2439 ui.status(msg % rel)
2439 ui.status(msg % rel)
2440 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2440 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2441 if abs not in table: continue
2441 if abs not in table: continue
2442 # file has changed in dirstate
2442 # file has changed in dirstate
2443 if mfentry:
2443 if mfentry:
2444 handle(hitlist, backuphit)
2444 handle(hitlist, backuphit)
2445 elif misslist is not None:
2445 elif misslist is not None:
2446 handle(misslist, backupmiss)
2446 handle(misslist, backupmiss)
2447 break
2447 break
2448 else:
2448 else:
2449 if abs not in repo.dirstate:
2449 if abs not in repo.dirstate:
2450 if mfentry:
2450 if mfentry:
2451 handle(add, True)
2451 handle(add, True)
2452 elif exact:
2452 elif exact:
2453 ui.warn(_('file not managed: %s\n') % rel)
2453 ui.warn(_('file not managed: %s\n') % rel)
2454 continue
2454 continue
2455 # file has not changed in dirstate
2455 # file has not changed in dirstate
2456 if node == parent:
2456 if node == parent:
2457 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2457 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2458 continue
2458 continue
2459 if pmf is None:
2459 if pmf is None:
2460 # only need parent manifest in this unlikely case,
2460 # only need parent manifest in this unlikely case,
2461 # so do not read by default
2461 # so do not read by default
2462 pmf = repo.changectx(parent).manifest()
2462 pmf = repo.changectx(parent).manifest()
2463 if abs in pmf:
2463 if abs in pmf:
2464 if mfentry:
2464 if mfentry:
2465 # if version of file is same in parent and target
2465 # if version of file is same in parent and target
2466 # manifests, do nothing
2466 # manifests, do nothing
2467 if (pmf[abs] != mfentry or
2467 if (pmf[abs] != mfentry or
2468 pmf.flags(abs) != mf.flags(abs)):
2468 pmf.flags(abs) != mf.flags(abs)):
2469 handle(revert, False)
2469 handle(revert, False)
2470 else:
2470 else:
2471 handle(remove, False)
2471 handle(remove, False)
2472
2472
2473 if not opts.get('dry_run'):
2473 if not opts.get('dry_run'):
2474 def checkout(f):
2474 def checkout(f):
2475 fc = ctx[f]
2475 fc = ctx[f]
2476 repo.wwrite(f, fc.data(), fc.fileflags())
2476 repo.wwrite(f, fc.data(), fc.fileflags())
2477
2477
2478 audit_path = util.path_auditor(repo.root)
2478 audit_path = util.path_auditor(repo.root)
2479 for f in remove[0]:
2479 for f in remove[0]:
2480 if repo.dirstate[f] == 'a':
2480 if repo.dirstate[f] == 'a':
2481 repo.dirstate.forget(f)
2481 repo.dirstate.forget(f)
2482 continue
2482 continue
2483 audit_path(f)
2483 audit_path(f)
2484 try:
2484 try:
2485 util.unlink(repo.wjoin(f))
2485 util.unlink(repo.wjoin(f))
2486 except OSError:
2486 except OSError:
2487 pass
2487 pass
2488 repo.dirstate.remove(f)
2488 repo.dirstate.remove(f)
2489
2489
2490 normal = None
2490 normal = None
2491 if node == parent:
2491 if node == parent:
2492 # We're reverting to our parent. If possible, we'd like status
2492 # We're reverting to our parent. If possible, we'd like status
2493 # to report the file as clean. We have to use normallookup for
2493 # to report the file as clean. We have to use normallookup for
2494 # merges to avoid losing information about merged/dirty files.
2494 # merges to avoid losing information about merged/dirty files.
2495 if p2 != nullid:
2495 if p2 != nullid:
2496 normal = repo.dirstate.normallookup
2496 normal = repo.dirstate.normallookup
2497 else:
2497 else:
2498 normal = repo.dirstate.normal
2498 normal = repo.dirstate.normal
2499 for f in revert[0]:
2499 for f in revert[0]:
2500 checkout(f)
2500 checkout(f)
2501 if normal:
2501 if normal:
2502 normal(f)
2502 normal(f)
2503
2503
2504 for f in add[0]:
2504 for f in add[0]:
2505 checkout(f)
2505 checkout(f)
2506 repo.dirstate.add(f)
2506 repo.dirstate.add(f)
2507
2507
2508 normal = repo.dirstate.normallookup
2508 normal = repo.dirstate.normallookup
2509 if node == parent and p2 == nullid:
2509 if node == parent and p2 == nullid:
2510 normal = repo.dirstate.normal
2510 normal = repo.dirstate.normal
2511 for f in undelete[0]:
2511 for f in undelete[0]:
2512 checkout(f)
2512 checkout(f)
2513 normal(f)
2513 normal(f)
2514
2514
2515 finally:
2515 finally:
2516 del wlock
2516 del wlock
2517
2517
2518 def rollback(ui, repo):
2518 def rollback(ui, repo):
2519 """roll back the last transaction
2519 """roll back the last transaction
2520
2520
2521 This command should be used with care. There is only one level of
2521 This command should be used with care. There is only one level of
2522 rollback, and there is no way to undo a rollback. It will also
2522 rollback, and there is no way to undo a rollback. It will also
2523 restore the dirstate at the time of the last transaction, losing
2523 restore the dirstate at the time of the last transaction, losing
2524 any dirstate changes since that time.
2524 any dirstate changes since that time.
2525
2525
2526 Transactions are used to encapsulate the effects of all commands
2526 Transactions are used to encapsulate the effects of all commands
2527 that create new changesets or propagate existing changesets into a
2527 that create new changesets or propagate existing changesets into a
2528 repository. For example, the following commands are transactional,
2528 repository. For example, the following commands are transactional,
2529 and their effects can be rolled back:
2529 and their effects can be rolled back:
2530
2530
2531 commit
2531 commit
2532 import
2532 import
2533 pull
2533 pull
2534 push (with this repository as destination)
2534 push (with this repository as destination)
2535 unbundle
2535 unbundle
2536
2536
2537 This command is not intended for use on public repositories. Once
2537 This command is not intended for use on public repositories. Once
2538 changes are visible for pull by other users, rolling a transaction
2538 changes are visible for pull by other users, rolling a transaction
2539 back locally is ineffective (someone else may already have pulled
2539 back locally is ineffective (someone else may already have pulled
2540 the changes). Furthermore, a race is possible with readers of the
2540 the changes). Furthermore, a race is possible with readers of the
2541 repository; for example an in-progress pull from the repository
2541 repository; for example an in-progress pull from the repository
2542 may fail if a rollback is performed.
2542 may fail if a rollback is performed.
2543 """
2543 """
2544 repo.rollback()
2544 repo.rollback()
2545
2545
2546 def root(ui, repo):
2546 def root(ui, repo):
2547 """print the root (top) of the current working dir
2547 """print the root (top) of the current working dir
2548
2548
2549 Print the root directory of the current repository.
2549 Print the root directory of the current repository.
2550 """
2550 """
2551 ui.write(repo.root + "\n")
2551 ui.write(repo.root + "\n")
2552
2552
2553 def serve(ui, repo, **opts):
2553 def serve(ui, repo, **opts):
2554 """export the repository via HTTP
2554 """export the repository via HTTP
2555
2555
2556 Start a local HTTP repository browser and pull server.
2556 Start a local HTTP repository browser and pull server.
2557
2557
2558 By default, the server logs accesses to stdout and errors to
2558 By default, the server logs accesses to stdout and errors to
2559 stderr. Use the "-A" and "-E" options to log to files.
2559 stderr. Use the "-A" and "-E" options to log to files.
2560 """
2560 """
2561
2561
2562 if opts["stdio"]:
2562 if opts["stdio"]:
2563 if repo is None:
2563 if repo is None:
2564 raise RepoError(_("There is no Mercurial repository here"
2564 raise RepoError(_("There is no Mercurial repository here"
2565 " (.hg not found)"))
2565 " (.hg not found)"))
2566 s = sshserver.sshserver(ui, repo)
2566 s = sshserver.sshserver(ui, repo)
2567 s.serve_forever()
2567 s.serve_forever()
2568
2568
2569 parentui = ui.parentui or ui
2569 parentui = ui.parentui or ui
2570 optlist = ("name templates style address port prefix ipv6"
2570 optlist = ("name templates style address port prefix ipv6"
2571 " accesslog errorlog webdir_conf certificate")
2571 " accesslog errorlog webdir_conf certificate")
2572 for o in optlist.split():
2572 for o in optlist.split():
2573 if opts[o]:
2573 if opts[o]:
2574 parentui.setconfig("web", o, str(opts[o]))
2574 parentui.setconfig("web", o, str(opts[o]))
2575 if (repo is not None) and (repo.ui != parentui):
2575 if (repo is not None) and (repo.ui != parentui):
2576 repo.ui.setconfig("web", o, str(opts[o]))
2576 repo.ui.setconfig("web", o, str(opts[o]))
2577
2577
2578 if repo is None and not ui.config("web", "webdir_conf"):
2578 if repo is None and not ui.config("web", "webdir_conf"):
2579 raise RepoError(_("There is no Mercurial repository here"
2579 raise RepoError(_("There is no Mercurial repository here"
2580 " (.hg not found)"))
2580 " (.hg not found)"))
2581
2581
2582 class service:
2582 class service:
2583 def init(self):
2583 def init(self):
2584 util.set_signal_handler()
2584 util.set_signal_handler()
2585 self.httpd = hgweb.server.create_server(parentui, repo)
2585 self.httpd = hgweb.server.create_server(parentui, repo)
2586
2586
2587 if not ui.verbose: return
2587 if not ui.verbose: return
2588
2588
2589 if self.httpd.prefix:
2589 if self.httpd.prefix:
2590 prefix = self.httpd.prefix.strip('/') + '/'
2590 prefix = self.httpd.prefix.strip('/') + '/'
2591 else:
2591 else:
2592 prefix = ''
2592 prefix = ''
2593
2593
2594 port = ':%d' % self.httpd.port
2594 port = ':%d' % self.httpd.port
2595 if port == ':80':
2595 if port == ':80':
2596 port = ''
2596 port = ''
2597
2597
2598 bindaddr = self.httpd.addr
2598 bindaddr = self.httpd.addr
2599 if bindaddr == '0.0.0.0':
2599 if bindaddr == '0.0.0.0':
2600 bindaddr = '*'
2600 bindaddr = '*'
2601 elif ':' in bindaddr: # IPv6
2601 elif ':' in bindaddr: # IPv6
2602 bindaddr = '[%s]' % bindaddr
2602 bindaddr = '[%s]' % bindaddr
2603
2603
2604 fqaddr = self.httpd.fqaddr
2604 fqaddr = self.httpd.fqaddr
2605 if ':' in fqaddr:
2605 if ':' in fqaddr:
2606 fqaddr = '[%s]' % fqaddr
2606 fqaddr = '[%s]' % fqaddr
2607 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2607 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2608 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2608 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2609
2609
2610 def run(self):
2610 def run(self):
2611 self.httpd.serve_forever()
2611 self.httpd.serve_forever()
2612
2612
2613 service = service()
2613 service = service()
2614
2614
2615 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2615 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2616
2616
2617 def status(ui, repo, *pats, **opts):
2617 def status(ui, repo, *pats, **opts):
2618 """show changed files in the working directory
2618 """show changed files in the working directory
2619
2619
2620 Show status of files in the repository. If names are given, only
2620 Show status of files in the repository. If names are given, only
2621 files that match are shown. Files that are clean or ignored or
2621 files that match are shown. Files that are clean or ignored or
2622 source of a copy/move operation, are not listed unless -c (clean),
2622 source of a copy/move operation, are not listed unless -c (clean),
2623 -i (ignored), -C (copies) or -A is given. Unless options described
2623 -i (ignored), -C (copies) or -A is given. Unless options described
2624 with "show only ..." are given, the options -mardu are used.
2624 with "show only ..." are given, the options -mardu are used.
2625
2625
2626 Option -q/--quiet hides untracked (unknown and ignored) files
2626 Option -q/--quiet hides untracked (unknown and ignored) files
2627 unless explicitly requested with -u/--unknown or -i/-ignored.
2627 unless explicitly requested with -u/--unknown or -i/-ignored.
2628
2628
2629 NOTE: status may appear to disagree with diff if permissions have
2629 NOTE: status may appear to disagree with diff if permissions have
2630 changed or a merge has occurred. The standard diff format does not
2630 changed or a merge has occurred. The standard diff format does not
2631 report permission changes and diff only reports changes relative
2631 report permission changes and diff only reports changes relative
2632 to one merge parent.
2632 to one merge parent.
2633
2633
2634 If one revision is given, it is used as the base revision.
2634 If one revision is given, it is used as the base revision.
2635 If two revisions are given, the difference between them is shown.
2635 If two revisions are given, the difference between them is shown.
2636
2636
2637 The codes used to show the status of files are:
2637 The codes used to show the status of files are:
2638 M = modified
2638 M = modified
2639 A = added
2639 A = added
2640 R = removed
2640 R = removed
2641 C = clean
2641 C = clean
2642 ! = deleted, but still tracked
2642 ! = deleted, but still tracked
2643 ? = not tracked
2643 ? = not tracked
2644 I = ignored
2644 I = ignored
2645 = the previous added file was copied from here
2645 = the previous added file was copied from here
2646 """
2646 """
2647
2647
2648 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2648 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2649 cwd = (pats and repo.getcwd()) or ''
2649 cwd = (pats and repo.getcwd()) or ''
2650 end = opts['print0'] and '\0' or '\n'
2650 end = opts['print0'] and '\0' or '\n'
2651 copy = {}
2651 copy = {}
2652 states = 'modified added removed deleted unknown ignored clean'.split()
2652 states = 'modified added removed deleted unknown ignored clean'.split()
2653 show = [k for k in states if opts[k]]
2653 show = [k for k in states if opts[k]]
2654 if opts['all']:
2654 if opts['all']:
2655 show += ui.quiet and (states[:4] + ['clean']) or states
2655 show += ui.quiet and (states[:4] + ['clean']) or states
2656 if not show:
2656 if not show:
2657 show = ui.quiet and states[:4] or states[:5]
2657 show = ui.quiet and states[:4] or states[:5]
2658
2658
2659 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2659 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2660 'ignored' in show, 'clean' in show, 'unknown' in show)
2660 'ignored' in show, 'clean' in show, 'unknown' in show)
2661 changestates = zip(states, 'MAR!?IC', stat)
2661 changestates = zip(states, 'MAR!?IC', stat)
2662
2662
2663 if (opts['all'] or opts['copies']) and not opts['no_status']:
2663 if (opts['all'] or opts['copies']) and not opts['no_status']:
2664 ctxn = repo.changectx(nullid)
2664 ctxn = repo.changectx(nullid)
2665 ctx1 = repo.changectx(node1)
2665 ctx1 = repo.changectx(node1)
2666 ctx2 = repo.changectx(node2)
2666 ctx2 = repo.changectx(node2)
2667 added = stat[1]
2667 added = stat[1]
2668 if node2 is None:
2668 if node2 is None:
2669 added = stat[0] + stat[1] # merged?
2669 added = stat[0] + stat[1] # merged?
2670 ctx2 = repo.workingctx()
2670 ctx2 = repo.workingctx()
2671 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2671 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2672 if k in added:
2672 if k in added:
2673 copy[k] = v
2673 copy[k] = v
2674 elif v in added:
2674 elif v in added:
2675 copy[v] = k
2675 copy[v] = k
2676
2676
2677 for state, char, files in changestates:
2677 for state, char, files in changestates:
2678 if state in show:
2678 if state in show:
2679 format = "%s %%s%s" % (char, end)
2679 format = "%s %%s%s" % (char, end)
2680 if opts['no_status']:
2680 if opts['no_status']:
2681 format = "%%s%s" % end
2681 format = "%%s%s" % end
2682
2682
2683 for f in files:
2683 for f in files:
2684 ui.write(format % repo.pathto(f, cwd))
2684 ui.write(format % repo.pathto(f, cwd))
2685 if f in copy:
2685 if f in copy:
2686 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2686 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2687
2687
2688 def tag(ui, repo, name1, *names, **opts):
2688 def tag(ui, repo, name1, *names, **opts):
2689 """add one or more tags for the current or given revision
2689 """add one or more tags for the current or given revision
2690
2690
2691 Name a particular revision using <name>.
2691 Name a particular revision using <name>.
2692
2692
2693 Tags are used to name particular revisions of the repository and are
2693 Tags are used to name particular revisions of the repository and are
2694 very useful to compare different revisions, to go back to significant
2694 very useful to compare different revisions, to go back to significant
2695 earlier versions or to mark branch points as releases, etc.
2695 earlier versions or to mark branch points as releases, etc.
2696
2696
2697 If no revision is given, the parent of the working directory is used,
2697 If no revision is given, the parent of the working directory is used,
2698 or tip if no revision is checked out.
2698 or tip if no revision is checked out.
2699
2699
2700 To facilitate version control, distribution, and merging of tags,
2700 To facilitate version control, distribution, and merging of tags,
2701 they are stored as a file named ".hgtags" which is managed
2701 they are stored as a file named ".hgtags" which is managed
2702 similarly to other project files and can be hand-edited if
2702 similarly to other project files and can be hand-edited if
2703 necessary. The file '.hg/localtags' is used for local tags (not
2703 necessary. The file '.hg/localtags' is used for local tags (not
2704 shared among repositories).
2704 shared among repositories).
2705
2705
2706 See 'hg help dates' for a list of formats valid for -d/--date.
2706 See 'hg help dates' for a list of formats valid for -d/--date.
2707 """
2707 """
2708
2708
2709 rev_ = None
2709 rev_ = None
2710 names = (name1,) + names
2710 names = (name1,) + names
2711 if len(names) != len(dict.fromkeys(names)):
2711 if len(names) != len(dict.fromkeys(names)):
2712 raise util.Abort(_('tag names must be unique'))
2712 raise util.Abort(_('tag names must be unique'))
2713 for n in names:
2713 for n in names:
2714 if n in ['tip', '.', 'null']:
2714 if n in ['tip', '.', 'null']:
2715 raise util.Abort(_('the name \'%s\' is reserved') % n)
2715 raise util.Abort(_('the name \'%s\' is reserved') % n)
2716 if opts['rev'] and opts['remove']:
2716 if opts['rev'] and opts['remove']:
2717 raise util.Abort(_("--rev and --remove are incompatible"))
2717 raise util.Abort(_("--rev and --remove are incompatible"))
2718 if opts['rev']:
2718 if opts['rev']:
2719 rev_ = opts['rev']
2719 rev_ = opts['rev']
2720 message = opts['message']
2720 message = opts['message']
2721 if opts['remove']:
2721 if opts['remove']:
2722 expectedtype = opts['local'] and 'local' or 'global'
2722 expectedtype = opts['local'] and 'local' or 'global'
2723 for n in names:
2723 for n in names:
2724 if not repo.tagtype(n):
2724 if not repo.tagtype(n):
2725 raise util.Abort(_('tag \'%s\' does not exist') % n)
2725 raise util.Abort(_('tag \'%s\' does not exist') % n)
2726 if repo.tagtype(n) != expectedtype:
2726 if repo.tagtype(n) != expectedtype:
2727 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2727 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2728 (n, expectedtype))
2728 (n, expectedtype))
2729 rev_ = nullid
2729 rev_ = nullid
2730 if not message:
2730 if not message:
2731 message = _('Removed tag %s') % ', '.join(names)
2731 message = _('Removed tag %s') % ', '.join(names)
2732 elif not opts['force']:
2732 elif not opts['force']:
2733 for n in names:
2733 for n in names:
2734 if n in repo.tags():
2734 if n in repo.tags():
2735 raise util.Abort(_('tag \'%s\' already exists '
2735 raise util.Abort(_('tag \'%s\' already exists '
2736 '(use -f to force)') % n)
2736 '(use -f to force)') % n)
2737 if not rev_ and repo.dirstate.parents()[1] != nullid:
2737 if not rev_ and repo.dirstate.parents()[1] != nullid:
2738 raise util.Abort(_('uncommitted merge - please provide a '
2738 raise util.Abort(_('uncommitted merge - please provide a '
2739 'specific revision'))
2739 'specific revision'))
2740 r = repo.changectx(rev_).node()
2740 r = repo.changectx(rev_).node()
2741
2741
2742 if not message:
2742 if not message:
2743 message = (_('Added tag %s for changeset %s') %
2743 message = (_('Added tag %s for changeset %s') %
2744 (', '.join(names), short(r)))
2744 (', '.join(names), short(r)))
2745
2745
2746 date = opts.get('date')
2746 date = opts.get('date')
2747 if date:
2747 if date:
2748 date = util.parsedate(date)
2748 date = util.parsedate(date)
2749
2749
2750 repo.tag(names, r, message, opts['local'], opts['user'], date)
2750 repo.tag(names, r, message, opts['local'], opts['user'], date)
2751
2751
2752 def tags(ui, repo):
2752 def tags(ui, repo):
2753 """list repository tags
2753 """list repository tags
2754
2754
2755 List the repository tags.
2755 List the repository tags.
2756
2756
2757 This lists both regular and local tags. When the -v/--verbose switch
2757 This lists both regular and local tags. When the -v/--verbose switch
2758 is used, a third column "local" is printed for local tags.
2758 is used, a third column "local" is printed for local tags.
2759 """
2759 """
2760
2760
2761 l = repo.tagslist()
2761 l = repo.tagslist()
2762 l.reverse()
2762 l.reverse()
2763 hexfunc = ui.debugflag and hex or short
2763 hexfunc = ui.debugflag and hex or short
2764 tagtype = ""
2764 tagtype = ""
2765
2765
2766 for t, n in l:
2766 for t, n in l:
2767 if ui.quiet:
2767 if ui.quiet:
2768 ui.write("%s\n" % t)
2768 ui.write("%s\n" % t)
2769 continue
2769 continue
2770
2770
2771 try:
2771 try:
2772 hn = hexfunc(n)
2772 hn = hexfunc(n)
2773 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2773 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2774 except revlog.LookupError:
2774 except revlog.LookupError:
2775 r = " ?:%s" % hn
2775 r = " ?:%s" % hn
2776 else:
2776 else:
2777 spaces = " " * (30 - util.locallen(t))
2777 spaces = " " * (30 - util.locallen(t))
2778 if ui.verbose:
2778 if ui.verbose:
2779 if repo.tagtype(t) == 'local':
2779 if repo.tagtype(t) == 'local':
2780 tagtype = " local"
2780 tagtype = " local"
2781 else:
2781 else:
2782 tagtype = ""
2782 tagtype = ""
2783 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2783 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2784
2784
2785 def tip(ui, repo, **opts):
2785 def tip(ui, repo, **opts):
2786 """show the tip revision
2786 """show the tip revision
2787
2787
2788 The tip revision (usually just called the tip) is the most
2788 The tip revision (usually just called the tip) is the most
2789 recently added changeset in the repository, the most recently
2789 recently added changeset in the repository, the most recently
2790 changed head.
2790 changed head.
2791
2791
2792 If you have just made a commit, that commit will be the tip. If
2792 If you have just made a commit, that commit will be the tip. If
2793 you have just pulled changes from another repository, the tip of
2793 you have just pulled changes from another repository, the tip of
2794 that repository becomes the current tip. The "tip" tag is special
2794 that repository becomes the current tip. The "tip" tag is special
2795 and cannot be renamed or assigned to a different changeset.
2795 and cannot be renamed or assigned to a different changeset.
2796 """
2796 """
2797 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2797 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2798
2798
2799 def unbundle(ui, repo, fname1, *fnames, **opts):
2799 def unbundle(ui, repo, fname1, *fnames, **opts):
2800 """apply one or more changegroup files
2800 """apply one or more changegroup files
2801
2801
2802 Apply one or more compressed changegroup files generated by the
2802 Apply one or more compressed changegroup files generated by the
2803 bundle command.
2803 bundle command.
2804 """
2804 """
2805 fnames = (fname1,) + fnames
2805 fnames = (fname1,) + fnames
2806
2806
2807 lock = None
2807 lock = None
2808 try:
2808 try:
2809 lock = repo.lock()
2809 lock = repo.lock()
2810 for fname in fnames:
2810 for fname in fnames:
2811 if os.path.exists(fname):
2811 if os.path.exists(fname):
2812 f = open(fname, "rb")
2812 f = open(fname, "rb")
2813 else:
2813 else:
2814 f = urllib.urlopen(fname)
2814 f = urllib.urlopen(fname)
2815 gen = changegroup.readbundle(f, fname)
2815 gen = changegroup.readbundle(f, fname)
2816 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2816 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2817 finally:
2817 finally:
2818 del lock
2818 del lock
2819
2819
2820 return postincoming(ui, repo, modheads, opts['update'], None)
2820 return postincoming(ui, repo, modheads, opts['update'], None)
2821
2821
2822 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2822 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2823 """update working directory
2823 """update working directory
2824
2824
2825 Update the working directory to the specified revision, or the
2825 Update the working directory to the specified revision, or the
2826 tip of the current branch if none is specified.
2826 tip of the current branch if none is specified.
2827
2827
2828 If the requested revision is a descendant of the working
2828 If the requested revision is a descendant of the working
2829 directory, any outstanding changes in the working directory will
2829 directory, any outstanding changes in the working directory will
2830 be merged into the result. If it is not directly descended but is
2830 be merged into the result. If it is not directly descended but is
2831 on the same named branch, update aborts with a suggestion to use
2831 on the same named branch, update aborts with a suggestion to use
2832 merge or update -C instead.
2832 merge or update -C instead.
2833
2833
2834 If the requested revision is on a different named branch and the
2834 If the requested revision is on a different named branch and the
2835 working directory is clean, update quietly switches branches.
2835 working directory is clean, update quietly switches branches.
2836
2836
2837 See 'hg help dates' for a list of formats valid for --date.
2837 See 'hg help dates' for a list of formats valid for --date.
2838 """
2838 """
2839 if rev and node:
2839 if rev and node:
2840 raise util.Abort(_("please specify just one revision"))
2840 raise util.Abort(_("please specify just one revision"))
2841
2841
2842 if not rev:
2842 if not rev:
2843 rev = node
2843 rev = node
2844
2844
2845 if date:
2845 if date:
2846 if rev:
2846 if rev:
2847 raise util.Abort(_("you can't specify a revision and a date"))
2847 raise util.Abort(_("you can't specify a revision and a date"))
2848 rev = cmdutil.finddate(ui, repo, date)
2848 rev = cmdutil.finddate(ui, repo, date)
2849
2849
2850 if clean:
2850 if clean:
2851 return hg.clean(repo, rev)
2851 return hg.clean(repo, rev)
2852 else:
2852 else:
2853 return hg.update(repo, rev)
2853 return hg.update(repo, rev)
2854
2854
2855 def verify(ui, repo):
2855 def verify(ui, repo):
2856 """verify the integrity of the repository
2856 """verify the integrity of the repository
2857
2857
2858 Verify the integrity of the current repository.
2858 Verify the integrity of the current repository.
2859
2859
2860 This will perform an extensive check of the repository's
2860 This will perform an extensive check of the repository's
2861 integrity, validating the hashes and checksums of each entry in
2861 integrity, validating the hashes and checksums of each entry in
2862 the changelog, manifest, and tracked files, as well as the
2862 the changelog, manifest, and tracked files, as well as the
2863 integrity of their crosslinks and indices.
2863 integrity of their crosslinks and indices.
2864 """
2864 """
2865 return hg.verify(repo)
2865 return hg.verify(repo)
2866
2866
2867 def version_(ui):
2867 def version_(ui):
2868 """output version and copyright information"""
2868 """output version and copyright information"""
2869 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2869 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2870 % version.get_version())
2870 % version.get_version())
2871 ui.status(_(
2871 ui.status(_(
2872 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2872 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2873 "This is free software; see the source for copying conditions. "
2873 "This is free software; see the source for copying conditions. "
2874 "There is NO\nwarranty; "
2874 "There is NO\nwarranty; "
2875 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2875 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2876 ))
2876 ))
2877
2877
2878 # Command options and aliases are listed here, alphabetically
2878 # Command options and aliases are listed here, alphabetically
2879
2879
2880 globalopts = [
2880 globalopts = [
2881 ('R', 'repository', '',
2881 ('R', 'repository', '',
2882 _('repository root directory or symbolic path name')),
2882 _('repository root directory or symbolic path name')),
2883 ('', 'cwd', '', _('change working directory')),
2883 ('', 'cwd', '', _('change working directory')),
2884 ('y', 'noninteractive', None,
2884 ('y', 'noninteractive', None,
2885 _('do not prompt, assume \'yes\' for any required answers')),
2885 _('do not prompt, assume \'yes\' for any required answers')),
2886 ('q', 'quiet', None, _('suppress output')),
2886 ('q', 'quiet', None, _('suppress output')),
2887 ('v', 'verbose', None, _('enable additional output')),
2887 ('v', 'verbose', None, _('enable additional output')),
2888 ('', 'config', [], _('set/override config option')),
2888 ('', 'config', [], _('set/override config option')),
2889 ('', 'debug', None, _('enable debugging output')),
2889 ('', 'debug', None, _('enable debugging output')),
2890 ('', 'debugger', None, _('start debugger')),
2890 ('', 'debugger', None, _('start debugger')),
2891 ('', 'encoding', util._encoding, _('set the charset encoding')),
2891 ('', 'encoding', util._encoding, _('set the charset encoding')),
2892 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2892 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2893 ('', 'lsprof', None, _('print improved command execution profile')),
2893 ('', 'lsprof', None, _('print improved command execution profile')),
2894 ('', 'traceback', None, _('print traceback on exception')),
2894 ('', 'traceback', None, _('print traceback on exception')),
2895 ('', 'time', None, _('time how long the command takes')),
2895 ('', 'time', None, _('time how long the command takes')),
2896 ('', 'profile', None, _('print command execution profile')),
2896 ('', 'profile', None, _('print command execution profile')),
2897 ('', 'version', None, _('output version information and exit')),
2897 ('', 'version', None, _('output version information and exit')),
2898 ('h', 'help', None, _('display help and exit')),
2898 ('h', 'help', None, _('display help and exit')),
2899 ]
2899 ]
2900
2900
2901 dryrunopts = [('n', 'dry-run', None,
2901 dryrunopts = [('n', 'dry-run', None,
2902 _('do not perform actions, just print output'))]
2902 _('do not perform actions, just print output'))]
2903
2903
2904 remoteopts = [
2904 remoteopts = [
2905 ('e', 'ssh', '', _('specify ssh command to use')),
2905 ('e', 'ssh', '', _('specify ssh command to use')),
2906 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2906 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2907 ]
2907 ]
2908
2908
2909 walkopts = [
2909 walkopts = [
2910 ('I', 'include', [], _('include names matching the given patterns')),
2910 ('I', 'include', [], _('include names matching the given patterns')),
2911 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2911 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2912 ]
2912 ]
2913
2913
2914 commitopts = [
2914 commitopts = [
2915 ('m', 'message', '', _('use <text> as commit message')),
2915 ('m', 'message', '', _('use <text> as commit message')),
2916 ('l', 'logfile', '', _('read commit message from <file>')),
2916 ('l', 'logfile', '', _('read commit message from <file>')),
2917 ]
2917 ]
2918
2918
2919 commitopts2 = [
2919 commitopts2 = [
2920 ('d', 'date', '', _('record datecode as commit date')),
2920 ('d', 'date', '', _('record datecode as commit date')),
2921 ('u', 'user', '', _('record user as committer')),
2921 ('u', 'user', '', _('record user as committer')),
2922 ]
2922 ]
2923
2923
2924 templateopts = [
2924 templateopts = [
2925 ('', 'style', '', _('display using template map file')),
2925 ('', 'style', '', _('display using template map file')),
2926 ('', 'template', '', _('display with template')),
2926 ('', 'template', '', _('display with template')),
2927 ]
2927 ]
2928
2928
2929 logopts = [
2929 logopts = [
2930 ('p', 'patch', None, _('show patch')),
2930 ('p', 'patch', None, _('show patch')),
2931 ('l', 'limit', '', _('limit number of changes displayed')),
2931 ('l', 'limit', '', _('limit number of changes displayed')),
2932 ('M', 'no-merges', None, _('do not show merges')),
2932 ('M', 'no-merges', None, _('do not show merges')),
2933 ] + templateopts
2933 ] + templateopts
2934
2934
2935 diffopts = [
2936 ('a', 'text', None, _('treat all files as text')),
2937 ('g', 'git', None, _('use git extended diff format')),
2938 ('', 'nodates', None, _("don't include dates in diff headers"))
2939 ]
2940
2941 diffopts2 = [
2942 ('p', 'show-function', None, _('show which function each change is in')),
2943 ('w', 'ignore-all-space', None,
2944 _('ignore white space when comparing lines')),
2945 ('b', 'ignore-space-change', None,
2946 _('ignore changes in the amount of white space')),
2947 ('B', 'ignore-blank-lines', None,
2948 _('ignore changes whose lines are all blank')),
2949 ('U', 'unified', '', _('number of lines of context to show'))
2950 ]
2951
2935 table = {
2952 table = {
2936 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2953 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2937 "addremove":
2954 "addremove":
2938 (addremove,
2955 (addremove,
2939 [('s', 'similarity', '',
2956 [('s', 'similarity', '',
2940 _('guess renamed files by similarity (0<=s<=100)')),
2957 _('guess renamed files by similarity (0<=s<=100)')),
2941 ] + walkopts + dryrunopts,
2958 ] + walkopts + dryrunopts,
2942 _('hg addremove [OPTION]... [FILE]...')),
2959 _('hg addremove [OPTION]... [FILE]...')),
2943 "^annotate|blame":
2960 "^annotate|blame":
2944 (annotate,
2961 (annotate,
2945 [('r', 'rev', '', _('annotate the specified revision')),
2962 [('r', 'rev', '', _('annotate the specified revision')),
2946 ('f', 'follow', None, _('follow file copies and renames')),
2963 ('f', 'follow', None, _('follow file copies and renames')),
2947 ('a', 'text', None, _('treat all files as text')),
2964 ('a', 'text', None, _('treat all files as text')),
2948 ('u', 'user', None, _('list the author (long with -v)')),
2965 ('u', 'user', None, _('list the author (long with -v)')),
2949 ('d', 'date', None, _('list the date (short with -q)')),
2966 ('d', 'date', None, _('list the date (short with -q)')),
2950 ('n', 'number', None, _('list the revision number (default)')),
2967 ('n', 'number', None, _('list the revision number (default)')),
2951 ('c', 'changeset', None, _('list the changeset')),
2968 ('c', 'changeset', None, _('list the changeset')),
2952 ('l', 'line-number', None,
2969 ('l', 'line-number', None,
2953 _('show line number at the first appearance'))
2970 _('show line number at the first appearance'))
2954 ] + walkopts,
2971 ] + walkopts,
2955 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2972 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2956 "archive":
2973 "archive":
2957 (archive,
2974 (archive,
2958 [('', 'no-decode', None, _('do not pass files through decoders')),
2975 [('', 'no-decode', None, _('do not pass files through decoders')),
2959 ('p', 'prefix', '', _('directory prefix for files in archive')),
2976 ('p', 'prefix', '', _('directory prefix for files in archive')),
2960 ('r', 'rev', '', _('revision to distribute')),
2977 ('r', 'rev', '', _('revision to distribute')),
2961 ('t', 'type', '', _('type of distribution to create')),
2978 ('t', 'type', '', _('type of distribution to create')),
2962 ] + walkopts,
2979 ] + walkopts,
2963 _('hg archive [OPTION]... DEST')),
2980 _('hg archive [OPTION]... DEST')),
2964 "backout":
2981 "backout":
2965 (backout,
2982 (backout,
2966 [('', 'merge', None,
2983 [('', 'merge', None,
2967 _('merge with old dirstate parent after backout')),
2984 _('merge with old dirstate parent after backout')),
2968 ('', 'parent', '', _('parent to choose when backing out merge')),
2985 ('', 'parent', '', _('parent to choose when backing out merge')),
2969 ('r', 'rev', '', _('revision to backout')),
2986 ('r', 'rev', '', _('revision to backout')),
2970 ] + walkopts + commitopts + commitopts2,
2987 ] + walkopts + commitopts + commitopts2,
2971 _('hg backout [OPTION]... [-r] REV')),
2988 _('hg backout [OPTION]... [-r] REV')),
2972 "bisect":
2989 "bisect":
2973 (bisect,
2990 (bisect,
2974 [('r', 'reset', False, _('reset bisect state')),
2991 [('r', 'reset', False, _('reset bisect state')),
2975 ('g', 'good', False, _('mark changeset good')),
2992 ('g', 'good', False, _('mark changeset good')),
2976 ('b', 'bad', False, _('mark changeset bad')),
2993 ('b', 'bad', False, _('mark changeset bad')),
2977 ('s', 'skip', False, _('skip testing changeset')),
2994 ('s', 'skip', False, _('skip testing changeset')),
2978 ('U', 'noupdate', False, _('do not update to target'))],
2995 ('U', 'noupdate', False, _('do not update to target'))],
2979 _("hg bisect [-gbsr] [REV]")),
2996 _("hg bisect [-gbsr] [REV]")),
2980 "branch":
2997 "branch":
2981 (branch,
2998 (branch,
2982 [('f', 'force', None,
2999 [('f', 'force', None,
2983 _('set branch name even if it shadows an existing branch'))],
3000 _('set branch name even if it shadows an existing branch'))],
2984 _('hg branch [-f] [NAME]')),
3001 _('hg branch [-f] [NAME]')),
2985 "branches":
3002 "branches":
2986 (branches,
3003 (branches,
2987 [('a', 'active', False,
3004 [('a', 'active', False,
2988 _('show only branches that have unmerged heads'))],
3005 _('show only branches that have unmerged heads'))],
2989 _('hg branches [-a]')),
3006 _('hg branches [-a]')),
2990 "bundle":
3007 "bundle":
2991 (bundle,
3008 (bundle,
2992 [('f', 'force', None,
3009 [('f', 'force', None,
2993 _('run even when remote repository is unrelated')),
3010 _('run even when remote repository is unrelated')),
2994 ('r', 'rev', [],
3011 ('r', 'rev', [],
2995 _('a changeset up to which you would like to bundle')),
3012 _('a changeset up to which you would like to bundle')),
2996 ('', 'base', [],
3013 ('', 'base', [],
2997 _('a base changeset to specify instead of a destination')),
3014 _('a base changeset to specify instead of a destination')),
2998 ('a', 'all', None, _('bundle all changesets in the repository')),
3015 ('a', 'all', None, _('bundle all changesets in the repository')),
2999 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3016 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3000 ] + remoteopts,
3017 ] + remoteopts,
3001 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3018 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3002 "cat":
3019 "cat":
3003 (cat,
3020 (cat,
3004 [('o', 'output', '', _('print output to file with formatted name')),
3021 [('o', 'output', '', _('print output to file with formatted name')),
3005 ('r', 'rev', '', _('print the given revision')),
3022 ('r', 'rev', '', _('print the given revision')),
3006 ('', 'decode', None, _('apply any matching decode filter')),
3023 ('', 'decode', None, _('apply any matching decode filter')),
3007 ] + walkopts,
3024 ] + walkopts,
3008 _('hg cat [OPTION]... FILE...')),
3025 _('hg cat [OPTION]... FILE...')),
3009 "^clone":
3026 "^clone":
3010 (clone,
3027 (clone,
3011 [('U', 'noupdate', None,
3028 [('U', 'noupdate', None,
3012 _('the clone will only contain a repository (no working copy)')),
3029 _('the clone will only contain a repository (no working copy)')),
3013 ('r', 'rev', [],
3030 ('r', 'rev', [],
3014 _('a changeset you would like to have after cloning')),
3031 _('a changeset you would like to have after cloning')),
3015 ('', 'pull', None, _('use pull protocol to copy metadata')),
3032 ('', 'pull', None, _('use pull protocol to copy metadata')),
3016 ('', 'uncompressed', None,
3033 ('', 'uncompressed', None,
3017 _('use uncompressed transfer (fast over LAN)')),
3034 _('use uncompressed transfer (fast over LAN)')),
3018 ] + remoteopts,
3035 ] + remoteopts,
3019 _('hg clone [OPTION]... SOURCE [DEST]')),
3036 _('hg clone [OPTION]... SOURCE [DEST]')),
3020 "^commit|ci":
3037 "^commit|ci":
3021 (commit,
3038 (commit,
3022 [('A', 'addremove', None,
3039 [('A', 'addremove', None,
3023 _('mark new/missing files as added/removed before committing')),
3040 _('mark new/missing files as added/removed before committing')),
3024 ] + walkopts + commitopts + commitopts2,
3041 ] + walkopts + commitopts + commitopts2,
3025 _('hg commit [OPTION]... [FILE]...')),
3042 _('hg commit [OPTION]... [FILE]...')),
3026 "copy|cp":
3043 "copy|cp":
3027 (copy,
3044 (copy,
3028 [('A', 'after', None, _('record a copy that has already occurred')),
3045 [('A', 'after', None, _('record a copy that has already occurred')),
3029 ('f', 'force', None,
3046 ('f', 'force', None,
3030 _('forcibly copy over an existing managed file')),
3047 _('forcibly copy over an existing managed file')),
3031 ] + walkopts + dryrunopts,
3048 ] + walkopts + dryrunopts,
3032 _('hg copy [OPTION]... [SOURCE]... DEST')),
3049 _('hg copy [OPTION]... [SOURCE]... DEST')),
3033 "debugancestor": (debugancestor, [],
3050 "debugancestor": (debugancestor, [],
3034 _('hg debugancestor [INDEX] REV1 REV2')),
3051 _('hg debugancestor [INDEX] REV1 REV2')),
3035 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3052 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3036 "debugcomplete":
3053 "debugcomplete":
3037 (debugcomplete,
3054 (debugcomplete,
3038 [('o', 'options', None, _('show the command options'))],
3055 [('o', 'options', None, _('show the command options'))],
3039 _('hg debugcomplete [-o] CMD')),
3056 _('hg debugcomplete [-o] CMD')),
3040 "debugdate":
3057 "debugdate":
3041 (debugdate,
3058 (debugdate,
3042 [('e', 'extended', None, _('try extended date formats'))],
3059 [('e', 'extended', None, _('try extended date formats'))],
3043 _('hg debugdate [-e] DATE [RANGE]')),
3060 _('hg debugdate [-e] DATE [RANGE]')),
3044 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3061 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3045 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3062 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3046 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3063 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3047 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3064 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3048 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3065 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3049 "debugrawcommit|rawcommit":
3066 "debugrawcommit|rawcommit":
3050 (rawcommit,
3067 (rawcommit,
3051 [('p', 'parent', [], _('parent')),
3068 [('p', 'parent', [], _('parent')),
3052 ('F', 'files', '', _('file list'))
3069 ('F', 'files', '', _('file list'))
3053 ] + commitopts + commitopts2,
3070 ] + commitopts + commitopts2,
3054 _('hg debugrawcommit [OPTION]... [FILE]...')),
3071 _('hg debugrawcommit [OPTION]... [FILE]...')),
3055 "debugrebuildstate":
3072 "debugrebuildstate":
3056 (debugrebuildstate,
3073 (debugrebuildstate,
3057 [('r', 'rev', '', _('revision to rebuild to'))],
3074 [('r', 'rev', '', _('revision to rebuild to'))],
3058 _('hg debugrebuildstate [-r REV] [REV]')),
3075 _('hg debugrebuildstate [-r REV] [REV]')),
3059 "debugrename":
3076 "debugrename":
3060 (debugrename,
3077 (debugrename,
3061 [('r', 'rev', '', _('revision to debug'))],
3078 [('r', 'rev', '', _('revision to debug'))],
3062 _('hg debugrename [-r REV] FILE')),
3079 _('hg debugrename [-r REV] FILE')),
3063 "debugsetparents":
3080 "debugsetparents":
3064 (debugsetparents,
3081 (debugsetparents,
3065 [],
3082 [],
3066 _('hg debugsetparents REV1 [REV2]')),
3083 _('hg debugsetparents REV1 [REV2]')),
3067 "debugstate":
3084 "debugstate":
3068 (debugstate,
3085 (debugstate,
3069 [('', 'nodates', None, _('do not display the saved mtime'))],
3086 [('', 'nodates', None, _('do not display the saved mtime'))],
3070 _('hg debugstate [OPTS]')),
3087 _('hg debugstate [OPTS]')),
3071 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3088 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3072 "^diff":
3089 "^diff":
3073 (diff,
3090 (diff,
3074 [('r', 'rev', [], _('revision')),
3091 [('r', 'rev', [], _('revision'))
3075 ('a', 'text', None, _('treat all files as text')),
3092 ] + diffopts + diffopts2 + walkopts,
3076 ('p', 'show-function', None,
3077 _('show which function each change is in')),
3078 ('g', 'git', None, _('use git extended diff format')),
3079 ('', 'nodates', None, _("don't include dates in diff headers")),
3080 ('w', 'ignore-all-space', None,
3081 _('ignore white space when comparing lines')),
3082 ('b', 'ignore-space-change', None,
3083 _('ignore changes in the amount of white space')),
3084 ('B', 'ignore-blank-lines', None,
3085 _('ignore changes whose lines are all blank')),
3086 ('U', 'unified', '',
3087 _('number of lines of context to show'))
3088 ] + walkopts,
3089 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3093 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3090 "^export":
3094 "^export":
3091 (export,
3095 (export,
3092 [('o', 'output', '', _('print output to file with formatted name')),
3096 [('o', 'output', '', _('print output to file with formatted name')),
3093 ('a', 'text', None, _('treat all files as text')),
3097 ('', 'switch-parent', None, _('diff against the second parent'))
3094 ('g', 'git', None, _('use git extended diff format')),
3098 ] + diffopts,
3095 ('', 'nodates', None, _("don't include dates in diff headers")),
3096 ('', 'switch-parent', None, _('diff against the second parent'))],
3097 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3099 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3098 "grep":
3100 "grep":
3099 (grep,
3101 (grep,
3100 [('0', 'print0', None, _('end fields with NUL')),
3102 [('0', 'print0', None, _('end fields with NUL')),
3101 ('', 'all', None, _('print all revisions that match')),
3103 ('', 'all', None, _('print all revisions that match')),
3102 ('f', 'follow', None,
3104 ('f', 'follow', None,
3103 _('follow changeset history, or file history across copies and renames')),
3105 _('follow changeset history, or file history across copies and renames')),
3104 ('i', 'ignore-case', None, _('ignore case when matching')),
3106 ('i', 'ignore-case', None, _('ignore case when matching')),
3105 ('l', 'files-with-matches', None,
3107 ('l', 'files-with-matches', None,
3106 _('print only filenames and revs that match')),
3108 _('print only filenames and revs that match')),
3107 ('n', 'line-number', None, _('print matching line numbers')),
3109 ('n', 'line-number', None, _('print matching line numbers')),
3108 ('r', 'rev', [], _('search in given revision range')),
3110 ('r', 'rev', [], _('search in given revision range')),
3109 ('u', 'user', None, _('list the author (long with -v)')),
3111 ('u', 'user', None, _('list the author (long with -v)')),
3110 ('d', 'date', None, _('list the date (short with -q)')),
3112 ('d', 'date', None, _('list the date (short with -q)')),
3111 ] + walkopts,
3113 ] + walkopts,
3112 _('hg grep [OPTION]... PATTERN [FILE]...')),
3114 _('hg grep [OPTION]... PATTERN [FILE]...')),
3113 "heads":
3115 "heads":
3114 (heads,
3116 (heads,
3115 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3117 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3116 ] + templateopts,
3118 ] + templateopts,
3117 _('hg heads [-r REV] [REV]...')),
3119 _('hg heads [-r REV] [REV]...')),
3118 "help": (help_, [], _('hg help [COMMAND]')),
3120 "help": (help_, [], _('hg help [COMMAND]')),
3119 "identify|id":
3121 "identify|id":
3120 (identify,
3122 (identify,
3121 [('r', 'rev', '', _('identify the specified rev')),
3123 [('r', 'rev', '', _('identify the specified rev')),
3122 ('n', 'num', None, _('show local revision number')),
3124 ('n', 'num', None, _('show local revision number')),
3123 ('i', 'id', None, _('show global revision id')),
3125 ('i', 'id', None, _('show global revision id')),
3124 ('b', 'branch', None, _('show branch')),
3126 ('b', 'branch', None, _('show branch')),
3125 ('t', 'tags', None, _('show tags'))],
3127 ('t', 'tags', None, _('show tags'))],
3126 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3128 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3127 "import|patch":
3129 "import|patch":
3128 (import_,
3130 (import_,
3129 [('p', 'strip', 1,
3131 [('p', 'strip', 1,
3130 _('directory strip option for patch. This has the same\n'
3132 _('directory strip option for patch. This has the same\n'
3131 'meaning as the corresponding patch option')),
3133 'meaning as the corresponding patch option')),
3132 ('b', 'base', '', _('base path')),
3134 ('b', 'base', '', _('base path')),
3133 ('f', 'force', None,
3135 ('f', 'force', None,
3134 _('skip check for outstanding uncommitted changes')),
3136 _('skip check for outstanding uncommitted changes')),
3135 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3137 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3136 ('', 'exact', None,
3138 ('', 'exact', None,
3137 _('apply patch to the nodes from which it was generated')),
3139 _('apply patch to the nodes from which it was generated')),
3138 ('', 'import-branch', None,
3140 ('', 'import-branch', None,
3139 _('Use any branch information in patch (implied by --exact)'))] +
3141 _('Use any branch information in patch (implied by --exact)'))] +
3140 commitopts + commitopts2,
3142 commitopts + commitopts2,
3141 _('hg import [OPTION]... PATCH...')),
3143 _('hg import [OPTION]... PATCH...')),
3142 "incoming|in":
3144 "incoming|in":
3143 (incoming,
3145 (incoming,
3144 [('f', 'force', None,
3146 [('f', 'force', None,
3145 _('run even when remote repository is unrelated')),
3147 _('run even when remote repository is unrelated')),
3146 ('n', 'newest-first', None, _('show newest record first')),
3148 ('n', 'newest-first', None, _('show newest record first')),
3147 ('', 'bundle', '', _('file to store the bundles into')),
3149 ('', 'bundle', '', _('file to store the bundles into')),
3148 ('r', 'rev', [],
3150 ('r', 'rev', [],
3149 _('a specific revision up to which you would like to pull')),
3151 _('a specific revision up to which you would like to pull')),
3150 ] + logopts + remoteopts,
3152 ] + logopts + remoteopts,
3151 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3153 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3152 ' [--bundle FILENAME] [SOURCE]')),
3154 ' [--bundle FILENAME] [SOURCE]')),
3153 "^init":
3155 "^init":
3154 (init,
3156 (init,
3155 remoteopts,
3157 remoteopts,
3156 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3158 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3157 "locate":
3159 "locate":
3158 (locate,
3160 (locate,
3159 [('r', 'rev', '', _('search the repository as it stood at rev')),
3161 [('r', 'rev', '', _('search the repository as it stood at rev')),
3160 ('0', 'print0', None,
3162 ('0', 'print0', None,
3161 _('end filenames with NUL, for use with xargs')),
3163 _('end filenames with NUL, for use with xargs')),
3162 ('f', 'fullpath', None,
3164 ('f', 'fullpath', None,
3163 _('print complete paths from the filesystem root')),
3165 _('print complete paths from the filesystem root')),
3164 ] + walkopts,
3166 ] + walkopts,
3165 _('hg locate [OPTION]... [PATTERN]...')),
3167 _('hg locate [OPTION]... [PATTERN]...')),
3166 "^log|history":
3168 "^log|history":
3167 (log,
3169 (log,
3168 [('f', 'follow', None,
3170 [('f', 'follow', None,
3169 _('follow changeset history, or file history across copies and renames')),
3171 _('follow changeset history, or file history across copies and renames')),
3170 ('', 'follow-first', None,
3172 ('', 'follow-first', None,
3171 _('only follow the first parent of merge changesets')),
3173 _('only follow the first parent of merge changesets')),
3172 ('d', 'date', '', _('show revs matching date spec')),
3174 ('d', 'date', '', _('show revs matching date spec')),
3173 ('C', 'copies', None, _('show copied files')),
3175 ('C', 'copies', None, _('show copied files')),
3174 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3176 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3175 ('r', 'rev', [], _('show the specified revision or range')),
3177 ('r', 'rev', [], _('show the specified revision or range')),
3176 ('', 'removed', None, _('include revs where files were removed')),
3178 ('', 'removed', None, _('include revs where files were removed')),
3177 ('m', 'only-merges', None, _('show only merges')),
3179 ('m', 'only-merges', None, _('show only merges')),
3178 ('b', 'only-branch', [],
3180 ('b', 'only-branch', [],
3179 _('show only changesets within the given named branch')),
3181 _('show only changesets within the given named branch')),
3180 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3182 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3181 ] + logopts + walkopts,
3183 ] + logopts + walkopts,
3182 _('hg log [OPTION]... [FILE]')),
3184 _('hg log [OPTION]... [FILE]')),
3183 "manifest":
3185 "manifest":
3184 (manifest,
3186 (manifest,
3185 [('r', 'rev', '', _('revision to display'))],
3187 [('r', 'rev', '', _('revision to display'))],
3186 _('hg manifest [-r REV]')),
3188 _('hg manifest [-r REV]')),
3187 "^merge":
3189 "^merge":
3188 (merge,
3190 (merge,
3189 [('f', 'force', None, _('force a merge with outstanding changes')),
3191 [('f', 'force', None, _('force a merge with outstanding changes')),
3190 ('r', 'rev', '', _('revision to merge')),
3192 ('r', 'rev', '', _('revision to merge')),
3191 ],
3193 ],
3192 _('hg merge [-f] [[-r] REV]')),
3194 _('hg merge [-f] [[-r] REV]')),
3193 "outgoing|out":
3195 "outgoing|out":
3194 (outgoing,
3196 (outgoing,
3195 [('f', 'force', None,
3197 [('f', 'force', None,
3196 _('run even when remote repository is unrelated')),
3198 _('run even when remote repository is unrelated')),
3197 ('r', 'rev', [],
3199 ('r', 'rev', [],
3198 _('a specific revision up to which you would like to push')),
3200 _('a specific revision up to which you would like to push')),
3199 ('n', 'newest-first', None, _('show newest record first')),
3201 ('n', 'newest-first', None, _('show newest record first')),
3200 ] + logopts + remoteopts,
3202 ] + logopts + remoteopts,
3201 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3203 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3202 "^parents":
3204 "^parents":
3203 (parents,
3205 (parents,
3204 [('r', 'rev', '', _('show parents from the specified rev')),
3206 [('r', 'rev', '', _('show parents from the specified rev')),
3205 ] + templateopts,
3207 ] + templateopts,
3206 _('hg parents [-r REV] [FILE]')),
3208 _('hg parents [-r REV] [FILE]')),
3207 "paths": (paths, [], _('hg paths [NAME]')),
3209 "paths": (paths, [], _('hg paths [NAME]')),
3208 "^pull":
3210 "^pull":
3209 (pull,
3211 (pull,
3210 [('u', 'update', None,
3212 [('u', 'update', None,
3211 _('update to new tip if changesets were pulled')),
3213 _('update to new tip if changesets were pulled')),
3212 ('f', 'force', None,
3214 ('f', 'force', None,
3213 _('run even when remote repository is unrelated')),
3215 _('run even when remote repository is unrelated')),
3214 ('r', 'rev', [],
3216 ('r', 'rev', [],
3215 _('a specific revision up to which you would like to pull')),
3217 _('a specific revision up to which you would like to pull')),
3216 ] + remoteopts,
3218 ] + remoteopts,
3217 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3219 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3218 "^push":
3220 "^push":
3219 (push,
3221 (push,
3220 [('f', 'force', None, _('force push')),
3222 [('f', 'force', None, _('force push')),
3221 ('r', 'rev', [],
3223 ('r', 'rev', [],
3222 _('a specific revision up to which you would like to push')),
3224 _('a specific revision up to which you would like to push')),
3223 ] + remoteopts,
3225 ] + remoteopts,
3224 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3226 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3225 "recover": (recover, [], _('hg recover')),
3227 "recover": (recover, [], _('hg recover')),
3226 "^remove|rm":
3228 "^remove|rm":
3227 (remove,
3229 (remove,
3228 [('A', 'after', None, _('record delete for missing files')),
3230 [('A', 'after', None, _('record delete for missing files')),
3229 ('f', 'force', None,
3231 ('f', 'force', None,
3230 _('remove (and delete) file even if added or modified')),
3232 _('remove (and delete) file even if added or modified')),
3231 ] + walkopts,
3233 ] + walkopts,
3232 _('hg remove [OPTION]... FILE...')),
3234 _('hg remove [OPTION]... FILE...')),
3233 "rename|mv":
3235 "rename|mv":
3234 (rename,
3236 (rename,
3235 [('A', 'after', None, _('record a rename that has already occurred')),
3237 [('A', 'after', None, _('record a rename that has already occurred')),
3236 ('f', 'force', None,
3238 ('f', 'force', None,
3237 _('forcibly copy over an existing managed file')),
3239 _('forcibly copy over an existing managed file')),
3238 ] + walkopts + dryrunopts,
3240 ] + walkopts + dryrunopts,
3239 _('hg rename [OPTION]... SOURCE... DEST')),
3241 _('hg rename [OPTION]... SOURCE... DEST')),
3240 "resolve":
3242 "resolve":
3241 (resolve,
3243 (resolve,
3242 [('l', 'list', None, _('list state of files needing merge')),
3244 [('l', 'list', None, _('list state of files needing merge')),
3243 ('m', 'mark', None, _('mark files as resolved')),
3245 ('m', 'mark', None, _('mark files as resolved')),
3244 ('u', 'unmark', None, _('unmark files as resolved'))],
3246 ('u', 'unmark', None, _('unmark files as resolved'))],
3245 ('hg resolve [OPTION] [FILES...]')),
3247 ('hg resolve [OPTION] [FILES...]')),
3246 "revert":
3248 "revert":
3247 (revert,
3249 (revert,
3248 [('a', 'all', None, _('revert all changes when no arguments given')),
3250 [('a', 'all', None, _('revert all changes when no arguments given')),
3249 ('d', 'date', '', _('tipmost revision matching date')),
3251 ('d', 'date', '', _('tipmost revision matching date')),
3250 ('r', 'rev', '', _('revision to revert to')),
3252 ('r', 'rev', '', _('revision to revert to')),
3251 ('', 'no-backup', None, _('do not save backup copies of files')),
3253 ('', 'no-backup', None, _('do not save backup copies of files')),
3252 ] + walkopts + dryrunopts,
3254 ] + walkopts + dryrunopts,
3253 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3255 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3254 "rollback": (rollback, [], _('hg rollback')),
3256 "rollback": (rollback, [], _('hg rollback')),
3255 "root": (root, [], _('hg root')),
3257 "root": (root, [], _('hg root')),
3256 "^serve":
3258 "^serve":
3257 (serve,
3259 (serve,
3258 [('A', 'accesslog', '', _('name of access log file to write to')),
3260 [('A', 'accesslog', '', _('name of access log file to write to')),
3259 ('d', 'daemon', None, _('run server in background')),
3261 ('d', 'daemon', None, _('run server in background')),
3260 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3262 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3261 ('E', 'errorlog', '', _('name of error log file to write to')),
3263 ('E', 'errorlog', '', _('name of error log file to write to')),
3262 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3264 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3263 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3265 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3264 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3266 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3265 ('n', 'name', '',
3267 ('n', 'name', '',
3266 _('name to show in web pages (default: working dir)')),
3268 _('name to show in web pages (default: working dir)')),
3267 ('', 'webdir-conf', '', _('name of the webdir config file'
3269 ('', 'webdir-conf', '', _('name of the webdir config file'
3268 ' (serve more than one repo)')),
3270 ' (serve more than one repo)')),
3269 ('', 'pid-file', '', _('name of file to write process ID to')),
3271 ('', 'pid-file', '', _('name of file to write process ID to')),
3270 ('', 'stdio', None, _('for remote clients')),
3272 ('', 'stdio', None, _('for remote clients')),
3271 ('t', 'templates', '', _('web templates to use')),
3273 ('t', 'templates', '', _('web templates to use')),
3272 ('', 'style', '', _('template style to use')),
3274 ('', 'style', '', _('template style to use')),
3273 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3275 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3274 ('', 'certificate', '', _('SSL certificate file'))],
3276 ('', 'certificate', '', _('SSL certificate file'))],
3275 _('hg serve [OPTION]...')),
3277 _('hg serve [OPTION]...')),
3276 "showconfig|debugconfig":
3278 "showconfig|debugconfig":
3277 (showconfig,
3279 (showconfig,
3278 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3280 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3279 _('hg showconfig [-u] [NAME]...')),
3281 _('hg showconfig [-u] [NAME]...')),
3280 "^status|st":
3282 "^status|st":
3281 (status,
3283 (status,
3282 [('A', 'all', None, _('show status of all files')),
3284 [('A', 'all', None, _('show status of all files')),
3283 ('m', 'modified', None, _('show only modified files')),
3285 ('m', 'modified', None, _('show only modified files')),
3284 ('a', 'added', None, _('show only added files')),
3286 ('a', 'added', None, _('show only added files')),
3285 ('r', 'removed', None, _('show only removed files')),
3287 ('r', 'removed', None, _('show only removed files')),
3286 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3288 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3287 ('c', 'clean', None, _('show only files without changes')),
3289 ('c', 'clean', None, _('show only files without changes')),
3288 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3290 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3289 ('i', 'ignored', None, _('show only ignored files')),
3291 ('i', 'ignored', None, _('show only ignored files')),
3290 ('n', 'no-status', None, _('hide status prefix')),
3292 ('n', 'no-status', None, _('hide status prefix')),
3291 ('C', 'copies', None, _('show source of copied files')),
3293 ('C', 'copies', None, _('show source of copied files')),
3292 ('0', 'print0', None,
3294 ('0', 'print0', None,
3293 _('end filenames with NUL, for use with xargs')),
3295 _('end filenames with NUL, for use with xargs')),
3294 ('', 'rev', [], _('show difference from revision')),
3296 ('', 'rev', [], _('show difference from revision')),
3295 ] + walkopts,
3297 ] + walkopts,
3296 _('hg status [OPTION]... [FILE]...')),
3298 _('hg status [OPTION]... [FILE]...')),
3297 "tag":
3299 "tag":
3298 (tag,
3300 (tag,
3299 [('f', 'force', None, _('replace existing tag')),
3301 [('f', 'force', None, _('replace existing tag')),
3300 ('l', 'local', None, _('make the tag local')),
3302 ('l', 'local', None, _('make the tag local')),
3301 ('r', 'rev', '', _('revision to tag')),
3303 ('r', 'rev', '', _('revision to tag')),
3302 ('', 'remove', None, _('remove a tag')),
3304 ('', 'remove', None, _('remove a tag')),
3303 # -l/--local is already there, commitopts cannot be used
3305 # -l/--local is already there, commitopts cannot be used
3304 ('m', 'message', '', _('use <text> as commit message')),
3306 ('m', 'message', '', _('use <text> as commit message')),
3305 ] + commitopts2,
3307 ] + commitopts2,
3306 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3308 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3307 "tags": (tags, [], _('hg tags')),
3309 "tags": (tags, [], _('hg tags')),
3308 "tip":
3310 "tip":
3309 (tip,
3311 (tip,
3310 [('p', 'patch', None, _('show patch')),
3312 [('p', 'patch', None, _('show patch')),
3311 ] + templateopts,
3313 ] + templateopts,
3312 _('hg tip [-p]')),
3314 _('hg tip [-p]')),
3313 "unbundle":
3315 "unbundle":
3314 (unbundle,
3316 (unbundle,
3315 [('u', 'update', None,
3317 [('u', 'update', None,
3316 _('update to new tip if changesets were unbundled'))],
3318 _('update to new tip if changesets were unbundled'))],
3317 _('hg unbundle [-u] FILE...')),
3319 _('hg unbundle [-u] FILE...')),
3318 "^update|up|checkout|co":
3320 "^update|up|checkout|co":
3319 (update,
3321 (update,
3320 [('C', 'clean', None, _('overwrite locally modified files')),
3322 [('C', 'clean', None, _('overwrite locally modified files')),
3321 ('d', 'date', '', _('tipmost revision matching date')),
3323 ('d', 'date', '', _('tipmost revision matching date')),
3322 ('r', 'rev', '', _('revision'))],
3324 ('r', 'rev', '', _('revision'))],
3323 _('hg update [-C] [-d DATE] [[-r] REV]')),
3325 _('hg update [-C] [-d DATE] [[-r] REV]')),
3324 "verify": (verify, [], _('hg verify')),
3326 "verify": (verify, [], _('hg verify')),
3325 "version": (version_, [], _('hg version')),
3327 "version": (version_, [], _('hg version')),
3326 }
3328 }
3327
3329
3328 norepo = ("clone init version help debugcomplete debugdata"
3330 norepo = ("clone init version help debugcomplete debugdata"
3329 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3331 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3330 optionalrepo = ("identify paths serve showconfig debugancestor")
3332 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,314 +1,314 b''
1 Mercurial Distributed SCM
1 Mercurial Distributed SCM
2
2
3 basic commands:
3 basic commands:
4
4
5 add add the specified files on the next commit
5 add add the specified files on the next commit
6 annotate show changeset information per file line
6 annotate show changeset information per file line
7 clone make a copy of an existing repository
7 clone make a copy of an existing repository
8 commit commit the specified files or all outstanding changes
8 commit commit the specified files or all outstanding changes
9 diff diff repository (or selected files)
9 diff diff repository (or selected files)
10 export dump the header and diffs for one or more changesets
10 export dump the header and diffs for one or more changesets
11 init create a new repository in the given directory
11 init create a new repository in the given directory
12 log show revision history of entire repository or files
12 log show revision history of entire repository or files
13 merge merge working directory with another revision
13 merge merge working directory with another revision
14 parents show the parents of the working dir or revision
14 parents show the parents of the working dir or revision
15 pull pull changes from the specified source
15 pull pull changes from the specified source
16 push push changes to the specified destination
16 push push changes to the specified destination
17 remove remove the specified files on the next commit
17 remove remove the specified files on the next commit
18 serve export the repository via HTTP
18 serve export the repository via HTTP
19 status show changed files in the working directory
19 status show changed files in the working directory
20 update update working directory
20 update update working directory
21
21
22 use "hg help" for the full list of commands or "hg -v" for details
22 use "hg help" for the full list of commands or "hg -v" for details
23 add add the specified files on the next commit
23 add add the specified files on the next commit
24 annotate show changeset information per file line
24 annotate show changeset information per file line
25 clone make a copy of an existing repository
25 clone make a copy of an existing repository
26 commit commit the specified files or all outstanding changes
26 commit commit the specified files or all outstanding changes
27 diff diff repository (or selected files)
27 diff diff repository (or selected files)
28 export dump the header and diffs for one or more changesets
28 export dump the header and diffs for one or more changesets
29 init create a new repository in the given directory
29 init create a new repository in the given directory
30 log show revision history of entire repository or files
30 log show revision history of entire repository or files
31 merge merge working directory with another revision
31 merge merge working directory with another revision
32 parents show the parents of the working dir or revision
32 parents show the parents of the working dir or revision
33 pull pull changes from the specified source
33 pull pull changes from the specified source
34 push push changes to the specified destination
34 push push changes to the specified destination
35 remove remove the specified files on the next commit
35 remove remove the specified files on the next commit
36 serve export the repository via HTTP
36 serve export the repository via HTTP
37 status show changed files in the working directory
37 status show changed files in the working directory
38 update update working directory
38 update update working directory
39 Mercurial Distributed SCM
39 Mercurial Distributed SCM
40
40
41 list of commands:
41 list of commands:
42
42
43 add add the specified files on the next commit
43 add add the specified files on the next commit
44 addremove add all new files, delete all missing files
44 addremove add all new files, delete all missing files
45 annotate show changeset information per file line
45 annotate show changeset information per file line
46 archive create unversioned archive of a repository revision
46 archive create unversioned archive of a repository revision
47 backout reverse effect of earlier changeset
47 backout reverse effect of earlier changeset
48 bisect subdivision search of changesets
48 bisect subdivision search of changesets
49 branch set or show the current branch name
49 branch set or show the current branch name
50 branches list repository named branches
50 branches list repository named branches
51 bundle create a changegroup file
51 bundle create a changegroup file
52 cat output the current or given revision of files
52 cat output the current or given revision of files
53 clone make a copy of an existing repository
53 clone make a copy of an existing repository
54 commit commit the specified files or all outstanding changes
54 commit commit the specified files or all outstanding changes
55 copy mark files as copied for the next commit
55 copy mark files as copied for the next commit
56 diff diff repository (or selected files)
56 diff diff repository (or selected files)
57 export dump the header and diffs for one or more changesets
57 export dump the header and diffs for one or more changesets
58 grep search for a pattern in specified files and revisions
58 grep search for a pattern in specified files and revisions
59 heads show current repository heads or show branch heads
59 heads show current repository heads or show branch heads
60 help show help for a command, extension, or list of commands
60 help show help for a command, extension, or list of commands
61 identify identify the working copy or specified revision
61 identify identify the working copy or specified revision
62 import import an ordered set of patches
62 import import an ordered set of patches
63 incoming show new changesets found in source
63 incoming show new changesets found in source
64 init create a new repository in the given directory
64 init create a new repository in the given directory
65 locate locate files matching specific patterns
65 locate locate files matching specific patterns
66 log show revision history of entire repository or files
66 log show revision history of entire repository or files
67 manifest output the current or given revision of the project manifest
67 manifest output the current or given revision of the project manifest
68 merge merge working directory with another revision
68 merge merge working directory with another revision
69 outgoing show changesets not found in destination
69 outgoing show changesets not found in destination
70 parents show the parents of the working dir or revision
70 parents show the parents of the working dir or revision
71 paths show definition of symbolic path names
71 paths show definition of symbolic path names
72 pull pull changes from the specified source
72 pull pull changes from the specified source
73 push push changes to the specified destination
73 push push changes to the specified destination
74 recover roll back an interrupted transaction
74 recover roll back an interrupted transaction
75 remove remove the specified files on the next commit
75 remove remove the specified files on the next commit
76 rename rename files; equivalent of copy + remove
76 rename rename files; equivalent of copy + remove
77 resolve resolve file merges from a branch merge or update
77 resolve resolve file merges from a branch merge or update
78 revert restore individual files or dirs to an earlier state
78 revert restore individual files or dirs to an earlier state
79 rollback roll back the last transaction
79 rollback roll back the last transaction
80 root print the root (top) of the current working dir
80 root print the root (top) of the current working dir
81 serve export the repository via HTTP
81 serve export the repository via HTTP
82 showconfig show combined config settings from all hgrc files
82 showconfig show combined config settings from all hgrc files
83 status show changed files in the working directory
83 status show changed files in the working directory
84 tag add one or more tags for the current or given revision
84 tag add one or more tags for the current or given revision
85 tags list repository tags
85 tags list repository tags
86 tip show the tip revision
86 tip show the tip revision
87 unbundle apply one or more changegroup files
87 unbundle apply one or more changegroup files
88 update update working directory
88 update update working directory
89 verify verify the integrity of the repository
89 verify verify the integrity of the repository
90 version output version and copyright information
90 version output version and copyright information
91
91
92 use "hg -v help" to show aliases and global options
92 use "hg -v help" to show aliases and global options
93 add add the specified files on the next commit
93 add add the specified files on the next commit
94 addremove add all new files, delete all missing files
94 addremove add all new files, delete all missing files
95 annotate show changeset information per file line
95 annotate show changeset information per file line
96 archive create unversioned archive of a repository revision
96 archive create unversioned archive of a repository revision
97 backout reverse effect of earlier changeset
97 backout reverse effect of earlier changeset
98 bisect subdivision search of changesets
98 bisect subdivision search of changesets
99 branch set or show the current branch name
99 branch set or show the current branch name
100 branches list repository named branches
100 branches list repository named branches
101 bundle create a changegroup file
101 bundle create a changegroup file
102 cat output the current or given revision of files
102 cat output the current or given revision of files
103 clone make a copy of an existing repository
103 clone make a copy of an existing repository
104 commit commit the specified files or all outstanding changes
104 commit commit the specified files or all outstanding changes
105 copy mark files as copied for the next commit
105 copy mark files as copied for the next commit
106 diff diff repository (or selected files)
106 diff diff repository (or selected files)
107 export dump the header and diffs for one or more changesets
107 export dump the header and diffs for one or more changesets
108 grep search for a pattern in specified files and revisions
108 grep search for a pattern in specified files and revisions
109 heads show current repository heads or show branch heads
109 heads show current repository heads or show branch heads
110 help show help for a command, extension, or list of commands
110 help show help for a command, extension, or list of commands
111 identify identify the working copy or specified revision
111 identify identify the working copy or specified revision
112 import import an ordered set of patches
112 import import an ordered set of patches
113 incoming show new changesets found in source
113 incoming show new changesets found in source
114 init create a new repository in the given directory
114 init create a new repository in the given directory
115 locate locate files matching specific patterns
115 locate locate files matching specific patterns
116 log show revision history of entire repository or files
116 log show revision history of entire repository or files
117 manifest output the current or given revision of the project manifest
117 manifest output the current or given revision of the project manifest
118 merge merge working directory with another revision
118 merge merge working directory with another revision
119 outgoing show changesets not found in destination
119 outgoing show changesets not found in destination
120 parents show the parents of the working dir or revision
120 parents show the parents of the working dir or revision
121 paths show definition of symbolic path names
121 paths show definition of symbolic path names
122 pull pull changes from the specified source
122 pull pull changes from the specified source
123 push push changes to the specified destination
123 push push changes to the specified destination
124 recover roll back an interrupted transaction
124 recover roll back an interrupted transaction
125 remove remove the specified files on the next commit
125 remove remove the specified files on the next commit
126 rename rename files; equivalent of copy + remove
126 rename rename files; equivalent of copy + remove
127 resolve resolve file merges from a branch merge or update
127 resolve resolve file merges from a branch merge or update
128 revert restore individual files or dirs to an earlier state
128 revert restore individual files or dirs to an earlier state
129 rollback roll back the last transaction
129 rollback roll back the last transaction
130 root print the root (top) of the current working dir
130 root print the root (top) of the current working dir
131 serve export the repository via HTTP
131 serve export the repository via HTTP
132 showconfig show combined config settings from all hgrc files
132 showconfig show combined config settings from all hgrc files
133 status show changed files in the working directory
133 status show changed files in the working directory
134 tag add one or more tags for the current or given revision
134 tag add one or more tags for the current or given revision
135 tags list repository tags
135 tags list repository tags
136 tip show the tip revision
136 tip show the tip revision
137 unbundle apply one or more changegroup files
137 unbundle apply one or more changegroup files
138 update update working directory
138 update update working directory
139 verify verify the integrity of the repository
139 verify verify the integrity of the repository
140 version output version and copyright information
140 version output version and copyright information
141 hg add [OPTION]... [FILE]...
141 hg add [OPTION]... [FILE]...
142
142
143 add the specified files on the next commit
143 add the specified files on the next commit
144
144
145 Schedule files to be version controlled and added to the repository.
145 Schedule files to be version controlled and added to the repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see hg revert.
148 undo an add before that, see hg revert.
149
149
150 If no names are given, add all files in the repository.
150 If no names are given, add all files in the repository.
151
151
152 options:
152 options:
153
153
154 -I --include include names matching the given patterns
154 -I --include include names matching the given patterns
155 -X --exclude exclude names matching the given patterns
155 -X --exclude exclude names matching the given patterns
156 -n --dry-run do not perform actions, just print output
156 -n --dry-run do not perform actions, just print output
157
157
158 use "hg -v help add" to show global options
158 use "hg -v help add" to show global options
159 hg add: option --skjdfks not recognized
159 hg add: option --skjdfks not recognized
160 hg add [OPTION]... [FILE]...
160 hg add [OPTION]... [FILE]...
161
161
162 add the specified files on the next commit
162 add the specified files on the next commit
163
163
164 Schedule files to be version controlled and added to the repository.
164 Schedule files to be version controlled and added to the repository.
165
165
166 The files will be added to the repository at the next commit. To
166 The files will be added to the repository at the next commit. To
167 undo an add before that, see hg revert.
167 undo an add before that, see hg revert.
168
168
169 If no names are given, add all files in the repository.
169 If no names are given, add all files in the repository.
170
170
171 options:
171 options:
172
172
173 -I --include include names matching the given patterns
173 -I --include include names matching the given patterns
174 -X --exclude exclude names matching the given patterns
174 -X --exclude exclude names matching the given patterns
175 -n --dry-run do not perform actions, just print output
175 -n --dry-run do not perform actions, just print output
176
176
177 use "hg -v help add" to show global options
177 use "hg -v help add" to show global options
178 hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...
178 hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...
179
179
180 diff repository (or selected files)
180 diff repository (or selected files)
181
181
182 Show differences between revisions for the specified files.
182 Show differences between revisions for the specified files.
183
183
184 Differences between files are shown using the unified diff format.
184 Differences between files are shown using the unified diff format.
185
185
186 NOTE: diff may generate unexpected results for merges, as it will
186 NOTE: diff may generate unexpected results for merges, as it will
187 default to comparing against the working directory's first parent
187 default to comparing against the working directory's first parent
188 changeset if no revisions are specified.
188 changeset if no revisions are specified.
189
189
190 When two revision arguments are given, then changes are shown
190 When two revision arguments are given, then changes are shown
191 between those revisions. If only one revision is specified then
191 between those revisions. If only one revision is specified then
192 that revision is compared to the working directory, and, when no
192 that revision is compared to the working directory, and, when no
193 revisions are specified, the working directory files are compared
193 revisions are specified, the working directory files are compared
194 to its parent.
194 to its parent.
195
195
196 Without the -a option, diff will avoid generating diffs of files
196 Without the -a option, diff will avoid generating diffs of files
197 it detects as binary. With -a, diff will generate a diff anyway,
197 it detects as binary. With -a, diff will generate a diff anyway,
198 probably with undesirable results.
198 probably with undesirable results.
199
199
200 options:
200 options:
201
201
202 -r --rev revision
202 -r --rev revision
203 -a --text treat all files as text
203 -a --text treat all files as text
204 -p --show-function show which function each change is in
205 -g --git use git extended diff format
204 -g --git use git extended diff format
206 --nodates don't include dates in diff headers
205 --nodates don't include dates in diff headers
206 -p --show-function show which function each change is in
207 -w --ignore-all-space ignore white space when comparing lines
207 -w --ignore-all-space ignore white space when comparing lines
208 -b --ignore-space-change ignore changes in the amount of white space
208 -b --ignore-space-change ignore changes in the amount of white space
209 -B --ignore-blank-lines ignore changes whose lines are all blank
209 -B --ignore-blank-lines ignore changes whose lines are all blank
210 -U --unified number of lines of context to show
210 -U --unified number of lines of context to show
211 -I --include include names matching the given patterns
211 -I --include include names matching the given patterns
212 -X --exclude exclude names matching the given patterns
212 -X --exclude exclude names matching the given patterns
213
213
214 use "hg -v help diff" to show global options
214 use "hg -v help diff" to show global options
215 hg status [OPTION]... [FILE]...
215 hg status [OPTION]... [FILE]...
216
216
217 aliases: st
217 aliases: st
218
218
219 show changed files in the working directory
219 show changed files in the working directory
220
220
221 Show status of files in the repository. If names are given, only
221 Show status of files in the repository. If names are given, only
222 files that match are shown. Files that are clean or ignored or
222 files that match are shown. Files that are clean or ignored or
223 source of a copy/move operation, are not listed unless -c (clean),
223 source of a copy/move operation, are not listed unless -c (clean),
224 -i (ignored), -C (copies) or -A is given. Unless options described
224 -i (ignored), -C (copies) or -A is given. Unless options described
225 with "show only ..." are given, the options -mardu are used.
225 with "show only ..." are given, the options -mardu are used.
226
226
227 Option -q/--quiet hides untracked (unknown and ignored) files
227 Option -q/--quiet hides untracked (unknown and ignored) files
228 unless explicitly requested with -u/--unknown or -i/-ignored.
228 unless explicitly requested with -u/--unknown or -i/-ignored.
229
229
230 NOTE: status may appear to disagree with diff if permissions have
230 NOTE: status may appear to disagree with diff if permissions have
231 changed or a merge has occurred. The standard diff format does not
231 changed or a merge has occurred. The standard diff format does not
232 report permission changes and diff only reports changes relative
232 report permission changes and diff only reports changes relative
233 to one merge parent.
233 to one merge parent.
234
234
235 If one revision is given, it is used as the base revision.
235 If one revision is given, it is used as the base revision.
236 If two revisions are given, the difference between them is shown.
236 If two revisions are given, the difference between them is shown.
237
237
238 The codes used to show the status of files are:
238 The codes used to show the status of files are:
239 M = modified
239 M = modified
240 A = added
240 A = added
241 R = removed
241 R = removed
242 C = clean
242 C = clean
243 ! = deleted, but still tracked
243 ! = deleted, but still tracked
244 ? = not tracked
244 ? = not tracked
245 I = ignored
245 I = ignored
246 = the previous added file was copied from here
246 = the previous added file was copied from here
247
247
248 options:
248 options:
249
249
250 -A --all show status of all files
250 -A --all show status of all files
251 -m --modified show only modified files
251 -m --modified show only modified files
252 -a --added show only added files
252 -a --added show only added files
253 -r --removed show only removed files
253 -r --removed show only removed files
254 -d --deleted show only deleted (but tracked) files
254 -d --deleted show only deleted (but tracked) files
255 -c --clean show only files without changes
255 -c --clean show only files without changes
256 -u --unknown show only unknown (not tracked) files
256 -u --unknown show only unknown (not tracked) files
257 -i --ignored show only ignored files
257 -i --ignored show only ignored files
258 -n --no-status hide status prefix
258 -n --no-status hide status prefix
259 -C --copies show source of copied files
259 -C --copies show source of copied files
260 -0 --print0 end filenames with NUL, for use with xargs
260 -0 --print0 end filenames with NUL, for use with xargs
261 --rev show difference from revision
261 --rev show difference from revision
262 -I --include include names matching the given patterns
262 -I --include include names matching the given patterns
263 -X --exclude exclude names matching the given patterns
263 -X --exclude exclude names matching the given patterns
264
264
265 use "hg -v help status" to show global options
265 use "hg -v help status" to show global options
266 hg status [OPTION]... [FILE]...
266 hg status [OPTION]... [FILE]...
267
267
268 show changed files in the working directory
268 show changed files in the working directory
269 hg: unknown command 'foo'
269 hg: unknown command 'foo'
270 Mercurial Distributed SCM
270 Mercurial Distributed SCM
271
271
272 basic commands:
272 basic commands:
273
273
274 add add the specified files on the next commit
274 add add the specified files on the next commit
275 annotate show changeset information per file line
275 annotate show changeset information per file line
276 clone make a copy of an existing repository
276 clone make a copy of an existing repository
277 commit commit the specified files or all outstanding changes
277 commit commit the specified files or all outstanding changes
278 diff diff repository (or selected files)
278 diff diff repository (or selected files)
279 export dump the header and diffs for one or more changesets
279 export dump the header and diffs for one or more changesets
280 init create a new repository in the given directory
280 init create a new repository in the given directory
281 log show revision history of entire repository or files
281 log show revision history of entire repository or files
282 merge merge working directory with another revision
282 merge merge working directory with another revision
283 parents show the parents of the working dir or revision
283 parents show the parents of the working dir or revision
284 pull pull changes from the specified source
284 pull pull changes from the specified source
285 push push changes to the specified destination
285 push push changes to the specified destination
286 remove remove the specified files on the next commit
286 remove remove the specified files on the next commit
287 serve export the repository via HTTP
287 serve export the repository via HTTP
288 status show changed files in the working directory
288 status show changed files in the working directory
289 update update working directory
289 update update working directory
290
290
291 use "hg help" for the full list of commands or "hg -v" for details
291 use "hg help" for the full list of commands or "hg -v" for details
292 hg: unknown command 'skjdfks'
292 hg: unknown command 'skjdfks'
293 Mercurial Distributed SCM
293 Mercurial Distributed SCM
294
294
295 basic commands:
295 basic commands:
296
296
297 add add the specified files on the next commit
297 add add the specified files on the next commit
298 annotate show changeset information per file line
298 annotate show changeset information per file line
299 clone make a copy of an existing repository
299 clone make a copy of an existing repository
300 commit commit the specified files or all outstanding changes
300 commit commit the specified files or all outstanding changes
301 diff diff repository (or selected files)
301 diff diff repository (or selected files)
302 export dump the header and diffs for one or more changesets
302 export dump the header and diffs for one or more changesets
303 init create a new repository in the given directory
303 init create a new repository in the given directory
304 log show revision history of entire repository or files
304 log show revision history of entire repository or files
305 merge merge working directory with another revision
305 merge merge working directory with another revision
306 parents show the parents of the working dir or revision
306 parents show the parents of the working dir or revision
307 pull pull changes from the specified source
307 pull pull changes from the specified source
308 push push changes to the specified destination
308 push push changes to the specified destination
309 remove remove the specified files on the next commit
309 remove remove the specified files on the next commit
310 serve export the repository via HTTP
310 serve export the repository via HTTP
311 status show changed files in the working directory
311 status show changed files in the working directory
312 update update working directory
312 update update working directory
313
313
314 use "hg help" for the full list of commands or "hg -v" for details
314 use "hg help" for the full list of commands or "hg -v" for details
@@ -1,27 +1,59 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "[extensions]" >> $HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
5
5
6 echo % init
6 echo % init
7 hg init a
7 hg init a
8 cd a
8 cd a
9
9
10 echo % commit
10 echo % commit
11 echo 'base' > base
11 echo 'base' > base
12 hg ci -Ambase -d '1 0'
12 hg ci -Ambase -d '1 0'
13
13
14 echo % qnew mqbase
14 echo % qnew mqbase
15 hg qnew -mmqbase mqbase
15 hg qnew -mmqbase mqbase
16
16
17 echo % qrefresh
17 echo % qrefresh
18 echo 'patched' > base
18 echo 'patched' > base
19 hg qrefresh
19 hg qrefresh
20
20
21 echo % qdiff
21 echo % qdiff
22 hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
22 hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
23 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
23 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
24
24
25 echo % qdiff dirname
25 echo % qdiff dirname
26 hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
26 hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
27 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
27 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
28
29 echo % qdiff filename
30 hg qdiff --nodates base
31
32 echo % revert
33 hg revert -a
34
35 echo % qpop
36 hg qpop
37
38 echo % qdelete mqbase
39 hg qdelete mqbase
40
41 echo % commit 2
42 printf '1\n2\n3\n4\nhello world\ngoodbye world\n7\n8\n9\n' > lines
43 hg ci -Amlines -d '2 0'
44
45 echo % qnew 2
46 hg qnew -mmqbase2 mqbase2
47 printf '\n\n1\n2\n3\n4\nhello world\n goodbye world\n7\n8\n9\n' > lines
48
49 echo % qdiff -U 1
50 hg qdiff --nodates -U 1
51
52 echo % qdiff -b
53 hg qdiff --nodates -b
54
55 echo % qdiff -U 1 -B
56 hg qdiff --nodates -U 1 -B
57
58 echo qdiff -w
59 hg qdiff --nodates -w
@@ -1,19 +1,87 b''
1 % init
1 % init
2 % commit
2 % commit
3 adding base
3 adding base
4 % qnew mqbase
4 % qnew mqbase
5 % qrefresh
5 % qrefresh
6 % qdiff
6 % qdiff
7 diff -r 67e992f2c4f3 base
7 diff -r 67e992f2c4f3 base
8 --- a/base
8 --- a/base
9 +++ b/base
9 +++ b/base
10 @@ -1,1 +1,1 @@
10 @@ -1,1 +1,1 @@
11 -base
11 -base
12 +patched
12 +patched
13 % qdiff dirname
13 % qdiff dirname
14 diff -r 67e992f2c4f3 base
14 diff -r 67e992f2c4f3 base
15 --- a/base
15 --- a/base
16 +++ b/base
16 +++ b/base
17 @@ -1,1 +1,1 @@
17 @@ -1,1 +1,1 @@
18 -base
18 -base
19 +patched
19 +patched
20 % qdiff filename
21 diff -r 67e992f2c4f3 base
22 --- a/base
23 +++ b/base
24 @@ -1,1 +1,1 @@
25 -base
26 +patched
27 % revert
28 % qpop
29 Patch queue now empty
30 % qdelete mqbase
31 % commit 2
32 adding lines
33 % qnew 2
34 % qdiff -U 1
35 diff -r 35fb829491c1 lines
36 --- a/lines
37 +++ b/lines
38 @@ -1,1 +1,3 @@
39 +
40 +
41 1
42 @@ -4,4 +6,4 @@
43 4
44 -hello world
45 -goodbye world
46 +hello world
47 + goodbye world
48 7
49 % qdiff -b
50 diff -r 35fb829491c1 lines
51 --- a/lines
52 +++ b/lines
53 @@ -1,9 +1,11 @@
54 +
55 +
56 1
57 2
58 3
59 4
60 -hello world
61 -goodbye world
62 +hello world
63 + goodbye world
64 7
65 8
66 9
67 % qdiff -U 1 -B
68 diff -r 35fb829491c1 lines
69 --- a/lines
70 +++ b/lines
71 @@ -4,4 +6,4 @@
72 4
73 -hello world
74 -goodbye world
75 +hello world
76 + goodbye world
77 7
78 qdiff -w
79 diff -r 35fb829491c1 lines
80 --- a/lines
81 +++ b/lines
82 @@ -1,3 +1,5 @@
83 +
84 +
85 1
86 2
87 3
General Comments 0
You need to be logged in to leave comments. Login now