##// END OF EJS Templates
bookmarks: rewrite pushing local bookmarks in "commands.push()" by "compare()"...
FUJIWARA Katsunori -
r20026:84905561 default
parent child Browse files
Show More
@@ -1,397 +1,427 b''
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial.node import hex, bin
9 from mercurial.node import hex, bin
10 from mercurial import encoding, error, util, obsolete
10 from mercurial import encoding, error, util, obsolete
11 import errno
11 import errno
12
12
13 class bmstore(dict):
13 class bmstore(dict):
14 """Storage for bookmarks.
14 """Storage for bookmarks.
15
15
16 This object should do all bookmark reads and writes, so that it's
16 This object should do all bookmark reads and writes, so that it's
17 fairly simple to replace the storage underlying bookmarks without
17 fairly simple to replace the storage underlying bookmarks without
18 having to clone the logic surrounding bookmarks.
18 having to clone the logic surrounding bookmarks.
19
19
20 This particular bmstore implementation stores bookmarks as
20 This particular bmstore implementation stores bookmarks as
21 {hash}\s{name}\n (the same format as localtags) in
21 {hash}\s{name}\n (the same format as localtags) in
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23
23
24 This class does NOT handle the "current" bookmark state at this
24 This class does NOT handle the "current" bookmark state at this
25 time.
25 time.
26 """
26 """
27
27
28 def __init__(self, repo):
28 def __init__(self, repo):
29 dict.__init__(self)
29 dict.__init__(self)
30 self._repo = repo
30 self._repo = repo
31 try:
31 try:
32 for line in repo.vfs('bookmarks'):
32 for line in repo.vfs('bookmarks'):
33 line = line.strip()
33 line = line.strip()
34 if not line:
34 if not line:
35 continue
35 continue
36 if ' ' not in line:
36 if ' ' not in line:
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
38 % line)
38 % line)
39 continue
39 continue
40 sha, refspec = line.split(' ', 1)
40 sha, refspec = line.split(' ', 1)
41 refspec = encoding.tolocal(refspec)
41 refspec = encoding.tolocal(refspec)
42 try:
42 try:
43 self[refspec] = repo.changelog.lookup(sha)
43 self[refspec] = repo.changelog.lookup(sha)
44 except LookupError:
44 except LookupError:
45 pass
45 pass
46 except IOError, inst:
46 except IOError, inst:
47 if inst.errno != errno.ENOENT:
47 if inst.errno != errno.ENOENT:
48 raise
48 raise
49
49
50 def write(self):
50 def write(self):
51 '''Write bookmarks
51 '''Write bookmarks
52
52
53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
54 in a format equal to those of localtags.
54 in a format equal to those of localtags.
55
55
56 We also store a backup of the previous state in undo.bookmarks that
56 We also store a backup of the previous state in undo.bookmarks that
57 can be copied back on rollback.
57 can be copied back on rollback.
58 '''
58 '''
59 repo = self._repo
59 repo = self._repo
60 if repo._bookmarkcurrent not in self:
60 if repo._bookmarkcurrent not in self:
61 setcurrent(repo, None)
61 setcurrent(repo, None)
62
62
63 wlock = repo.wlock()
63 wlock = repo.wlock()
64 try:
64 try:
65
65
66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
67 for name, node in self.iteritems():
67 for name, node in self.iteritems():
68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
69 file.close()
69 file.close()
70
70
71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
72 try:
72 try:
73 repo.svfs.utime('00changelog.i', None)
73 repo.svfs.utime('00changelog.i', None)
74 except OSError:
74 except OSError:
75 pass
75 pass
76
76
77 finally:
77 finally:
78 wlock.release()
78 wlock.release()
79
79
80 def readcurrent(repo):
80 def readcurrent(repo):
81 '''Get the current bookmark
81 '''Get the current bookmark
82
82
83 If we use gittish branches we have a current bookmark that
83 If we use gittish branches we have a current bookmark that
84 we are on. This function returns the name of the bookmark. It
84 we are on. This function returns the name of the bookmark. It
85 is stored in .hg/bookmarks.current
85 is stored in .hg/bookmarks.current
86 '''
86 '''
87 mark = None
87 mark = None
88 try:
88 try:
89 file = repo.opener('bookmarks.current')
89 file = repo.opener('bookmarks.current')
90 except IOError, inst:
90 except IOError, inst:
91 if inst.errno != errno.ENOENT:
91 if inst.errno != errno.ENOENT:
92 raise
92 raise
93 return None
93 return None
94 try:
94 try:
95 # No readline() in osutil.posixfile, reading everything is cheap
95 # No readline() in osutil.posixfile, reading everything is cheap
96 mark = encoding.tolocal((file.readlines() or [''])[0])
96 mark = encoding.tolocal((file.readlines() or [''])[0])
97 if mark == '' or mark not in repo._bookmarks:
97 if mark == '' or mark not in repo._bookmarks:
98 mark = None
98 mark = None
99 finally:
99 finally:
100 file.close()
100 file.close()
101 return mark
101 return mark
102
102
103 def setcurrent(repo, mark):
103 def setcurrent(repo, mark):
104 '''Set the name of the bookmark that we are currently on
104 '''Set the name of the bookmark that we are currently on
105
105
106 Set the name of the bookmark that we are on (hg update <bookmark>).
106 Set the name of the bookmark that we are on (hg update <bookmark>).
107 The name is recorded in .hg/bookmarks.current
107 The name is recorded in .hg/bookmarks.current
108 '''
108 '''
109 current = repo._bookmarkcurrent
109 current = repo._bookmarkcurrent
110 if current == mark:
110 if current == mark:
111 return
111 return
112
112
113 if mark not in repo._bookmarks:
113 if mark not in repo._bookmarks:
114 mark = ''
114 mark = ''
115
115
116 wlock = repo.wlock()
116 wlock = repo.wlock()
117 try:
117 try:
118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
119 file.write(encoding.fromlocal(mark))
119 file.write(encoding.fromlocal(mark))
120 file.close()
120 file.close()
121 finally:
121 finally:
122 wlock.release()
122 wlock.release()
123 repo._bookmarkcurrent = mark
123 repo._bookmarkcurrent = mark
124
124
125 def unsetcurrent(repo):
125 def unsetcurrent(repo):
126 wlock = repo.wlock()
126 wlock = repo.wlock()
127 try:
127 try:
128 try:
128 try:
129 repo.vfs.unlink('bookmarks.current')
129 repo.vfs.unlink('bookmarks.current')
130 repo._bookmarkcurrent = None
130 repo._bookmarkcurrent = None
131 except OSError, inst:
131 except OSError, inst:
132 if inst.errno != errno.ENOENT:
132 if inst.errno != errno.ENOENT:
133 raise
133 raise
134 finally:
134 finally:
135 wlock.release()
135 wlock.release()
136
136
137 def iscurrent(repo, mark=None, parents=None):
137 def iscurrent(repo, mark=None, parents=None):
138 '''Tell whether the current bookmark is also active
138 '''Tell whether the current bookmark is also active
139
139
140 I.e., the bookmark listed in .hg/bookmarks.current also points to a
140 I.e., the bookmark listed in .hg/bookmarks.current also points to a
141 parent of the working directory.
141 parent of the working directory.
142 '''
142 '''
143 if not mark:
143 if not mark:
144 mark = repo._bookmarkcurrent
144 mark = repo._bookmarkcurrent
145 if not parents:
145 if not parents:
146 parents = [p.node() for p in repo[None].parents()]
146 parents = [p.node() for p in repo[None].parents()]
147 marks = repo._bookmarks
147 marks = repo._bookmarks
148 return (mark in marks and marks[mark] in parents)
148 return (mark in marks and marks[mark] in parents)
149
149
150 def updatecurrentbookmark(repo, oldnode, curbranch):
150 def updatecurrentbookmark(repo, oldnode, curbranch):
151 try:
151 try:
152 return update(repo, oldnode, repo.branchtip(curbranch))
152 return update(repo, oldnode, repo.branchtip(curbranch))
153 except error.RepoLookupError:
153 except error.RepoLookupError:
154 if curbranch == "default": # no default branch!
154 if curbranch == "default": # no default branch!
155 return update(repo, oldnode, repo.lookup("tip"))
155 return update(repo, oldnode, repo.lookup("tip"))
156 else:
156 else:
157 raise util.Abort(_("branch %s not found") % curbranch)
157 raise util.Abort(_("branch %s not found") % curbranch)
158
158
159 def deletedivergent(repo, deletefrom, bm):
159 def deletedivergent(repo, deletefrom, bm):
160 '''Delete divergent versions of bm on nodes in deletefrom.
160 '''Delete divergent versions of bm on nodes in deletefrom.
161
161
162 Return True if at least one bookmark was deleted, False otherwise.'''
162 Return True if at least one bookmark was deleted, False otherwise.'''
163 deleted = False
163 deleted = False
164 marks = repo._bookmarks
164 marks = repo._bookmarks
165 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
165 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
166 for mark in divergent:
166 for mark in divergent:
167 if mark and marks[mark] in deletefrom:
167 if mark and marks[mark] in deletefrom:
168 if mark != bm:
168 if mark != bm:
169 del marks[mark]
169 del marks[mark]
170 deleted = True
170 deleted = True
171 return deleted
171 return deleted
172
172
173 def calculateupdate(ui, repo, checkout):
173 def calculateupdate(ui, repo, checkout):
174 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
174 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
175 check out and where to move the active bookmark from, if needed.'''
175 check out and where to move the active bookmark from, if needed.'''
176 movemarkfrom = None
176 movemarkfrom = None
177 if checkout is None:
177 if checkout is None:
178 curmark = repo._bookmarkcurrent
178 curmark = repo._bookmarkcurrent
179 if iscurrent(repo):
179 if iscurrent(repo):
180 movemarkfrom = repo['.'].node()
180 movemarkfrom = repo['.'].node()
181 elif curmark:
181 elif curmark:
182 ui.status(_("updating to active bookmark %s\n") % curmark)
182 ui.status(_("updating to active bookmark %s\n") % curmark)
183 checkout = curmark
183 checkout = curmark
184 return (checkout, movemarkfrom)
184 return (checkout, movemarkfrom)
185
185
186 def update(repo, parents, node):
186 def update(repo, parents, node):
187 deletefrom = parents
187 deletefrom = parents
188 marks = repo._bookmarks
188 marks = repo._bookmarks
189 update = False
189 update = False
190 cur = repo._bookmarkcurrent
190 cur = repo._bookmarkcurrent
191 if not cur:
191 if not cur:
192 return False
192 return False
193
193
194 if marks[cur] in parents:
194 if marks[cur] in parents:
195 old = repo[marks[cur]]
195 old = repo[marks[cur]]
196 new = repo[node]
196 new = repo[node]
197 divs = [repo[b] for b in marks
197 divs = [repo[b] for b in marks
198 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
198 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
199 anc = repo.changelog.ancestors([new.rev()])
199 anc = repo.changelog.ancestors([new.rev()])
200 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
200 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
201 if old.descendant(new):
201 if old.descendant(new):
202 marks[cur] = new.node()
202 marks[cur] = new.node()
203 update = True
203 update = True
204
204
205 if deletedivergent(repo, deletefrom, cur):
205 if deletedivergent(repo, deletefrom, cur):
206 update = True
206 update = True
207
207
208 if update:
208 if update:
209 marks.write()
209 marks.write()
210 return update
210 return update
211
211
212 def listbookmarks(repo):
212 def listbookmarks(repo):
213 # We may try to list bookmarks on a repo type that does not
213 # We may try to list bookmarks on a repo type that does not
214 # support it (e.g., statichttprepository).
214 # support it (e.g., statichttprepository).
215 marks = getattr(repo, '_bookmarks', {})
215 marks = getattr(repo, '_bookmarks', {})
216
216
217 d = {}
217 d = {}
218 hasnode = repo.changelog.hasnode
218 hasnode = repo.changelog.hasnode
219 for k, v in marks.iteritems():
219 for k, v in marks.iteritems():
220 # don't expose local divergent bookmarks
220 # don't expose local divergent bookmarks
221 if hasnode(v) and ('@' not in k or k.endswith('@')):
221 if hasnode(v) and ('@' not in k or k.endswith('@')):
222 d[k] = hex(v)
222 d[k] = hex(v)
223 return d
223 return d
224
224
225 def pushbookmark(repo, key, old, new):
225 def pushbookmark(repo, key, old, new):
226 w = repo.wlock()
226 w = repo.wlock()
227 try:
227 try:
228 marks = repo._bookmarks
228 marks = repo._bookmarks
229 if hex(marks.get(key, '')) != old:
229 if hex(marks.get(key, '')) != old:
230 return False
230 return False
231 if new == '':
231 if new == '':
232 del marks[key]
232 del marks[key]
233 else:
233 else:
234 if new not in repo:
234 if new not in repo:
235 return False
235 return False
236 marks[key] = repo[new].node()
236 marks[key] = repo[new].node()
237 marks.write()
237 marks.write()
238 return True
238 return True
239 finally:
239 finally:
240 w.release()
240 w.release()
241
241
242 def compare(repo, srcmarks, dstmarks,
242 def compare(repo, srcmarks, dstmarks,
243 srchex=None, dsthex=None, targets=None):
243 srchex=None, dsthex=None, targets=None):
244 '''Compare bookmarks between srcmarks and dstmarks
244 '''Compare bookmarks between srcmarks and dstmarks
245
245
246 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
246 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
247 differ, invalid)", each are list of bookmarks below:
247 differ, invalid)", each are list of bookmarks below:
248
248
249 :addsrc: added on src side (removed on dst side, perhaps)
249 :addsrc: added on src side (removed on dst side, perhaps)
250 :adddst: added on dst side (removed on src side, perhaps)
250 :adddst: added on dst side (removed on src side, perhaps)
251 :advsrc: advanced on src side
251 :advsrc: advanced on src side
252 :advdst: advanced on dst side
252 :advdst: advanced on dst side
253 :diverge: diverge
253 :diverge: diverge
254 :differ: changed, but changeset referred on src is unknown on dst
254 :differ: changed, but changeset referred on src is unknown on dst
255 :invalid: unknown on both side
255 :invalid: unknown on both side
256
256
257 Each elements of lists in result tuple is tuple "(bookmark name,
257 Each elements of lists in result tuple is tuple "(bookmark name,
258 changeset ID on source side, changeset ID on destination
258 changeset ID on source side, changeset ID on destination
259 side)". Each changeset IDs are 40 hexadecimal digit string or
259 side)". Each changeset IDs are 40 hexadecimal digit string or
260 None.
260 None.
261
261
262 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
262 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
263 "invalid" list may be unknown for repo.
263 "invalid" list may be unknown for repo.
264
264
265 This function expects that "srcmarks" and "dstmarks" return
265 This function expects that "srcmarks" and "dstmarks" return
266 changeset ID in 40 hexadecimal digit string for specified
266 changeset ID in 40 hexadecimal digit string for specified
267 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
267 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
268 binary value), "srchex" or "dsthex" should be specified to convert
268 binary value), "srchex" or "dsthex" should be specified to convert
269 into such form.
269 into such form.
270
270
271 If "targets" is specified, only bookmarks listed in it are
271 If "targets" is specified, only bookmarks listed in it are
272 examined.
272 examined.
273 '''
273 '''
274 if not srchex:
274 if not srchex:
275 srchex = lambda x: x
275 srchex = lambda x: x
276 if not dsthex:
276 if not dsthex:
277 dsthex = lambda x: x
277 dsthex = lambda x: x
278
278
279 if targets:
279 if targets:
280 bset = set(targets)
280 bset = set(targets)
281 else:
281 else:
282 srcmarkset = set(srcmarks)
282 srcmarkset = set(srcmarks)
283 dstmarkset = set(dstmarks)
283 dstmarkset = set(dstmarks)
284 bset = srcmarkset ^ dstmarkset
284 bset = srcmarkset ^ dstmarkset
285 for b in srcmarkset & dstmarkset:
285 for b in srcmarkset & dstmarkset:
286 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
286 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
287 bset.add(b)
287 bset.add(b)
288
288
289 results = ([], [], [], [], [], [], [])
289 results = ([], [], [], [], [], [], [])
290 addsrc = results[0].append
290 addsrc = results[0].append
291 adddst = results[1].append
291 adddst = results[1].append
292 advsrc = results[2].append
292 advsrc = results[2].append
293 advdst = results[3].append
293 advdst = results[3].append
294 diverge = results[4].append
294 diverge = results[4].append
295 differ = results[5].append
295 differ = results[5].append
296 invalid = results[6].append
296 invalid = results[6].append
297
297
298 for b in sorted(bset):
298 for b in sorted(bset):
299 if b not in srcmarks:
299 if b not in srcmarks:
300 if b in dstmarks:
300 if b in dstmarks:
301 adddst((b, None, dsthex(dstmarks[b])))
301 adddst((b, None, dsthex(dstmarks[b])))
302 else:
302 else:
303 invalid((b, None, None))
303 invalid((b, None, None))
304 elif b not in dstmarks:
304 elif b not in dstmarks:
305 addsrc((b, srchex(srcmarks[b]), None))
305 addsrc((b, srchex(srcmarks[b]), None))
306 else:
306 else:
307 scid = srchex(srcmarks[b])
307 scid = srchex(srcmarks[b])
308 dcid = dsthex(dstmarks[b])
308 dcid = dsthex(dstmarks[b])
309 if scid in repo and dcid in repo:
309 if scid in repo and dcid in repo:
310 sctx = repo[scid]
310 sctx = repo[scid]
311 dctx = repo[dcid]
311 dctx = repo[dcid]
312 if sctx.rev() < dctx.rev():
312 if sctx.rev() < dctx.rev():
313 if validdest(repo, sctx, dctx):
313 if validdest(repo, sctx, dctx):
314 advdst((b, scid, dcid))
314 advdst((b, scid, dcid))
315 else:
315 else:
316 diverge((b, scid, dcid))
316 diverge((b, scid, dcid))
317 else:
317 else:
318 if validdest(repo, dctx, sctx):
318 if validdest(repo, dctx, sctx):
319 advsrc((b, scid, dcid))
319 advsrc((b, scid, dcid))
320 else:
320 else:
321 diverge((b, scid, dcid))
321 diverge((b, scid, dcid))
322 else:
322 else:
323 # it is too expensive to examine in detail, in this case
323 # it is too expensive to examine in detail, in this case
324 differ((b, scid, dcid))
324 differ((b, scid, dcid))
325
325
326 return results
326 return results
327
327
328 def _diverge(ui, b, path, localmarks):
328 def _diverge(ui, b, path, localmarks):
329 if b == '@':
329 if b == '@':
330 b = ''
330 b = ''
331 # find a unique @ suffix
331 # find a unique @ suffix
332 for x in range(1, 100):
332 for x in range(1, 100):
333 n = '%s@%d' % (b, x)
333 n = '%s@%d' % (b, x)
334 if n not in localmarks:
334 if n not in localmarks:
335 break
335 break
336 # try to use an @pathalias suffix
336 # try to use an @pathalias suffix
337 # if an @pathalias already exists, we overwrite (update) it
337 # if an @pathalias already exists, we overwrite (update) it
338 for p, u in ui.configitems("paths"):
338 for p, u in ui.configitems("paths"):
339 if path == u:
339 if path == u:
340 n = '%s@%s' % (b, p)
340 n = '%s@%s' % (b, p)
341 return n
341 return n
342
342
343 def updatefromremote(ui, repo, remotemarks, path):
343 def updatefromremote(ui, repo, remotemarks, path):
344 ui.debug("checking for updated bookmarks\n")
344 ui.debug("checking for updated bookmarks\n")
345 localmarks = repo._bookmarks
345 localmarks = repo._bookmarks
346 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
346 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
347 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
347 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
348
348
349 changed = []
349 changed = []
350 for b, scid, dcid in addsrc:
350 for b, scid, dcid in addsrc:
351 if scid in repo: # add remote bookmarks for changes we already have
351 if scid in repo: # add remote bookmarks for changes we already have
352 changed.append((b, bin(scid), ui.status,
352 changed.append((b, bin(scid), ui.status,
353 _("adding remote bookmark %s\n") % (b)))
353 _("adding remote bookmark %s\n") % (b)))
354 for b, scid, dcid in advsrc:
354 for b, scid, dcid in advsrc:
355 changed.append((b, bin(scid), ui.status,
355 changed.append((b, bin(scid), ui.status,
356 _("updating bookmark %s\n") % (b)))
356 _("updating bookmark %s\n") % (b)))
357 for b, scid, dcid in diverge:
357 for b, scid, dcid in diverge:
358 db = _diverge(ui, b, path, localmarks)
358 db = _diverge(ui, b, path, localmarks)
359 changed.append((db, bin(scid), ui.warn,
359 changed.append((db, bin(scid), ui.warn,
360 _("divergent bookmark %s stored as %s\n") % (b, db)))
360 _("divergent bookmark %s stored as %s\n") % (b, db)))
361 if changed:
361 if changed:
362 for b, node, writer, msg in sorted(changed):
362 for b, node, writer, msg in sorted(changed):
363 localmarks[b] = node
363 localmarks[b] = node
364 writer(msg)
364 writer(msg)
365 localmarks.write()
365 localmarks.write()
366
366
367 def pushtoremote(ui, repo, remote, targets):
368 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
369 ) = compare(repo, repo._bookmarks, remote.listkeys('bookmarks'),
370 srchex=hex, targets=targets)
371 if invalid:
372 b, scid, dcid = invalid[0]
373 ui.warn(_('bookmark %s does not exist on the local '
374 'or remote repository!\n') % b)
375 return 2
376
377 def push(b, old, new):
378 r = remote.pushkey('bookmarks', b, old, new)
379 if not r:
380 ui.warn(_('updating bookmark %s failed!\n') % b)
381 return 1
382 return 0
383 failed = 0
384 for b, scid, dcid in sorted(addsrc + advsrc + advdst + diverge + differ):
385 ui.status(_("exporting bookmark %s\n") % b)
386 if dcid is None:
387 dcid = ''
388 failed += push(b, dcid, scid)
389 for b, scid, dcid in adddst:
390 # treat as "deleted locally"
391 ui.status(_("deleting remote bookmark %s\n") % b)
392 failed += push(b, dcid, '')
393
394 if failed:
395 return 1
396
367 def diff(ui, dst, src):
397 def diff(ui, dst, src):
368 ui.status(_("searching for changed bookmarks\n"))
398 ui.status(_("searching for changed bookmarks\n"))
369
399
370 smarks = src.listkeys('bookmarks')
400 smarks = src.listkeys('bookmarks')
371 dmarks = dst.listkeys('bookmarks')
401 dmarks = dst.listkeys('bookmarks')
372
402
373 diff = sorted(set(smarks) - set(dmarks))
403 diff = sorted(set(smarks) - set(dmarks))
374 for k in diff:
404 for k in diff:
375 mark = ui.debugflag and smarks[k] or smarks[k][:12]
405 mark = ui.debugflag and smarks[k] or smarks[k][:12]
376 ui.write(" %-25s %s\n" % (k, mark))
406 ui.write(" %-25s %s\n" % (k, mark))
377
407
378 if len(diff) <= 0:
408 if len(diff) <= 0:
379 ui.status(_("no changed bookmarks found\n"))
409 ui.status(_("no changed bookmarks found\n"))
380 return 1
410 return 1
381 return 0
411 return 0
382
412
383 def validdest(repo, old, new):
413 def validdest(repo, old, new):
384 """Is the new bookmark destination a valid update from the old one"""
414 """Is the new bookmark destination a valid update from the old one"""
385 repo = repo.unfiltered()
415 repo = repo.unfiltered()
386 if old == new:
416 if old == new:
387 # Old == new -> nothing to update.
417 # Old == new -> nothing to update.
388 return False
418 return False
389 elif not old:
419 elif not old:
390 # old is nullrev, anything is valid.
420 # old is nullrev, anything is valid.
391 # (new != nullrev has been excluded by the previous check)
421 # (new != nullrev has been excluded by the previous check)
392 return True
422 return True
393 elif repo.obsstore:
423 elif repo.obsstore:
394 return new.node() in obsolete.foreground(repo, [old.node()])
424 return new.node() in obsolete.foreground(repo, [old.node()])
395 else:
425 else:
396 # still an independent clause as it is lazyer (and therefore faster)
426 # still an independent clause as it is lazyer (and therefore faster)
397 return old.descendant(new)
427 return old.descendant(new)
@@ -1,5928 +1,5914 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, commandserver
15 import sshserver, hgweb, commandserver
16 from hgweb import server as hgweb_server
16 from hgweb import server as hgweb_server
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge, graphmod
19 import dagparser, context, simplemerge, graphmod
20 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
21 import phases, obsolete
21 import phases, obsolete
22
22
23 table = {}
23 table = {}
24
24
25 command = cmdutil.command(table)
25 command = cmdutil.command(table)
26
26
27 # common command options
27 # common command options
28
28
29 globalopts = [
29 globalopts = [
30 ('R', 'repository', '',
30 ('R', 'repository', '',
31 _('repository root directory or name of overlay bundle file'),
31 _('repository root directory or name of overlay bundle file'),
32 _('REPO')),
32 _('REPO')),
33 ('', 'cwd', '',
33 ('', 'cwd', '',
34 _('change working directory'), _('DIR')),
34 _('change working directory'), _('DIR')),
35 ('y', 'noninteractive', None,
35 ('y', 'noninteractive', None,
36 _('do not prompt, automatically pick the first choice for all prompts')),
36 _('do not prompt, automatically pick the first choice for all prompts')),
37 ('q', 'quiet', None, _('suppress output')),
37 ('q', 'quiet', None, _('suppress output')),
38 ('v', 'verbose', None, _('enable additional output')),
38 ('v', 'verbose', None, _('enable additional output')),
39 ('', 'config', [],
39 ('', 'config', [],
40 _('set/override config option (use \'section.name=value\')'),
40 _('set/override config option (use \'section.name=value\')'),
41 _('CONFIG')),
41 _('CONFIG')),
42 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debug', None, _('enable debugging output')),
43 ('', 'debugger', None, _('start debugger')),
43 ('', 'debugger', None, _('start debugger')),
44 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
45 _('ENCODE')),
45 _('ENCODE')),
46 ('', 'encodingmode', encoding.encodingmode,
46 ('', 'encodingmode', encoding.encodingmode,
47 _('set the charset encoding mode'), _('MODE')),
47 _('set the charset encoding mode'), _('MODE')),
48 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'traceback', None, _('always print a traceback on exception')),
49 ('', 'time', None, _('time how long the command takes')),
49 ('', 'time', None, _('time how long the command takes')),
50 ('', 'profile', None, _('print command execution profile')),
50 ('', 'profile', None, _('print command execution profile')),
51 ('', 'version', None, _('output version information and exit')),
51 ('', 'version', None, _('output version information and exit')),
52 ('h', 'help', None, _('display help and exit')),
52 ('h', 'help', None, _('display help and exit')),
53 ('', 'hidden', False, _('consider hidden changesets')),
53 ('', 'hidden', False, _('consider hidden changesets')),
54 ]
54 ]
55
55
56 dryrunopts = [('n', 'dry-run', None,
56 dryrunopts = [('n', 'dry-run', None,
57 _('do not perform actions, just print output'))]
57 _('do not perform actions, just print output'))]
58
58
59 remoteopts = [
59 remoteopts = [
60 ('e', 'ssh', '',
60 ('e', 'ssh', '',
61 _('specify ssh command to use'), _('CMD')),
61 _('specify ssh command to use'), _('CMD')),
62 ('', 'remotecmd', '',
62 ('', 'remotecmd', '',
63 _('specify hg command to run on the remote side'), _('CMD')),
63 _('specify hg command to run on the remote side'), _('CMD')),
64 ('', 'insecure', None,
64 ('', 'insecure', None,
65 _('do not verify server certificate (ignoring web.cacerts config)')),
65 _('do not verify server certificate (ignoring web.cacerts config)')),
66 ]
66 ]
67
67
68 walkopts = [
68 walkopts = [
69 ('I', 'include', [],
69 ('I', 'include', [],
70 _('include names matching the given patterns'), _('PATTERN')),
70 _('include names matching the given patterns'), _('PATTERN')),
71 ('X', 'exclude', [],
71 ('X', 'exclude', [],
72 _('exclude names matching the given patterns'), _('PATTERN')),
72 _('exclude names matching the given patterns'), _('PATTERN')),
73 ]
73 ]
74
74
75 commitopts = [
75 commitopts = [
76 ('m', 'message', '',
76 ('m', 'message', '',
77 _('use text as commit message'), _('TEXT')),
77 _('use text as commit message'), _('TEXT')),
78 ('l', 'logfile', '',
78 ('l', 'logfile', '',
79 _('read commit message from file'), _('FILE')),
79 _('read commit message from file'), _('FILE')),
80 ]
80 ]
81
81
82 commitopts2 = [
82 commitopts2 = [
83 ('d', 'date', '',
83 ('d', 'date', '',
84 _('record the specified date as commit date'), _('DATE')),
84 _('record the specified date as commit date'), _('DATE')),
85 ('u', 'user', '',
85 ('u', 'user', '',
86 _('record the specified user as committer'), _('USER')),
86 _('record the specified user as committer'), _('USER')),
87 ]
87 ]
88
88
89 templateopts = [
89 templateopts = [
90 ('', 'style', '',
90 ('', 'style', '',
91 _('display using template map file'), _('STYLE')),
91 _('display using template map file'), _('STYLE')),
92 ('', 'template', '',
92 ('', 'template', '',
93 _('display with template'), _('TEMPLATE')),
93 _('display with template'), _('TEMPLATE')),
94 ]
94 ]
95
95
96 logopts = [
96 logopts = [
97 ('p', 'patch', None, _('show patch')),
97 ('p', 'patch', None, _('show patch')),
98 ('g', 'git', None, _('use git extended diff format')),
98 ('g', 'git', None, _('use git extended diff format')),
99 ('l', 'limit', '',
99 ('l', 'limit', '',
100 _('limit number of changes displayed'), _('NUM')),
100 _('limit number of changes displayed'), _('NUM')),
101 ('M', 'no-merges', None, _('do not show merges')),
101 ('M', 'no-merges', None, _('do not show merges')),
102 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('', 'stat', None, _('output diffstat-style summary of changes')),
103 ('G', 'graph', None, _("show the revision DAG")),
103 ('G', 'graph', None, _("show the revision DAG")),
104 ] + templateopts
104 ] + templateopts
105
105
106 diffopts = [
106 diffopts = [
107 ('a', 'text', None, _('treat all files as text')),
107 ('a', 'text', None, _('treat all files as text')),
108 ('g', 'git', None, _('use git extended diff format')),
108 ('g', 'git', None, _('use git extended diff format')),
109 ('', 'nodates', None, _('omit dates from diff headers'))
109 ('', 'nodates', None, _('omit dates from diff headers'))
110 ]
110 ]
111
111
112 diffwsopts = [
112 diffwsopts = [
113 ('w', 'ignore-all-space', None,
113 ('w', 'ignore-all-space', None,
114 _('ignore white space when comparing lines')),
114 _('ignore white space when comparing lines')),
115 ('b', 'ignore-space-change', None,
115 ('b', 'ignore-space-change', None,
116 _('ignore changes in the amount of white space')),
116 _('ignore changes in the amount of white space')),
117 ('B', 'ignore-blank-lines', None,
117 ('B', 'ignore-blank-lines', None,
118 _('ignore changes whose lines are all blank')),
118 _('ignore changes whose lines are all blank')),
119 ]
119 ]
120
120
121 diffopts2 = [
121 diffopts2 = [
122 ('p', 'show-function', None, _('show which function each change is in')),
122 ('p', 'show-function', None, _('show which function each change is in')),
123 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ('', 'reverse', None, _('produce a diff that undoes the changes')),
124 ] + diffwsopts + [
124 ] + diffwsopts + [
125 ('U', 'unified', '',
125 ('U', 'unified', '',
126 _('number of lines of context to show'), _('NUM')),
126 _('number of lines of context to show'), _('NUM')),
127 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ('', 'stat', None, _('output diffstat-style summary of changes')),
128 ]
128 ]
129
129
130 mergetoolopts = [
130 mergetoolopts = [
131 ('t', 'tool', '', _('specify merge tool')),
131 ('t', 'tool', '', _('specify merge tool')),
132 ]
132 ]
133
133
134 similarityopts = [
134 similarityopts = [
135 ('s', 'similarity', '',
135 ('s', 'similarity', '',
136 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
137 ]
137 ]
138
138
139 subrepoopts = [
139 subrepoopts = [
140 ('S', 'subrepos', None,
140 ('S', 'subrepos', None,
141 _('recurse into subrepositories'))
141 _('recurse into subrepositories'))
142 ]
142 ]
143
143
144 # Commands start here, listed alphabetically
144 # Commands start here, listed alphabetically
145
145
146 @command('^add',
146 @command('^add',
147 walkopts + subrepoopts + dryrunopts,
147 walkopts + subrepoopts + dryrunopts,
148 _('[OPTION]... [FILE]...'))
148 _('[OPTION]... [FILE]...'))
149 def add(ui, repo, *pats, **opts):
149 def add(ui, repo, *pats, **opts):
150 """add the specified files on the next commit
150 """add the specified files on the next commit
151
151
152 Schedule files to be version controlled and added to the
152 Schedule files to be version controlled and added to the
153 repository.
153 repository.
154
154
155 The files will be added to the repository at the next commit. To
155 The files will be added to the repository at the next commit. To
156 undo an add before that, see :hg:`forget`.
156 undo an add before that, see :hg:`forget`.
157
157
158 If no names are given, add all files to the repository.
158 If no names are given, add all files to the repository.
159
159
160 .. container:: verbose
160 .. container:: verbose
161
161
162 An example showing how new (unknown) files are added
162 An example showing how new (unknown) files are added
163 automatically by :hg:`add`::
163 automatically by :hg:`add`::
164
164
165 $ ls
165 $ ls
166 foo.c
166 foo.c
167 $ hg status
167 $ hg status
168 ? foo.c
168 ? foo.c
169 $ hg add
169 $ hg add
170 adding foo.c
170 adding foo.c
171 $ hg status
171 $ hg status
172 A foo.c
172 A foo.c
173
173
174 Returns 0 if all files are successfully added.
174 Returns 0 if all files are successfully added.
175 """
175 """
176
176
177 m = scmutil.match(repo[None], pats, opts)
177 m = scmutil.match(repo[None], pats, opts)
178 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
179 opts.get('subrepos'), prefix="", explicitonly=False)
179 opts.get('subrepos'), prefix="", explicitonly=False)
180 return rejected and 1 or 0
180 return rejected and 1 or 0
181
181
182 @command('addremove',
182 @command('addremove',
183 similarityopts + walkopts + dryrunopts,
183 similarityopts + walkopts + dryrunopts,
184 _('[OPTION]... [FILE]...'))
184 _('[OPTION]... [FILE]...'))
185 def addremove(ui, repo, *pats, **opts):
185 def addremove(ui, repo, *pats, **opts):
186 """add all new files, delete all missing files
186 """add all new files, delete all missing files
187
187
188 Add all new files and remove all missing files from the
188 Add all new files and remove all missing files from the
189 repository.
189 repository.
190
190
191 New files are ignored if they match any of the patterns in
191 New files are ignored if they match any of the patterns in
192 ``.hgignore``. As with add, these changes take effect at the next
192 ``.hgignore``. As with add, these changes take effect at the next
193 commit.
193 commit.
194
194
195 Use the -s/--similarity option to detect renamed files. This
195 Use the -s/--similarity option to detect renamed files. This
196 option takes a percentage between 0 (disabled) and 100 (files must
196 option takes a percentage between 0 (disabled) and 100 (files must
197 be identical) as its parameter. With a parameter greater than 0,
197 be identical) as its parameter. With a parameter greater than 0,
198 this compares every removed file with every added file and records
198 this compares every removed file with every added file and records
199 those similar enough as renames. Detecting renamed files this way
199 those similar enough as renames. Detecting renamed files this way
200 can be expensive. After using this option, :hg:`status -C` can be
200 can be expensive. After using this option, :hg:`status -C` can be
201 used to check which files were identified as moved or renamed. If
201 used to check which files were identified as moved or renamed. If
202 not specified, -s/--similarity defaults to 100 and only renames of
202 not specified, -s/--similarity defaults to 100 and only renames of
203 identical files are detected.
203 identical files are detected.
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207 try:
207 try:
208 sim = float(opts.get('similarity') or 100)
208 sim = float(opts.get('similarity') or 100)
209 except ValueError:
209 except ValueError:
210 raise util.Abort(_('similarity must be a number'))
210 raise util.Abort(_('similarity must be a number'))
211 if sim < 0 or sim > 100:
211 if sim < 0 or sim > 100:
212 raise util.Abort(_('similarity must be between 0 and 100'))
212 raise util.Abort(_('similarity must be between 0 and 100'))
213 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
214
214
215 @command('^annotate|blame',
215 @command('^annotate|blame',
216 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
217 ('', 'follow', None,
217 ('', 'follow', None,
218 _('follow copies/renames and list the filename (DEPRECATED)')),
218 _('follow copies/renames and list the filename (DEPRECATED)')),
219 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('', 'no-follow', None, _("don't follow copies and renames")),
220 ('a', 'text', None, _('treat all files as text')),
220 ('a', 'text', None, _('treat all files as text')),
221 ('u', 'user', None, _('list the author (long with -v)')),
221 ('u', 'user', None, _('list the author (long with -v)')),
222 ('f', 'file', None, _('list the filename')),
222 ('f', 'file', None, _('list the filename')),
223 ('d', 'date', None, _('list the date (short with -q)')),
223 ('d', 'date', None, _('list the date (short with -q)')),
224 ('n', 'number', None, _('list the revision number (default)')),
224 ('n', 'number', None, _('list the revision number (default)')),
225 ('c', 'changeset', None, _('list the changeset')),
225 ('c', 'changeset', None, _('list the changeset')),
226 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ('l', 'line-number', None, _('show line number at the first appearance'))
227 ] + diffwsopts + walkopts,
227 ] + diffwsopts + walkopts,
228 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
229 def annotate(ui, repo, *pats, **opts):
229 def annotate(ui, repo, *pats, **opts):
230 """show changeset information by line for each file
230 """show changeset information by line for each file
231
231
232 List changes in files, showing the revision id responsible for
232 List changes in files, showing the revision id responsible for
233 each line
233 each line
234
234
235 This command is useful for discovering when a change was made and
235 This command is useful for discovering when a change was made and
236 by whom.
236 by whom.
237
237
238 Without the -a/--text option, annotate will avoid processing files
238 Without the -a/--text option, annotate will avoid processing files
239 it detects as binary. With -a, annotate will annotate the file
239 it detects as binary. With -a, annotate will annotate the file
240 anyway, although the results will probably be neither useful
240 anyway, although the results will probably be neither useful
241 nor desirable.
241 nor desirable.
242
242
243 Returns 0 on success.
243 Returns 0 on success.
244 """
244 """
245 if opts.get('follow'):
245 if opts.get('follow'):
246 # --follow is deprecated and now just an alias for -f/--file
246 # --follow is deprecated and now just an alias for -f/--file
247 # to mimic the behavior of Mercurial before version 1.5
247 # to mimic the behavior of Mercurial before version 1.5
248 opts['file'] = True
248 opts['file'] = True
249
249
250 datefunc = ui.quiet and util.shortdate or util.datestr
250 datefunc = ui.quiet and util.shortdate or util.datestr
251 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
252
252
253 if not pats:
253 if not pats:
254 raise util.Abort(_('at least one filename or pattern is required'))
254 raise util.Abort(_('at least one filename or pattern is required'))
255
255
256 hexfn = ui.debugflag and hex or short
256 hexfn = ui.debugflag and hex or short
257
257
258 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
259 ('number', ' ', lambda x: str(x[0].rev())),
259 ('number', ' ', lambda x: str(x[0].rev())),
260 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('changeset', ' ', lambda x: hexfn(x[0].node())),
261 ('date', ' ', getdate),
261 ('date', ' ', getdate),
262 ('file', ' ', lambda x: x[0].path()),
262 ('file', ' ', lambda x: x[0].path()),
263 ('line_number', ':', lambda x: str(x[1])),
263 ('line_number', ':', lambda x: str(x[1])),
264 ]
264 ]
265
265
266 if (not opts.get('user') and not opts.get('changeset')
266 if (not opts.get('user') and not opts.get('changeset')
267 and not opts.get('date') and not opts.get('file')):
267 and not opts.get('date') and not opts.get('file')):
268 opts['number'] = True
268 opts['number'] = True
269
269
270 linenumber = opts.get('line_number') is not None
270 linenumber = opts.get('line_number') is not None
271 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
272 raise util.Abort(_('at least one of -n/-c is required for -l'))
272 raise util.Abort(_('at least one of -n/-c is required for -l'))
273
273
274 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
275 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
276
276
277 def bad(x, y):
277 def bad(x, y):
278 raise util.Abort("%s: %s" % (x, y))
278 raise util.Abort("%s: %s" % (x, y))
279
279
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
281 m = scmutil.match(ctx, pats, opts)
281 m = scmutil.match(ctx, pats, opts)
282 m.bad = bad
282 m.bad = bad
283 follow = not opts.get('no_follow')
283 follow = not opts.get('no_follow')
284 diffopts = patch.diffopts(ui, opts, section='annotate')
284 diffopts = patch.diffopts(ui, opts, section='annotate')
285 for abs in ctx.walk(m):
285 for abs in ctx.walk(m):
286 fctx = ctx[abs]
286 fctx = ctx[abs]
287 if not opts.get('text') and util.binary(fctx.data()):
287 if not opts.get('text') and util.binary(fctx.data()):
288 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
289 continue
289 continue
290
290
291 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 lines = fctx.annotate(follow=follow, linenumber=linenumber,
292 diffopts=diffopts)
292 diffopts=diffopts)
293 pieces = []
293 pieces = []
294
294
295 for f, sep in funcmap:
295 for f, sep in funcmap:
296 l = [f(n) for n, dummy in lines]
296 l = [f(n) for n, dummy in lines]
297 if l:
297 if l:
298 sized = [(x, encoding.colwidth(x)) for x in l]
298 sized = [(x, encoding.colwidth(x)) for x in l]
299 ml = max([w for x, w in sized])
299 ml = max([w for x, w in sized])
300 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
301 for x, w in sized])
301 for x, w in sized])
302
302
303 if pieces:
303 if pieces:
304 for p, l in zip(zip(*pieces), lines):
304 for p, l in zip(zip(*pieces), lines):
305 ui.write("%s: %s" % ("".join(p), l[1]))
305 ui.write("%s: %s" % ("".join(p), l[1]))
306
306
307 if lines and not lines[-1][1].endswith('\n'):
307 if lines and not lines[-1][1].endswith('\n'):
308 ui.write('\n')
308 ui.write('\n')
309
309
310 @command('archive',
310 @command('archive',
311 [('', 'no-decode', None, _('do not pass files through decoders')),
311 [('', 'no-decode', None, _('do not pass files through decoders')),
312 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 ('p', 'prefix', '', _('directory prefix for files in archive'),
313 _('PREFIX')),
313 _('PREFIX')),
314 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('r', 'rev', '', _('revision to distribute'), _('REV')),
315 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
316 ] + subrepoopts + walkopts,
316 ] + subrepoopts + walkopts,
317 _('[OPTION]... DEST'))
317 _('[OPTION]... DEST'))
318 def archive(ui, repo, dest, **opts):
318 def archive(ui, repo, dest, **opts):
319 '''create an unversioned archive of a repository revision
319 '''create an unversioned archive of a repository revision
320
320
321 By default, the revision used is the parent of the working
321 By default, the revision used is the parent of the working
322 directory; use -r/--rev to specify a different revision.
322 directory; use -r/--rev to specify a different revision.
323
323
324 The archive type is automatically detected based on file
324 The archive type is automatically detected based on file
325 extension (or override using -t/--type).
325 extension (or override using -t/--type).
326
326
327 .. container:: verbose
327 .. container:: verbose
328
328
329 Examples:
329 Examples:
330
330
331 - create a zip file containing the 1.0 release::
331 - create a zip file containing the 1.0 release::
332
332
333 hg archive -r 1.0 project-1.0.zip
333 hg archive -r 1.0 project-1.0.zip
334
334
335 - create a tarball excluding .hg files::
335 - create a tarball excluding .hg files::
336
336
337 hg archive project.tar.gz -X ".hg*"
337 hg archive project.tar.gz -X ".hg*"
338
338
339 Valid types are:
339 Valid types are:
340
340
341 :``files``: a directory full of files (default)
341 :``files``: a directory full of files (default)
342 :``tar``: tar archive, uncompressed
342 :``tar``: tar archive, uncompressed
343 :``tbz2``: tar archive, compressed using bzip2
343 :``tbz2``: tar archive, compressed using bzip2
344 :``tgz``: tar archive, compressed using gzip
344 :``tgz``: tar archive, compressed using gzip
345 :``uzip``: zip archive, uncompressed
345 :``uzip``: zip archive, uncompressed
346 :``zip``: zip archive, compressed using deflate
346 :``zip``: zip archive, compressed using deflate
347
347
348 The exact name of the destination archive or directory is given
348 The exact name of the destination archive or directory is given
349 using a format string; see :hg:`help export` for details.
349 using a format string; see :hg:`help export` for details.
350
350
351 Each member added to an archive file has a directory prefix
351 Each member added to an archive file has a directory prefix
352 prepended. Use -p/--prefix to specify a format string for the
352 prepended. Use -p/--prefix to specify a format string for the
353 prefix. The default is the basename of the archive, with suffixes
353 prefix. The default is the basename of the archive, with suffixes
354 removed.
354 removed.
355
355
356 Returns 0 on success.
356 Returns 0 on success.
357 '''
357 '''
358
358
359 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 ctx = scmutil.revsingle(repo, opts.get('rev'))
360 if not ctx:
360 if not ctx:
361 raise util.Abort(_('no working directory: please specify a revision'))
361 raise util.Abort(_('no working directory: please specify a revision'))
362 node = ctx.node()
362 node = ctx.node()
363 dest = cmdutil.makefilename(repo, dest, node)
363 dest = cmdutil.makefilename(repo, dest, node)
364 if os.path.realpath(dest) == repo.root:
364 if os.path.realpath(dest) == repo.root:
365 raise util.Abort(_('repository root cannot be destination'))
365 raise util.Abort(_('repository root cannot be destination'))
366
366
367 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 kind = opts.get('type') or archival.guesskind(dest) or 'files'
368 prefix = opts.get('prefix')
368 prefix = opts.get('prefix')
369
369
370 if dest == '-':
370 if dest == '-':
371 if kind == 'files':
371 if kind == 'files':
372 raise util.Abort(_('cannot archive plain files to stdout'))
372 raise util.Abort(_('cannot archive plain files to stdout'))
373 dest = cmdutil.makefileobj(repo, dest)
373 dest = cmdutil.makefileobj(repo, dest)
374 if not prefix:
374 if not prefix:
375 prefix = os.path.basename(repo.root) + '-%h'
375 prefix = os.path.basename(repo.root) + '-%h'
376
376
377 prefix = cmdutil.makefilename(repo, prefix, node)
377 prefix = cmdutil.makefilename(repo, prefix, node)
378 matchfn = scmutil.match(ctx, [], opts)
378 matchfn = scmutil.match(ctx, [], opts)
379 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
380 matchfn, prefix, subrepos=opts.get('subrepos'))
380 matchfn, prefix, subrepos=opts.get('subrepos'))
381
381
382 @command('backout',
382 @command('backout',
383 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 [('', 'merge', None, _('merge with old dirstate parent after backout')),
384 ('', 'parent', '',
384 ('', 'parent', '',
385 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
386 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ('r', 'rev', '', _('revision to backout'), _('REV')),
387 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 ] + mergetoolopts + walkopts + commitopts + commitopts2,
388 _('[OPTION]... [-r] REV'))
388 _('[OPTION]... [-r] REV'))
389 def backout(ui, repo, node=None, rev=None, **opts):
389 def backout(ui, repo, node=None, rev=None, **opts):
390 '''reverse effect of earlier changeset
390 '''reverse effect of earlier changeset
391
391
392 Prepare a new changeset with the effect of REV undone in the
392 Prepare a new changeset with the effect of REV undone in the
393 current working directory.
393 current working directory.
394
394
395 If REV is the parent of the working directory, then this new changeset
395 If REV is the parent of the working directory, then this new changeset
396 is committed automatically. Otherwise, hg needs to merge the
396 is committed automatically. Otherwise, hg needs to merge the
397 changes and the merged result is left uncommitted.
397 changes and the merged result is left uncommitted.
398
398
399 .. note::
399 .. note::
400
400
401 backout cannot be used to fix either an unwanted or
401 backout cannot be used to fix either an unwanted or
402 incorrect merge.
402 incorrect merge.
403
403
404 .. container:: verbose
404 .. container:: verbose
405
405
406 By default, the pending changeset will have one parent,
406 By default, the pending changeset will have one parent,
407 maintaining a linear history. With --merge, the pending
407 maintaining a linear history. With --merge, the pending
408 changeset will instead have two parents: the old parent of the
408 changeset will instead have two parents: the old parent of the
409 working directory and a new child of REV that simply undoes REV.
409 working directory and a new child of REV that simply undoes REV.
410
410
411 Before version 1.7, the behavior without --merge was equivalent
411 Before version 1.7, the behavior without --merge was equivalent
412 to specifying --merge followed by :hg:`update --clean .` to
412 to specifying --merge followed by :hg:`update --clean .` to
413 cancel the merge and leave the child of REV as a head to be
413 cancel the merge and leave the child of REV as a head to be
414 merged separately.
414 merged separately.
415
415
416 See :hg:`help dates` for a list of formats valid for -d/--date.
416 See :hg:`help dates` for a list of formats valid for -d/--date.
417
417
418 Returns 0 on success.
418 Returns 0 on success.
419 '''
419 '''
420 if rev and node:
420 if rev and node:
421 raise util.Abort(_("please specify just one revision"))
421 raise util.Abort(_("please specify just one revision"))
422
422
423 if not rev:
423 if not rev:
424 rev = node
424 rev = node
425
425
426 if not rev:
426 if not rev:
427 raise util.Abort(_("please specify a revision to backout"))
427 raise util.Abort(_("please specify a revision to backout"))
428
428
429 date = opts.get('date')
429 date = opts.get('date')
430 if date:
430 if date:
431 opts['date'] = util.parsedate(date)
431 opts['date'] = util.parsedate(date)
432
432
433 cmdutil.checkunfinished(repo)
433 cmdutil.checkunfinished(repo)
434 cmdutil.bailifchanged(repo)
434 cmdutil.bailifchanged(repo)
435 node = scmutil.revsingle(repo, rev).node()
435 node = scmutil.revsingle(repo, rev).node()
436
436
437 op1, op2 = repo.dirstate.parents()
437 op1, op2 = repo.dirstate.parents()
438 a = repo.changelog.ancestor(op1, node)
438 a = repo.changelog.ancestor(op1, node)
439 if a != node:
439 if a != node:
440 raise util.Abort(_('cannot backout change on a different branch'))
440 raise util.Abort(_('cannot backout change on a different branch'))
441
441
442 p1, p2 = repo.changelog.parents(node)
442 p1, p2 = repo.changelog.parents(node)
443 if p1 == nullid:
443 if p1 == nullid:
444 raise util.Abort(_('cannot backout a change with no parents'))
444 raise util.Abort(_('cannot backout a change with no parents'))
445 if p2 != nullid:
445 if p2 != nullid:
446 if not opts.get('parent'):
446 if not opts.get('parent'):
447 raise util.Abort(_('cannot backout a merge changeset'))
447 raise util.Abort(_('cannot backout a merge changeset'))
448 p = repo.lookup(opts['parent'])
448 p = repo.lookup(opts['parent'])
449 if p not in (p1, p2):
449 if p not in (p1, p2):
450 raise util.Abort(_('%s is not a parent of %s') %
450 raise util.Abort(_('%s is not a parent of %s') %
451 (short(p), short(node)))
451 (short(p), short(node)))
452 parent = p
452 parent = p
453 else:
453 else:
454 if opts.get('parent'):
454 if opts.get('parent'):
455 raise util.Abort(_('cannot use --parent on non-merge changeset'))
455 raise util.Abort(_('cannot use --parent on non-merge changeset'))
456 parent = p1
456 parent = p1
457
457
458 # the backout should appear on the same branch
458 # the backout should appear on the same branch
459 wlock = repo.wlock()
459 wlock = repo.wlock()
460 try:
460 try:
461 branch = repo.dirstate.branch()
461 branch = repo.dirstate.branch()
462 bheads = repo.branchheads(branch)
462 bheads = repo.branchheads(branch)
463 hg.clean(repo, node, show_stats=False)
463 hg.clean(repo, node, show_stats=False)
464 repo.dirstate.setbranch(branch)
464 repo.dirstate.setbranch(branch)
465 rctx = scmutil.revsingle(repo, hex(parent))
465 rctx = scmutil.revsingle(repo, hex(parent))
466 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
466 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
467 if not opts.get('merge') and op1 != node:
467 if not opts.get('merge') and op1 != node:
468 try:
468 try:
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
470 return hg.update(repo, op1)
470 return hg.update(repo, op1)
471 finally:
471 finally:
472 ui.setconfig('ui', 'forcemerge', '')
472 ui.setconfig('ui', 'forcemerge', '')
473
473
474 e = cmdutil.commiteditor
474 e = cmdutil.commiteditor
475 if not opts['message'] and not opts['logfile']:
475 if not opts['message'] and not opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 opts['message'] = "Backed out changeset %s" % short(node)
477 opts['message'] = "Backed out changeset %s" % short(node)
478 e = cmdutil.commitforceeditor
478 e = cmdutil.commitforceeditor
479
479
480 def commitfunc(ui, repo, message, match, opts):
480 def commitfunc(ui, repo, message, match, opts):
481 return repo.commit(message, opts.get('user'), opts.get('date'),
481 return repo.commit(message, opts.get('user'), opts.get('date'),
482 match, editor=e)
482 match, editor=e)
483 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
483 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
484 cmdutil.commitstatus(repo, newnode, branch, bheads)
484 cmdutil.commitstatus(repo, newnode, branch, bheads)
485
485
486 def nice(node):
486 def nice(node):
487 return '%d:%s' % (repo.changelog.rev(node), short(node))
487 return '%d:%s' % (repo.changelog.rev(node), short(node))
488 ui.status(_('changeset %s backs out changeset %s\n') %
488 ui.status(_('changeset %s backs out changeset %s\n') %
489 (nice(repo.changelog.tip()), nice(node)))
489 (nice(repo.changelog.tip()), nice(node)))
490 if opts.get('merge') and op1 != node:
490 if opts.get('merge') and op1 != node:
491 hg.clean(repo, op1, show_stats=False)
491 hg.clean(repo, op1, show_stats=False)
492 ui.status(_('merging with changeset %s\n')
492 ui.status(_('merging with changeset %s\n')
493 % nice(repo.changelog.tip()))
493 % nice(repo.changelog.tip()))
494 try:
494 try:
495 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
495 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
496 return hg.merge(repo, hex(repo.changelog.tip()))
496 return hg.merge(repo, hex(repo.changelog.tip()))
497 finally:
497 finally:
498 ui.setconfig('ui', 'forcemerge', '')
498 ui.setconfig('ui', 'forcemerge', '')
499 finally:
499 finally:
500 wlock.release()
500 wlock.release()
501 return 0
501 return 0
502
502
503 @command('bisect',
503 @command('bisect',
504 [('r', 'reset', False, _('reset bisect state')),
504 [('r', 'reset', False, _('reset bisect state')),
505 ('g', 'good', False, _('mark changeset good')),
505 ('g', 'good', False, _('mark changeset good')),
506 ('b', 'bad', False, _('mark changeset bad')),
506 ('b', 'bad', False, _('mark changeset bad')),
507 ('s', 'skip', False, _('skip testing changeset')),
507 ('s', 'skip', False, _('skip testing changeset')),
508 ('e', 'extend', False, _('extend the bisect range')),
508 ('e', 'extend', False, _('extend the bisect range')),
509 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
509 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
510 ('U', 'noupdate', False, _('do not update to target'))],
510 ('U', 'noupdate', False, _('do not update to target'))],
511 _("[-gbsr] [-U] [-c CMD] [REV]"))
511 _("[-gbsr] [-U] [-c CMD] [REV]"))
512 def bisect(ui, repo, rev=None, extra=None, command=None,
512 def bisect(ui, repo, rev=None, extra=None, command=None,
513 reset=None, good=None, bad=None, skip=None, extend=None,
513 reset=None, good=None, bad=None, skip=None, extend=None,
514 noupdate=None):
514 noupdate=None):
515 """subdivision search of changesets
515 """subdivision search of changesets
516
516
517 This command helps to find changesets which introduce problems. To
517 This command helps to find changesets which introduce problems. To
518 use, mark the earliest changeset you know exhibits the problem as
518 use, mark the earliest changeset you know exhibits the problem as
519 bad, then mark the latest changeset which is free from the problem
519 bad, then mark the latest changeset which is free from the problem
520 as good. Bisect will update your working directory to a revision
520 as good. Bisect will update your working directory to a revision
521 for testing (unless the -U/--noupdate option is specified). Once
521 for testing (unless the -U/--noupdate option is specified). Once
522 you have performed tests, mark the working directory as good or
522 you have performed tests, mark the working directory as good or
523 bad, and bisect will either update to another candidate changeset
523 bad, and bisect will either update to another candidate changeset
524 or announce that it has found the bad revision.
524 or announce that it has found the bad revision.
525
525
526 As a shortcut, you can also use the revision argument to mark a
526 As a shortcut, you can also use the revision argument to mark a
527 revision as good or bad without checking it out first.
527 revision as good or bad without checking it out first.
528
528
529 If you supply a command, it will be used for automatic bisection.
529 If you supply a command, it will be used for automatic bisection.
530 The environment variable HG_NODE will contain the ID of the
530 The environment variable HG_NODE will contain the ID of the
531 changeset being tested. The exit status of the command will be
531 changeset being tested. The exit status of the command will be
532 used to mark revisions as good or bad: status 0 means good, 125
532 used to mark revisions as good or bad: status 0 means good, 125
533 means to skip the revision, 127 (command not found) will abort the
533 means to skip the revision, 127 (command not found) will abort the
534 bisection, and any other non-zero exit status means the revision
534 bisection, and any other non-zero exit status means the revision
535 is bad.
535 is bad.
536
536
537 .. container:: verbose
537 .. container:: verbose
538
538
539 Some examples:
539 Some examples:
540
540
541 - start a bisection with known bad revision 12, and good revision 34::
541 - start a bisection with known bad revision 12, and good revision 34::
542
542
543 hg bisect --bad 34
543 hg bisect --bad 34
544 hg bisect --good 12
544 hg bisect --good 12
545
545
546 - advance the current bisection by marking current revision as good or
546 - advance the current bisection by marking current revision as good or
547 bad::
547 bad::
548
548
549 hg bisect --good
549 hg bisect --good
550 hg bisect --bad
550 hg bisect --bad
551
551
552 - mark the current revision, or a known revision, to be skipped (e.g. if
552 - mark the current revision, or a known revision, to be skipped (e.g. if
553 that revision is not usable because of another issue)::
553 that revision is not usable because of another issue)::
554
554
555 hg bisect --skip
555 hg bisect --skip
556 hg bisect --skip 23
556 hg bisect --skip 23
557
557
558 - skip all revisions that do not touch directories ``foo`` or ``bar``::
558 - skip all revisions that do not touch directories ``foo`` or ``bar``::
559
559
560 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
560 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
561
561
562 - forget the current bisection::
562 - forget the current bisection::
563
563
564 hg bisect --reset
564 hg bisect --reset
565
565
566 - use 'make && make tests' to automatically find the first broken
566 - use 'make && make tests' to automatically find the first broken
567 revision::
567 revision::
568
568
569 hg bisect --reset
569 hg bisect --reset
570 hg bisect --bad 34
570 hg bisect --bad 34
571 hg bisect --good 12
571 hg bisect --good 12
572 hg bisect --command "make && make tests"
572 hg bisect --command "make && make tests"
573
573
574 - see all changesets whose states are already known in the current
574 - see all changesets whose states are already known in the current
575 bisection::
575 bisection::
576
576
577 hg log -r "bisect(pruned)"
577 hg log -r "bisect(pruned)"
578
578
579 - see the changeset currently being bisected (especially useful
579 - see the changeset currently being bisected (especially useful
580 if running with -U/--noupdate)::
580 if running with -U/--noupdate)::
581
581
582 hg log -r "bisect(current)"
582 hg log -r "bisect(current)"
583
583
584 - see all changesets that took part in the current bisection::
584 - see all changesets that took part in the current bisection::
585
585
586 hg log -r "bisect(range)"
586 hg log -r "bisect(range)"
587
587
588 - with the graphlog extension, you can even get a nice graph::
588 - with the graphlog extension, you can even get a nice graph::
589
589
590 hg log --graph -r "bisect(range)"
590 hg log --graph -r "bisect(range)"
591
591
592 See :hg:`help revsets` for more about the `bisect()` keyword.
592 See :hg:`help revsets` for more about the `bisect()` keyword.
593
593
594 Returns 0 on success.
594 Returns 0 on success.
595 """
595 """
596 def extendbisectrange(nodes, good):
596 def extendbisectrange(nodes, good):
597 # bisect is incomplete when it ends on a merge node and
597 # bisect is incomplete when it ends on a merge node and
598 # one of the parent was not checked.
598 # one of the parent was not checked.
599 parents = repo[nodes[0]].parents()
599 parents = repo[nodes[0]].parents()
600 if len(parents) > 1:
600 if len(parents) > 1:
601 side = good and state['bad'] or state['good']
601 side = good and state['bad'] or state['good']
602 num = len(set(i.node() for i in parents) & set(side))
602 num = len(set(i.node() for i in parents) & set(side))
603 if num == 1:
603 if num == 1:
604 return parents[0].ancestor(parents[1])
604 return parents[0].ancestor(parents[1])
605 return None
605 return None
606
606
607 def print_result(nodes, good):
607 def print_result(nodes, good):
608 displayer = cmdutil.show_changeset(ui, repo, {})
608 displayer = cmdutil.show_changeset(ui, repo, {})
609 if len(nodes) == 1:
609 if len(nodes) == 1:
610 # narrowed it down to a single revision
610 # narrowed it down to a single revision
611 if good:
611 if good:
612 ui.write(_("The first good revision is:\n"))
612 ui.write(_("The first good revision is:\n"))
613 else:
613 else:
614 ui.write(_("The first bad revision is:\n"))
614 ui.write(_("The first bad revision is:\n"))
615 displayer.show(repo[nodes[0]])
615 displayer.show(repo[nodes[0]])
616 extendnode = extendbisectrange(nodes, good)
616 extendnode = extendbisectrange(nodes, good)
617 if extendnode is not None:
617 if extendnode is not None:
618 ui.write(_('Not all ancestors of this changeset have been'
618 ui.write(_('Not all ancestors of this changeset have been'
619 ' checked.\nUse bisect --extend to continue the '
619 ' checked.\nUse bisect --extend to continue the '
620 'bisection from\nthe common ancestor, %s.\n')
620 'bisection from\nthe common ancestor, %s.\n')
621 % extendnode)
621 % extendnode)
622 else:
622 else:
623 # multiple possible revisions
623 # multiple possible revisions
624 if good:
624 if good:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "good revision could be any of:\n"))
626 "good revision could be any of:\n"))
627 else:
627 else:
628 ui.write(_("Due to skipped revisions, the first "
628 ui.write(_("Due to skipped revisions, the first "
629 "bad revision could be any of:\n"))
629 "bad revision could be any of:\n"))
630 for n in nodes:
630 for n in nodes:
631 displayer.show(repo[n])
631 displayer.show(repo[n])
632 displayer.close()
632 displayer.close()
633
633
634 def check_state(state, interactive=True):
634 def check_state(state, interactive=True):
635 if not state['good'] or not state['bad']:
635 if not state['good'] or not state['bad']:
636 if (good or bad or skip or reset) and interactive:
636 if (good or bad or skip or reset) and interactive:
637 return
637 return
638 if not state['good']:
638 if not state['good']:
639 raise util.Abort(_('cannot bisect (no known good revisions)'))
639 raise util.Abort(_('cannot bisect (no known good revisions)'))
640 else:
640 else:
641 raise util.Abort(_('cannot bisect (no known bad revisions)'))
641 raise util.Abort(_('cannot bisect (no known bad revisions)'))
642 return True
642 return True
643
643
644 # backward compatibility
644 # backward compatibility
645 if rev in "good bad reset init".split():
645 if rev in "good bad reset init".split():
646 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
646 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
647 cmd, rev, extra = rev, extra, None
647 cmd, rev, extra = rev, extra, None
648 if cmd == "good":
648 if cmd == "good":
649 good = True
649 good = True
650 elif cmd == "bad":
650 elif cmd == "bad":
651 bad = True
651 bad = True
652 else:
652 else:
653 reset = True
653 reset = True
654 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
654 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
655 raise util.Abort(_('incompatible arguments'))
655 raise util.Abort(_('incompatible arguments'))
656
656
657 cmdutil.checkunfinished(repo)
657 cmdutil.checkunfinished(repo)
658
658
659 if reset:
659 if reset:
660 p = repo.join("bisect.state")
660 p = repo.join("bisect.state")
661 if os.path.exists(p):
661 if os.path.exists(p):
662 os.unlink(p)
662 os.unlink(p)
663 return
663 return
664
664
665 state = hbisect.load_state(repo)
665 state = hbisect.load_state(repo)
666
666
667 if command:
667 if command:
668 changesets = 1
668 changesets = 1
669 try:
669 try:
670 node = state['current'][0]
670 node = state['current'][0]
671 except LookupError:
671 except LookupError:
672 if noupdate:
672 if noupdate:
673 raise util.Abort(_('current bisect revision is unknown - '
673 raise util.Abort(_('current bisect revision is unknown - '
674 'start a new bisect to fix'))
674 'start a new bisect to fix'))
675 node, p2 = repo.dirstate.parents()
675 node, p2 = repo.dirstate.parents()
676 if p2 != nullid:
676 if p2 != nullid:
677 raise util.Abort(_('current bisect revision is a merge'))
677 raise util.Abort(_('current bisect revision is a merge'))
678 try:
678 try:
679 while changesets:
679 while changesets:
680 # update state
680 # update state
681 state['current'] = [node]
681 state['current'] = [node]
682 hbisect.save_state(repo, state)
682 hbisect.save_state(repo, state)
683 status = util.system(command,
683 status = util.system(command,
684 environ={'HG_NODE': hex(node)},
684 environ={'HG_NODE': hex(node)},
685 out=ui.fout)
685 out=ui.fout)
686 if status == 125:
686 if status == 125:
687 transition = "skip"
687 transition = "skip"
688 elif status == 0:
688 elif status == 0:
689 transition = "good"
689 transition = "good"
690 # status < 0 means process was killed
690 # status < 0 means process was killed
691 elif status == 127:
691 elif status == 127:
692 raise util.Abort(_("failed to execute %s") % command)
692 raise util.Abort(_("failed to execute %s") % command)
693 elif status < 0:
693 elif status < 0:
694 raise util.Abort(_("%s killed") % command)
694 raise util.Abort(_("%s killed") % command)
695 else:
695 else:
696 transition = "bad"
696 transition = "bad"
697 ctx = scmutil.revsingle(repo, rev, node)
697 ctx = scmutil.revsingle(repo, rev, node)
698 rev = None # clear for future iterations
698 rev = None # clear for future iterations
699 state[transition].append(ctx.node())
699 state[transition].append(ctx.node())
700 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
700 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
701 check_state(state, interactive=False)
701 check_state(state, interactive=False)
702 # bisect
702 # bisect
703 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
703 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
704 # update to next check
704 # update to next check
705 node = nodes[0]
705 node = nodes[0]
706 if not noupdate:
706 if not noupdate:
707 cmdutil.bailifchanged(repo)
707 cmdutil.bailifchanged(repo)
708 hg.clean(repo, node, show_stats=False)
708 hg.clean(repo, node, show_stats=False)
709 finally:
709 finally:
710 state['current'] = [node]
710 state['current'] = [node]
711 hbisect.save_state(repo, state)
711 hbisect.save_state(repo, state)
712 print_result(nodes, good)
712 print_result(nodes, good)
713 return
713 return
714
714
715 # update state
715 # update state
716
716
717 if rev:
717 if rev:
718 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
718 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
719 else:
719 else:
720 nodes = [repo.lookup('.')]
720 nodes = [repo.lookup('.')]
721
721
722 if good or bad or skip:
722 if good or bad or skip:
723 if good:
723 if good:
724 state['good'] += nodes
724 state['good'] += nodes
725 elif bad:
725 elif bad:
726 state['bad'] += nodes
726 state['bad'] += nodes
727 elif skip:
727 elif skip:
728 state['skip'] += nodes
728 state['skip'] += nodes
729 hbisect.save_state(repo, state)
729 hbisect.save_state(repo, state)
730
730
731 if not check_state(state):
731 if not check_state(state):
732 return
732 return
733
733
734 # actually bisect
734 # actually bisect
735 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
735 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
736 if extend:
736 if extend:
737 if not changesets:
737 if not changesets:
738 extendnode = extendbisectrange(nodes, good)
738 extendnode = extendbisectrange(nodes, good)
739 if extendnode is not None:
739 if extendnode is not None:
740 ui.write(_("Extending search to changeset %d:%s\n"
740 ui.write(_("Extending search to changeset %d:%s\n"
741 % (extendnode.rev(), extendnode)))
741 % (extendnode.rev(), extendnode)))
742 state['current'] = [extendnode.node()]
742 state['current'] = [extendnode.node()]
743 hbisect.save_state(repo, state)
743 hbisect.save_state(repo, state)
744 if noupdate:
744 if noupdate:
745 return
745 return
746 cmdutil.bailifchanged(repo)
746 cmdutil.bailifchanged(repo)
747 return hg.clean(repo, extendnode.node())
747 return hg.clean(repo, extendnode.node())
748 raise util.Abort(_("nothing to extend"))
748 raise util.Abort(_("nothing to extend"))
749
749
750 if changesets == 0:
750 if changesets == 0:
751 print_result(nodes, good)
751 print_result(nodes, good)
752 else:
752 else:
753 assert len(nodes) == 1 # only a single node can be tested next
753 assert len(nodes) == 1 # only a single node can be tested next
754 node = nodes[0]
754 node = nodes[0]
755 # compute the approximate number of remaining tests
755 # compute the approximate number of remaining tests
756 tests, size = 0, 2
756 tests, size = 0, 2
757 while size <= changesets:
757 while size <= changesets:
758 tests, size = tests + 1, size * 2
758 tests, size = tests + 1, size * 2
759 rev = repo.changelog.rev(node)
759 rev = repo.changelog.rev(node)
760 ui.write(_("Testing changeset %d:%s "
760 ui.write(_("Testing changeset %d:%s "
761 "(%d changesets remaining, ~%d tests)\n")
761 "(%d changesets remaining, ~%d tests)\n")
762 % (rev, short(node), changesets, tests))
762 % (rev, short(node), changesets, tests))
763 state['current'] = [node]
763 state['current'] = [node]
764 hbisect.save_state(repo, state)
764 hbisect.save_state(repo, state)
765 if not noupdate:
765 if not noupdate:
766 cmdutil.bailifchanged(repo)
766 cmdutil.bailifchanged(repo)
767 return hg.clean(repo, node)
767 return hg.clean(repo, node)
768
768
769 @command('bookmarks|bookmark',
769 @command('bookmarks|bookmark',
770 [('f', 'force', False, _('force')),
770 [('f', 'force', False, _('force')),
771 ('r', 'rev', '', _('revision'), _('REV')),
771 ('r', 'rev', '', _('revision'), _('REV')),
772 ('d', 'delete', False, _('delete a given bookmark')),
772 ('d', 'delete', False, _('delete a given bookmark')),
773 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
773 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
774 ('i', 'inactive', False, _('mark a bookmark inactive'))],
774 ('i', 'inactive', False, _('mark a bookmark inactive'))],
775 _('hg bookmarks [OPTIONS]... [NAME]...'))
775 _('hg bookmarks [OPTIONS]... [NAME]...'))
776 def bookmark(ui, repo, *names, **opts):
776 def bookmark(ui, repo, *names, **opts):
777 '''track a line of development with movable markers
777 '''track a line of development with movable markers
778
778
779 Bookmarks are pointers to certain commits that move when committing.
779 Bookmarks are pointers to certain commits that move when committing.
780 Bookmarks are local. They can be renamed, copied and deleted. It is
780 Bookmarks are local. They can be renamed, copied and deleted. It is
781 possible to use :hg:`merge NAME` to merge from a given bookmark, and
781 possible to use :hg:`merge NAME` to merge from a given bookmark, and
782 :hg:`update NAME` to update to a given bookmark.
782 :hg:`update NAME` to update to a given bookmark.
783
783
784 You can use :hg:`bookmark NAME` to set a bookmark on the working
784 You can use :hg:`bookmark NAME` to set a bookmark on the working
785 directory's parent revision with the given name. If you specify
785 directory's parent revision with the given name. If you specify
786 a revision using -r REV (where REV may be an existing bookmark),
786 a revision using -r REV (where REV may be an existing bookmark),
787 the bookmark is assigned to that revision.
787 the bookmark is assigned to that revision.
788
788
789 Bookmarks can be pushed and pulled between repositories (see :hg:`help
789 Bookmarks can be pushed and pulled between repositories (see :hg:`help
790 push` and :hg:`help pull`). This requires both the local and remote
790 push` and :hg:`help pull`). This requires both the local and remote
791 repositories to support bookmarks. For versions prior to 1.8, this means
791 repositories to support bookmarks. For versions prior to 1.8, this means
792 the bookmarks extension must be enabled.
792 the bookmarks extension must be enabled.
793
793
794 If you set a bookmark called '@', new clones of the repository will
794 If you set a bookmark called '@', new clones of the repository will
795 have that revision checked out (and the bookmark made active) by
795 have that revision checked out (and the bookmark made active) by
796 default.
796 default.
797
797
798 With -i/--inactive, the new bookmark will not be made the active
798 With -i/--inactive, the new bookmark will not be made the active
799 bookmark. If -r/--rev is given, the new bookmark will not be made
799 bookmark. If -r/--rev is given, the new bookmark will not be made
800 active even if -i/--inactive is not given. If no NAME is given, the
800 active even if -i/--inactive is not given. If no NAME is given, the
801 current active bookmark will be marked inactive.
801 current active bookmark will be marked inactive.
802 '''
802 '''
803 force = opts.get('force')
803 force = opts.get('force')
804 rev = opts.get('rev')
804 rev = opts.get('rev')
805 delete = opts.get('delete')
805 delete = opts.get('delete')
806 rename = opts.get('rename')
806 rename = opts.get('rename')
807 inactive = opts.get('inactive')
807 inactive = opts.get('inactive')
808
808
809 hexfn = ui.debugflag and hex or short
809 hexfn = ui.debugflag and hex or short
810 marks = repo._bookmarks
810 marks = repo._bookmarks
811 cur = repo.changectx('.').node()
811 cur = repo.changectx('.').node()
812
812
813 def checkformat(mark):
813 def checkformat(mark):
814 mark = mark.strip()
814 mark = mark.strip()
815 if not mark:
815 if not mark:
816 raise util.Abort(_("bookmark names cannot consist entirely of "
816 raise util.Abort(_("bookmark names cannot consist entirely of "
817 "whitespace"))
817 "whitespace"))
818 scmutil.checknewlabel(repo, mark, 'bookmark')
818 scmutil.checknewlabel(repo, mark, 'bookmark')
819 return mark
819 return mark
820
820
821 def checkconflict(repo, mark, force=False, target=None):
821 def checkconflict(repo, mark, force=False, target=None):
822 if mark in marks and not force:
822 if mark in marks and not force:
823 if target:
823 if target:
824 if marks[mark] == target and target == cur:
824 if marks[mark] == target and target == cur:
825 # re-activating a bookmark
825 # re-activating a bookmark
826 return
826 return
827 anc = repo.changelog.ancestors([repo[target].rev()])
827 anc = repo.changelog.ancestors([repo[target].rev()])
828 bmctx = repo[marks[mark]]
828 bmctx = repo[marks[mark]]
829 divs = [repo[b].node() for b in marks
829 divs = [repo[b].node() for b in marks
830 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
830 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
831
831
832 # allow resolving a single divergent bookmark even if moving
832 # allow resolving a single divergent bookmark even if moving
833 # the bookmark across branches when a revision is specified
833 # the bookmark across branches when a revision is specified
834 # that contains a divergent bookmark
834 # that contains a divergent bookmark
835 if bmctx.rev() not in anc and target in divs:
835 if bmctx.rev() not in anc and target in divs:
836 bookmarks.deletedivergent(repo, [target], mark)
836 bookmarks.deletedivergent(repo, [target], mark)
837 return
837 return
838
838
839 deletefrom = [b for b in divs
839 deletefrom = [b for b in divs
840 if repo[b].rev() in anc or b == target]
840 if repo[b].rev() in anc or b == target]
841 bookmarks.deletedivergent(repo, deletefrom, mark)
841 bookmarks.deletedivergent(repo, deletefrom, mark)
842 if bmctx.rev() in anc:
842 if bmctx.rev() in anc:
843 ui.status(_("moving bookmark '%s' forward from %s\n") %
843 ui.status(_("moving bookmark '%s' forward from %s\n") %
844 (mark, short(bmctx.node())))
844 (mark, short(bmctx.node())))
845 return
845 return
846 raise util.Abort(_("bookmark '%s' already exists "
846 raise util.Abort(_("bookmark '%s' already exists "
847 "(use -f to force)") % mark)
847 "(use -f to force)") % mark)
848 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
848 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
849 and not force):
849 and not force):
850 raise util.Abort(
850 raise util.Abort(
851 _("a bookmark cannot have the name of an existing branch"))
851 _("a bookmark cannot have the name of an existing branch"))
852
852
853 if delete and rename:
853 if delete and rename:
854 raise util.Abort(_("--delete and --rename are incompatible"))
854 raise util.Abort(_("--delete and --rename are incompatible"))
855 if delete and rev:
855 if delete and rev:
856 raise util.Abort(_("--rev is incompatible with --delete"))
856 raise util.Abort(_("--rev is incompatible with --delete"))
857 if rename and rev:
857 if rename and rev:
858 raise util.Abort(_("--rev is incompatible with --rename"))
858 raise util.Abort(_("--rev is incompatible with --rename"))
859 if not names and (delete or rev):
859 if not names and (delete or rev):
860 raise util.Abort(_("bookmark name required"))
860 raise util.Abort(_("bookmark name required"))
861
861
862 if delete:
862 if delete:
863 for mark in names:
863 for mark in names:
864 if mark not in marks:
864 if mark not in marks:
865 raise util.Abort(_("bookmark '%s' does not exist") % mark)
865 raise util.Abort(_("bookmark '%s' does not exist") % mark)
866 if mark == repo._bookmarkcurrent:
866 if mark == repo._bookmarkcurrent:
867 bookmarks.setcurrent(repo, None)
867 bookmarks.setcurrent(repo, None)
868 del marks[mark]
868 del marks[mark]
869 marks.write()
869 marks.write()
870
870
871 elif rename:
871 elif rename:
872 if not names:
872 if not names:
873 raise util.Abort(_("new bookmark name required"))
873 raise util.Abort(_("new bookmark name required"))
874 elif len(names) > 1:
874 elif len(names) > 1:
875 raise util.Abort(_("only one new bookmark name allowed"))
875 raise util.Abort(_("only one new bookmark name allowed"))
876 mark = checkformat(names[0])
876 mark = checkformat(names[0])
877 if rename not in marks:
877 if rename not in marks:
878 raise util.Abort(_("bookmark '%s' does not exist") % rename)
878 raise util.Abort(_("bookmark '%s' does not exist") % rename)
879 checkconflict(repo, mark, force)
879 checkconflict(repo, mark, force)
880 marks[mark] = marks[rename]
880 marks[mark] = marks[rename]
881 if repo._bookmarkcurrent == rename and not inactive:
881 if repo._bookmarkcurrent == rename and not inactive:
882 bookmarks.setcurrent(repo, mark)
882 bookmarks.setcurrent(repo, mark)
883 del marks[rename]
883 del marks[rename]
884 marks.write()
884 marks.write()
885
885
886 elif names:
886 elif names:
887 newact = None
887 newact = None
888 for mark in names:
888 for mark in names:
889 mark = checkformat(mark)
889 mark = checkformat(mark)
890 if newact is None:
890 if newact is None:
891 newact = mark
891 newact = mark
892 if inactive and mark == repo._bookmarkcurrent:
892 if inactive and mark == repo._bookmarkcurrent:
893 bookmarks.setcurrent(repo, None)
893 bookmarks.setcurrent(repo, None)
894 return
894 return
895 tgt = cur
895 tgt = cur
896 if rev:
896 if rev:
897 tgt = scmutil.revsingle(repo, rev).node()
897 tgt = scmutil.revsingle(repo, rev).node()
898 checkconflict(repo, mark, force, tgt)
898 checkconflict(repo, mark, force, tgt)
899 marks[mark] = tgt
899 marks[mark] = tgt
900 if not inactive and cur == marks[newact] and not rev:
900 if not inactive and cur == marks[newact] and not rev:
901 bookmarks.setcurrent(repo, newact)
901 bookmarks.setcurrent(repo, newact)
902 elif cur != tgt and newact == repo._bookmarkcurrent:
902 elif cur != tgt and newact == repo._bookmarkcurrent:
903 bookmarks.setcurrent(repo, None)
903 bookmarks.setcurrent(repo, None)
904 marks.write()
904 marks.write()
905
905
906 # Same message whether trying to deactivate the current bookmark (-i
906 # Same message whether trying to deactivate the current bookmark (-i
907 # with no NAME) or listing bookmarks
907 # with no NAME) or listing bookmarks
908 elif len(marks) == 0:
908 elif len(marks) == 0:
909 ui.status(_("no bookmarks set\n"))
909 ui.status(_("no bookmarks set\n"))
910
910
911 elif inactive:
911 elif inactive:
912 if not repo._bookmarkcurrent:
912 if not repo._bookmarkcurrent:
913 ui.status(_("no active bookmark\n"))
913 ui.status(_("no active bookmark\n"))
914 else:
914 else:
915 bookmarks.setcurrent(repo, None)
915 bookmarks.setcurrent(repo, None)
916
916
917 else: # show bookmarks
917 else: # show bookmarks
918 for bmark, n in sorted(marks.iteritems()):
918 for bmark, n in sorted(marks.iteritems()):
919 current = repo._bookmarkcurrent
919 current = repo._bookmarkcurrent
920 if bmark == current:
920 if bmark == current:
921 prefix, label = '*', 'bookmarks.current'
921 prefix, label = '*', 'bookmarks.current'
922 else:
922 else:
923 prefix, label = ' ', ''
923 prefix, label = ' ', ''
924
924
925 if ui.quiet:
925 if ui.quiet:
926 ui.write("%s\n" % bmark, label=label)
926 ui.write("%s\n" % bmark, label=label)
927 else:
927 else:
928 ui.write(" %s %-25s %d:%s\n" % (
928 ui.write(" %s %-25s %d:%s\n" % (
929 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
929 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
930 label=label)
930 label=label)
931
931
932 @command('branch',
932 @command('branch',
933 [('f', 'force', None,
933 [('f', 'force', None,
934 _('set branch name even if it shadows an existing branch')),
934 _('set branch name even if it shadows an existing branch')),
935 ('C', 'clean', None, _('reset branch name to parent branch name'))],
935 ('C', 'clean', None, _('reset branch name to parent branch name'))],
936 _('[-fC] [NAME]'))
936 _('[-fC] [NAME]'))
937 def branch(ui, repo, label=None, **opts):
937 def branch(ui, repo, label=None, **opts):
938 """set or show the current branch name
938 """set or show the current branch name
939
939
940 .. note::
940 .. note::
941
941
942 Branch names are permanent and global. Use :hg:`bookmark` to create a
942 Branch names are permanent and global. Use :hg:`bookmark` to create a
943 light-weight bookmark instead. See :hg:`help glossary` for more
943 light-weight bookmark instead. See :hg:`help glossary` for more
944 information about named branches and bookmarks.
944 information about named branches and bookmarks.
945
945
946 With no argument, show the current branch name. With one argument,
946 With no argument, show the current branch name. With one argument,
947 set the working directory branch name (the branch will not exist
947 set the working directory branch name (the branch will not exist
948 in the repository until the next commit). Standard practice
948 in the repository until the next commit). Standard practice
949 recommends that primary development take place on the 'default'
949 recommends that primary development take place on the 'default'
950 branch.
950 branch.
951
951
952 Unless -f/--force is specified, branch will not let you set a
952 Unless -f/--force is specified, branch will not let you set a
953 branch name that already exists, even if it's inactive.
953 branch name that already exists, even if it's inactive.
954
954
955 Use -C/--clean to reset the working directory branch to that of
955 Use -C/--clean to reset the working directory branch to that of
956 the parent of the working directory, negating a previous branch
956 the parent of the working directory, negating a previous branch
957 change.
957 change.
958
958
959 Use the command :hg:`update` to switch to an existing branch. Use
959 Use the command :hg:`update` to switch to an existing branch. Use
960 :hg:`commit --close-branch` to mark this branch as closed.
960 :hg:`commit --close-branch` to mark this branch as closed.
961
961
962 Returns 0 on success.
962 Returns 0 on success.
963 """
963 """
964 if label:
964 if label:
965 label = label.strip()
965 label = label.strip()
966
966
967 if not opts.get('clean') and not label:
967 if not opts.get('clean') and not label:
968 ui.write("%s\n" % repo.dirstate.branch())
968 ui.write("%s\n" % repo.dirstate.branch())
969 return
969 return
970
970
971 wlock = repo.wlock()
971 wlock = repo.wlock()
972 try:
972 try:
973 if opts.get('clean'):
973 if opts.get('clean'):
974 label = repo[None].p1().branch()
974 label = repo[None].p1().branch()
975 repo.dirstate.setbranch(label)
975 repo.dirstate.setbranch(label)
976 ui.status(_('reset working directory to branch %s\n') % label)
976 ui.status(_('reset working directory to branch %s\n') % label)
977 elif label:
977 elif label:
978 if not opts.get('force') and label in repo.branchmap():
978 if not opts.get('force') and label in repo.branchmap():
979 if label not in [p.branch() for p in repo.parents()]:
979 if label not in [p.branch() for p in repo.parents()]:
980 raise util.Abort(_('a branch of the same name already'
980 raise util.Abort(_('a branch of the same name already'
981 ' exists'),
981 ' exists'),
982 # i18n: "it" refers to an existing branch
982 # i18n: "it" refers to an existing branch
983 hint=_("use 'hg update' to switch to it"))
983 hint=_("use 'hg update' to switch to it"))
984 scmutil.checknewlabel(repo, label, 'branch')
984 scmutil.checknewlabel(repo, label, 'branch')
985 repo.dirstate.setbranch(label)
985 repo.dirstate.setbranch(label)
986 ui.status(_('marked working directory as branch %s\n') % label)
986 ui.status(_('marked working directory as branch %s\n') % label)
987 ui.status(_('(branches are permanent and global, '
987 ui.status(_('(branches are permanent and global, '
988 'did you want a bookmark?)\n'))
988 'did you want a bookmark?)\n'))
989 finally:
989 finally:
990 wlock.release()
990 wlock.release()
991
991
992 @command('branches',
992 @command('branches',
993 [('a', 'active', False, _('show only branches that have unmerged heads')),
993 [('a', 'active', False, _('show only branches that have unmerged heads')),
994 ('c', 'closed', False, _('show normal and closed branches'))],
994 ('c', 'closed', False, _('show normal and closed branches'))],
995 _('[-ac]'))
995 _('[-ac]'))
996 def branches(ui, repo, active=False, closed=False):
996 def branches(ui, repo, active=False, closed=False):
997 """list repository named branches
997 """list repository named branches
998
998
999 List the repository's named branches, indicating which ones are
999 List the repository's named branches, indicating which ones are
1000 inactive. If -c/--closed is specified, also list branches which have
1000 inactive. If -c/--closed is specified, also list branches which have
1001 been marked closed (see :hg:`commit --close-branch`).
1001 been marked closed (see :hg:`commit --close-branch`).
1002
1002
1003 If -a/--active is specified, only show active branches. A branch
1003 If -a/--active is specified, only show active branches. A branch
1004 is considered active if it contains repository heads.
1004 is considered active if it contains repository heads.
1005
1005
1006 Use the command :hg:`update` to switch to an existing branch.
1006 Use the command :hg:`update` to switch to an existing branch.
1007
1007
1008 Returns 0.
1008 Returns 0.
1009 """
1009 """
1010
1010
1011 hexfunc = ui.debugflag and hex or short
1011 hexfunc = ui.debugflag and hex or short
1012
1012
1013 activebranches = set([repo[n].branch() for n in repo.heads()])
1013 activebranches = set([repo[n].branch() for n in repo.heads()])
1014 branches = []
1014 branches = []
1015 for tag, heads in repo.branchmap().iteritems():
1015 for tag, heads in repo.branchmap().iteritems():
1016 for h in reversed(heads):
1016 for h in reversed(heads):
1017 ctx = repo[h]
1017 ctx = repo[h]
1018 isopen = not ctx.closesbranch()
1018 isopen = not ctx.closesbranch()
1019 if isopen:
1019 if isopen:
1020 tip = ctx
1020 tip = ctx
1021 break
1021 break
1022 else:
1022 else:
1023 tip = repo[heads[-1]]
1023 tip = repo[heads[-1]]
1024 isactive = tag in activebranches and isopen
1024 isactive = tag in activebranches and isopen
1025 branches.append((tip, isactive, isopen))
1025 branches.append((tip, isactive, isopen))
1026 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1026 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1027 reverse=True)
1027 reverse=True)
1028
1028
1029 for ctx, isactive, isopen in branches:
1029 for ctx, isactive, isopen in branches:
1030 if (not active) or isactive:
1030 if (not active) or isactive:
1031 if isactive:
1031 if isactive:
1032 label = 'branches.active'
1032 label = 'branches.active'
1033 notice = ''
1033 notice = ''
1034 elif not isopen:
1034 elif not isopen:
1035 if not closed:
1035 if not closed:
1036 continue
1036 continue
1037 label = 'branches.closed'
1037 label = 'branches.closed'
1038 notice = _(' (closed)')
1038 notice = _(' (closed)')
1039 else:
1039 else:
1040 label = 'branches.inactive'
1040 label = 'branches.inactive'
1041 notice = _(' (inactive)')
1041 notice = _(' (inactive)')
1042 if ctx.branch() == repo.dirstate.branch():
1042 if ctx.branch() == repo.dirstate.branch():
1043 label = 'branches.current'
1043 label = 'branches.current'
1044 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1044 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1045 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1045 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1046 'log.changeset changeset.%s' % ctx.phasestr())
1046 'log.changeset changeset.%s' % ctx.phasestr())
1047 tag = ui.label(ctx.branch(), label)
1047 tag = ui.label(ctx.branch(), label)
1048 if ui.quiet:
1048 if ui.quiet:
1049 ui.write("%s\n" % tag)
1049 ui.write("%s\n" % tag)
1050 else:
1050 else:
1051 ui.write("%s %s%s\n" % (tag, rev, notice))
1051 ui.write("%s %s%s\n" % (tag, rev, notice))
1052
1052
1053 @command('bundle',
1053 @command('bundle',
1054 [('f', 'force', None, _('run even when the destination is unrelated')),
1054 [('f', 'force', None, _('run even when the destination is unrelated')),
1055 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1055 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1056 _('REV')),
1056 _('REV')),
1057 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1057 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1058 _('BRANCH')),
1058 _('BRANCH')),
1059 ('', 'base', [],
1059 ('', 'base', [],
1060 _('a base changeset assumed to be available at the destination'),
1060 _('a base changeset assumed to be available at the destination'),
1061 _('REV')),
1061 _('REV')),
1062 ('a', 'all', None, _('bundle all changesets in the repository')),
1062 ('a', 'all', None, _('bundle all changesets in the repository')),
1063 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1063 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1064 ] + remoteopts,
1064 ] + remoteopts,
1065 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1065 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1066 def bundle(ui, repo, fname, dest=None, **opts):
1066 def bundle(ui, repo, fname, dest=None, **opts):
1067 """create a changegroup file
1067 """create a changegroup file
1068
1068
1069 Generate a compressed changegroup file collecting changesets not
1069 Generate a compressed changegroup file collecting changesets not
1070 known to be in another repository.
1070 known to be in another repository.
1071
1071
1072 If you omit the destination repository, then hg assumes the
1072 If you omit the destination repository, then hg assumes the
1073 destination will have all the nodes you specify with --base
1073 destination will have all the nodes you specify with --base
1074 parameters. To create a bundle containing all changesets, use
1074 parameters. To create a bundle containing all changesets, use
1075 -a/--all (or --base null).
1075 -a/--all (or --base null).
1076
1076
1077 You can change compression method with the -t/--type option.
1077 You can change compression method with the -t/--type option.
1078 The available compression methods are: none, bzip2, and
1078 The available compression methods are: none, bzip2, and
1079 gzip (by default, bundles are compressed using bzip2).
1079 gzip (by default, bundles are compressed using bzip2).
1080
1080
1081 The bundle file can then be transferred using conventional means
1081 The bundle file can then be transferred using conventional means
1082 and applied to another repository with the unbundle or pull
1082 and applied to another repository with the unbundle or pull
1083 command. This is useful when direct push and pull are not
1083 command. This is useful when direct push and pull are not
1084 available or when exporting an entire repository is undesirable.
1084 available or when exporting an entire repository is undesirable.
1085
1085
1086 Applying bundles preserves all changeset contents including
1086 Applying bundles preserves all changeset contents including
1087 permissions, copy/rename information, and revision history.
1087 permissions, copy/rename information, and revision history.
1088
1088
1089 Returns 0 on success, 1 if no changes found.
1089 Returns 0 on success, 1 if no changes found.
1090 """
1090 """
1091 revs = None
1091 revs = None
1092 if 'rev' in opts:
1092 if 'rev' in opts:
1093 revs = scmutil.revrange(repo, opts['rev'])
1093 revs = scmutil.revrange(repo, opts['rev'])
1094
1094
1095 bundletype = opts.get('type', 'bzip2').lower()
1095 bundletype = opts.get('type', 'bzip2').lower()
1096 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1096 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1097 bundletype = btypes.get(bundletype)
1097 bundletype = btypes.get(bundletype)
1098 if bundletype not in changegroup.bundletypes:
1098 if bundletype not in changegroup.bundletypes:
1099 raise util.Abort(_('unknown bundle type specified with --type'))
1099 raise util.Abort(_('unknown bundle type specified with --type'))
1100
1100
1101 if opts.get('all'):
1101 if opts.get('all'):
1102 base = ['null']
1102 base = ['null']
1103 else:
1103 else:
1104 base = scmutil.revrange(repo, opts.get('base'))
1104 base = scmutil.revrange(repo, opts.get('base'))
1105 # TODO: get desired bundlecaps from command line.
1105 # TODO: get desired bundlecaps from command line.
1106 bundlecaps = None
1106 bundlecaps = None
1107 if base:
1107 if base:
1108 if dest:
1108 if dest:
1109 raise util.Abort(_("--base is incompatible with specifying "
1109 raise util.Abort(_("--base is incompatible with specifying "
1110 "a destination"))
1110 "a destination"))
1111 common = [repo.lookup(rev) for rev in base]
1111 common = [repo.lookup(rev) for rev in base]
1112 heads = revs and map(repo.lookup, revs) or revs
1112 heads = revs and map(repo.lookup, revs) or revs
1113 cg = repo.getbundle('bundle', heads=heads, common=common,
1113 cg = repo.getbundle('bundle', heads=heads, common=common,
1114 bundlecaps=bundlecaps)
1114 bundlecaps=bundlecaps)
1115 outgoing = None
1115 outgoing = None
1116 else:
1116 else:
1117 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1117 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1118 dest, branches = hg.parseurl(dest, opts.get('branch'))
1118 dest, branches = hg.parseurl(dest, opts.get('branch'))
1119 other = hg.peer(repo, opts, dest)
1119 other = hg.peer(repo, opts, dest)
1120 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1120 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1121 heads = revs and map(repo.lookup, revs) or revs
1121 heads = revs and map(repo.lookup, revs) or revs
1122 outgoing = discovery.findcommonoutgoing(repo, other,
1122 outgoing = discovery.findcommonoutgoing(repo, other,
1123 onlyheads=heads,
1123 onlyheads=heads,
1124 force=opts.get('force'),
1124 force=opts.get('force'),
1125 portable=True)
1125 portable=True)
1126 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1126 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1127 if not cg:
1127 if not cg:
1128 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1128 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1129 return 1
1129 return 1
1130
1130
1131 changegroup.writebundle(cg, fname, bundletype)
1131 changegroup.writebundle(cg, fname, bundletype)
1132
1132
1133 @command('cat',
1133 @command('cat',
1134 [('o', 'output', '',
1134 [('o', 'output', '',
1135 _('print output to file with formatted name'), _('FORMAT')),
1135 _('print output to file with formatted name'), _('FORMAT')),
1136 ('r', 'rev', '', _('print the given revision'), _('REV')),
1136 ('r', 'rev', '', _('print the given revision'), _('REV')),
1137 ('', 'decode', None, _('apply any matching decode filter')),
1137 ('', 'decode', None, _('apply any matching decode filter')),
1138 ] + walkopts,
1138 ] + walkopts,
1139 _('[OPTION]... FILE...'))
1139 _('[OPTION]... FILE...'))
1140 def cat(ui, repo, file1, *pats, **opts):
1140 def cat(ui, repo, file1, *pats, **opts):
1141 """output the current or given revision of files
1141 """output the current or given revision of files
1142
1142
1143 Print the specified files as they were at the given revision. If
1143 Print the specified files as they were at the given revision. If
1144 no revision is given, the parent of the working directory is used.
1144 no revision is given, the parent of the working directory is used.
1145
1145
1146 Output may be to a file, in which case the name of the file is
1146 Output may be to a file, in which case the name of the file is
1147 given using a format string. The formatting rules are the same as
1147 given using a format string. The formatting rules are the same as
1148 for the export command, with the following additions:
1148 for the export command, with the following additions:
1149
1149
1150 :``%s``: basename of file being printed
1150 :``%s``: basename of file being printed
1151 :``%d``: dirname of file being printed, or '.' if in repository root
1151 :``%d``: dirname of file being printed, or '.' if in repository root
1152 :``%p``: root-relative path name of file being printed
1152 :``%p``: root-relative path name of file being printed
1153
1153
1154 Returns 0 on success.
1154 Returns 0 on success.
1155 """
1155 """
1156 ctx = scmutil.revsingle(repo, opts.get('rev'))
1156 ctx = scmutil.revsingle(repo, opts.get('rev'))
1157 err = 1
1157 err = 1
1158 m = scmutil.match(ctx, (file1,) + pats, opts)
1158 m = scmutil.match(ctx, (file1,) + pats, opts)
1159 for abs in ctx.walk(m):
1159 for abs in ctx.walk(m):
1160 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1160 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1161 pathname=abs)
1161 pathname=abs)
1162 data = ctx[abs].data()
1162 data = ctx[abs].data()
1163 if opts.get('decode'):
1163 if opts.get('decode'):
1164 data = repo.wwritedata(abs, data)
1164 data = repo.wwritedata(abs, data)
1165 fp.write(data)
1165 fp.write(data)
1166 fp.close()
1166 fp.close()
1167 err = 0
1167 err = 0
1168 return err
1168 return err
1169
1169
1170 @command('^clone',
1170 @command('^clone',
1171 [('U', 'noupdate', None,
1171 [('U', 'noupdate', None,
1172 _('the clone will include an empty working copy (only a repository)')),
1172 _('the clone will include an empty working copy (only a repository)')),
1173 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1173 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1174 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1174 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1175 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1175 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1176 ('', 'pull', None, _('use pull protocol to copy metadata')),
1176 ('', 'pull', None, _('use pull protocol to copy metadata')),
1177 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1177 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1178 ] + remoteopts,
1178 ] + remoteopts,
1179 _('[OPTION]... SOURCE [DEST]'))
1179 _('[OPTION]... SOURCE [DEST]'))
1180 def clone(ui, source, dest=None, **opts):
1180 def clone(ui, source, dest=None, **opts):
1181 """make a copy of an existing repository
1181 """make a copy of an existing repository
1182
1182
1183 Create a copy of an existing repository in a new directory.
1183 Create a copy of an existing repository in a new directory.
1184
1184
1185 If no destination directory name is specified, it defaults to the
1185 If no destination directory name is specified, it defaults to the
1186 basename of the source.
1186 basename of the source.
1187
1187
1188 The location of the source is added to the new repository's
1188 The location of the source is added to the new repository's
1189 ``.hg/hgrc`` file, as the default to be used for future pulls.
1189 ``.hg/hgrc`` file, as the default to be used for future pulls.
1190
1190
1191 Only local paths and ``ssh://`` URLs are supported as
1191 Only local paths and ``ssh://`` URLs are supported as
1192 destinations. For ``ssh://`` destinations, no working directory or
1192 destinations. For ``ssh://`` destinations, no working directory or
1193 ``.hg/hgrc`` will be created on the remote side.
1193 ``.hg/hgrc`` will be created on the remote side.
1194
1194
1195 To pull only a subset of changesets, specify one or more revisions
1195 To pull only a subset of changesets, specify one or more revisions
1196 identifiers with -r/--rev or branches with -b/--branch. The
1196 identifiers with -r/--rev or branches with -b/--branch. The
1197 resulting clone will contain only the specified changesets and
1197 resulting clone will contain only the specified changesets and
1198 their ancestors. These options (or 'clone src#rev dest') imply
1198 their ancestors. These options (or 'clone src#rev dest') imply
1199 --pull, even for local source repositories. Note that specifying a
1199 --pull, even for local source repositories. Note that specifying a
1200 tag will include the tagged changeset but not the changeset
1200 tag will include the tagged changeset but not the changeset
1201 containing the tag.
1201 containing the tag.
1202
1202
1203 If the source repository has a bookmark called '@' set, that
1203 If the source repository has a bookmark called '@' set, that
1204 revision will be checked out in the new repository by default.
1204 revision will be checked out in the new repository by default.
1205
1205
1206 To check out a particular version, use -u/--update, or
1206 To check out a particular version, use -u/--update, or
1207 -U/--noupdate to create a clone with no working directory.
1207 -U/--noupdate to create a clone with no working directory.
1208
1208
1209 .. container:: verbose
1209 .. container:: verbose
1210
1210
1211 For efficiency, hardlinks are used for cloning whenever the
1211 For efficiency, hardlinks are used for cloning whenever the
1212 source and destination are on the same filesystem (note this
1212 source and destination are on the same filesystem (note this
1213 applies only to the repository data, not to the working
1213 applies only to the repository data, not to the working
1214 directory). Some filesystems, such as AFS, implement hardlinking
1214 directory). Some filesystems, such as AFS, implement hardlinking
1215 incorrectly, but do not report errors. In these cases, use the
1215 incorrectly, but do not report errors. In these cases, use the
1216 --pull option to avoid hardlinking.
1216 --pull option to avoid hardlinking.
1217
1217
1218 In some cases, you can clone repositories and the working
1218 In some cases, you can clone repositories and the working
1219 directory using full hardlinks with ::
1219 directory using full hardlinks with ::
1220
1220
1221 $ cp -al REPO REPOCLONE
1221 $ cp -al REPO REPOCLONE
1222
1222
1223 This is the fastest way to clone, but it is not always safe. The
1223 This is the fastest way to clone, but it is not always safe. The
1224 operation is not atomic (making sure REPO is not modified during
1224 operation is not atomic (making sure REPO is not modified during
1225 the operation is up to you) and you have to make sure your
1225 the operation is up to you) and you have to make sure your
1226 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1226 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1227 so). Also, this is not compatible with certain extensions that
1227 so). Also, this is not compatible with certain extensions that
1228 place their metadata under the .hg directory, such as mq.
1228 place their metadata under the .hg directory, such as mq.
1229
1229
1230 Mercurial will update the working directory to the first applicable
1230 Mercurial will update the working directory to the first applicable
1231 revision from this list:
1231 revision from this list:
1232
1232
1233 a) null if -U or the source repository has no changesets
1233 a) null if -U or the source repository has no changesets
1234 b) if -u . and the source repository is local, the first parent of
1234 b) if -u . and the source repository is local, the first parent of
1235 the source repository's working directory
1235 the source repository's working directory
1236 c) the changeset specified with -u (if a branch name, this means the
1236 c) the changeset specified with -u (if a branch name, this means the
1237 latest head of that branch)
1237 latest head of that branch)
1238 d) the changeset specified with -r
1238 d) the changeset specified with -r
1239 e) the tipmost head specified with -b
1239 e) the tipmost head specified with -b
1240 f) the tipmost head specified with the url#branch source syntax
1240 f) the tipmost head specified with the url#branch source syntax
1241 g) the revision marked with the '@' bookmark, if present
1241 g) the revision marked with the '@' bookmark, if present
1242 h) the tipmost head of the default branch
1242 h) the tipmost head of the default branch
1243 i) tip
1243 i) tip
1244
1244
1245 Examples:
1245 Examples:
1246
1246
1247 - clone a remote repository to a new directory named hg/::
1247 - clone a remote repository to a new directory named hg/::
1248
1248
1249 hg clone http://selenic.com/hg
1249 hg clone http://selenic.com/hg
1250
1250
1251 - create a lightweight local clone::
1251 - create a lightweight local clone::
1252
1252
1253 hg clone project/ project-feature/
1253 hg clone project/ project-feature/
1254
1254
1255 - clone from an absolute path on an ssh server (note double-slash)::
1255 - clone from an absolute path on an ssh server (note double-slash)::
1256
1256
1257 hg clone ssh://user@server//home/projects/alpha/
1257 hg clone ssh://user@server//home/projects/alpha/
1258
1258
1259 - do a high-speed clone over a LAN while checking out a
1259 - do a high-speed clone over a LAN while checking out a
1260 specified version::
1260 specified version::
1261
1261
1262 hg clone --uncompressed http://server/repo -u 1.5
1262 hg clone --uncompressed http://server/repo -u 1.5
1263
1263
1264 - create a repository without changesets after a particular revision::
1264 - create a repository without changesets after a particular revision::
1265
1265
1266 hg clone -r 04e544 experimental/ good/
1266 hg clone -r 04e544 experimental/ good/
1267
1267
1268 - clone (and track) a particular named branch::
1268 - clone (and track) a particular named branch::
1269
1269
1270 hg clone http://selenic.com/hg#stable
1270 hg clone http://selenic.com/hg#stable
1271
1271
1272 See :hg:`help urls` for details on specifying URLs.
1272 See :hg:`help urls` for details on specifying URLs.
1273
1273
1274 Returns 0 on success.
1274 Returns 0 on success.
1275 """
1275 """
1276 if opts.get('noupdate') and opts.get('updaterev'):
1276 if opts.get('noupdate') and opts.get('updaterev'):
1277 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1277 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1278
1278
1279 r = hg.clone(ui, opts, source, dest,
1279 r = hg.clone(ui, opts, source, dest,
1280 pull=opts.get('pull'),
1280 pull=opts.get('pull'),
1281 stream=opts.get('uncompressed'),
1281 stream=opts.get('uncompressed'),
1282 rev=opts.get('rev'),
1282 rev=opts.get('rev'),
1283 update=opts.get('updaterev') or not opts.get('noupdate'),
1283 update=opts.get('updaterev') or not opts.get('noupdate'),
1284 branch=opts.get('branch'))
1284 branch=opts.get('branch'))
1285
1285
1286 return r is None
1286 return r is None
1287
1287
1288 @command('^commit|ci',
1288 @command('^commit|ci',
1289 [('A', 'addremove', None,
1289 [('A', 'addremove', None,
1290 _('mark new/missing files as added/removed before committing')),
1290 _('mark new/missing files as added/removed before committing')),
1291 ('', 'close-branch', None,
1291 ('', 'close-branch', None,
1292 _('mark a branch as closed, hiding it from the branch list')),
1292 _('mark a branch as closed, hiding it from the branch list')),
1293 ('', 'amend', None, _('amend the parent of the working dir')),
1293 ('', 'amend', None, _('amend the parent of the working dir')),
1294 ('s', 'secret', None, _('use the secret phase for committing')),
1294 ('s', 'secret', None, _('use the secret phase for committing')),
1295 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1295 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1296 _('[OPTION]... [FILE]...'))
1296 _('[OPTION]... [FILE]...'))
1297 def commit(ui, repo, *pats, **opts):
1297 def commit(ui, repo, *pats, **opts):
1298 """commit the specified files or all outstanding changes
1298 """commit the specified files or all outstanding changes
1299
1299
1300 Commit changes to the given files into the repository. Unlike a
1300 Commit changes to the given files into the repository. Unlike a
1301 centralized SCM, this operation is a local operation. See
1301 centralized SCM, this operation is a local operation. See
1302 :hg:`push` for a way to actively distribute your changes.
1302 :hg:`push` for a way to actively distribute your changes.
1303
1303
1304 If a list of files is omitted, all changes reported by :hg:`status`
1304 If a list of files is omitted, all changes reported by :hg:`status`
1305 will be committed.
1305 will be committed.
1306
1306
1307 If you are committing the result of a merge, do not provide any
1307 If you are committing the result of a merge, do not provide any
1308 filenames or -I/-X filters.
1308 filenames or -I/-X filters.
1309
1309
1310 If no commit message is specified, Mercurial starts your
1310 If no commit message is specified, Mercurial starts your
1311 configured editor where you can enter a message. In case your
1311 configured editor where you can enter a message. In case your
1312 commit fails, you will find a backup of your message in
1312 commit fails, you will find a backup of your message in
1313 ``.hg/last-message.txt``.
1313 ``.hg/last-message.txt``.
1314
1314
1315 The --amend flag can be used to amend the parent of the
1315 The --amend flag can be used to amend the parent of the
1316 working directory with a new commit that contains the changes
1316 working directory with a new commit that contains the changes
1317 in the parent in addition to those currently reported by :hg:`status`,
1317 in the parent in addition to those currently reported by :hg:`status`,
1318 if there are any. The old commit is stored in a backup bundle in
1318 if there are any. The old commit is stored in a backup bundle in
1319 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1319 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1320 on how to restore it).
1320 on how to restore it).
1321
1321
1322 Message, user and date are taken from the amended commit unless
1322 Message, user and date are taken from the amended commit unless
1323 specified. When a message isn't specified on the command line,
1323 specified. When a message isn't specified on the command line,
1324 the editor will open with the message of the amended commit.
1324 the editor will open with the message of the amended commit.
1325
1325
1326 It is not possible to amend public changesets (see :hg:`help phases`)
1326 It is not possible to amend public changesets (see :hg:`help phases`)
1327 or changesets that have children.
1327 or changesets that have children.
1328
1328
1329 See :hg:`help dates` for a list of formats valid for -d/--date.
1329 See :hg:`help dates` for a list of formats valid for -d/--date.
1330
1330
1331 Returns 0 on success, 1 if nothing changed.
1331 Returns 0 on success, 1 if nothing changed.
1332 """
1332 """
1333 if opts.get('subrepos'):
1333 if opts.get('subrepos'):
1334 if opts.get('amend'):
1334 if opts.get('amend'):
1335 raise util.Abort(_('cannot amend with --subrepos'))
1335 raise util.Abort(_('cannot amend with --subrepos'))
1336 # Let --subrepos on the command line override config setting.
1336 # Let --subrepos on the command line override config setting.
1337 ui.setconfig('ui', 'commitsubrepos', True)
1337 ui.setconfig('ui', 'commitsubrepos', True)
1338
1338
1339 # Save this for restoring it later
1339 # Save this for restoring it later
1340 oldcommitphase = ui.config('phases', 'new-commit')
1340 oldcommitphase = ui.config('phases', 'new-commit')
1341
1341
1342 cmdutil.checkunfinished(repo, commit=True)
1342 cmdutil.checkunfinished(repo, commit=True)
1343
1343
1344 branch = repo[None].branch()
1344 branch = repo[None].branch()
1345 bheads = repo.branchheads(branch)
1345 bheads = repo.branchheads(branch)
1346
1346
1347 extra = {}
1347 extra = {}
1348 if opts.get('close_branch'):
1348 if opts.get('close_branch'):
1349 extra['close'] = 1
1349 extra['close'] = 1
1350
1350
1351 if not bheads:
1351 if not bheads:
1352 raise util.Abort(_('can only close branch heads'))
1352 raise util.Abort(_('can only close branch heads'))
1353 elif opts.get('amend'):
1353 elif opts.get('amend'):
1354 if repo.parents()[0].p1().branch() != branch and \
1354 if repo.parents()[0].p1().branch() != branch and \
1355 repo.parents()[0].p2().branch() != branch:
1355 repo.parents()[0].p2().branch() != branch:
1356 raise util.Abort(_('can only close branch heads'))
1356 raise util.Abort(_('can only close branch heads'))
1357
1357
1358 if opts.get('amend'):
1358 if opts.get('amend'):
1359 if ui.configbool('ui', 'commitsubrepos'):
1359 if ui.configbool('ui', 'commitsubrepos'):
1360 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1360 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1361
1361
1362 old = repo['.']
1362 old = repo['.']
1363 if old.phase() == phases.public:
1363 if old.phase() == phases.public:
1364 raise util.Abort(_('cannot amend public changesets'))
1364 raise util.Abort(_('cannot amend public changesets'))
1365 if len(repo[None].parents()) > 1:
1365 if len(repo[None].parents()) > 1:
1366 raise util.Abort(_('cannot amend while merging'))
1366 raise util.Abort(_('cannot amend while merging'))
1367 if (not obsolete._enabled) and old.children():
1367 if (not obsolete._enabled) and old.children():
1368 raise util.Abort(_('cannot amend changeset with children'))
1368 raise util.Abort(_('cannot amend changeset with children'))
1369
1369
1370 e = cmdutil.commiteditor
1370 e = cmdutil.commiteditor
1371 if opts.get('force_editor'):
1371 if opts.get('force_editor'):
1372 e = cmdutil.commitforceeditor
1372 e = cmdutil.commitforceeditor
1373
1373
1374 def commitfunc(ui, repo, message, match, opts):
1374 def commitfunc(ui, repo, message, match, opts):
1375 editor = e
1375 editor = e
1376 # message contains text from -m or -l, if it's empty,
1376 # message contains text from -m or -l, if it's empty,
1377 # open the editor with the old message
1377 # open the editor with the old message
1378 if not message:
1378 if not message:
1379 message = old.description()
1379 message = old.description()
1380 editor = cmdutil.commitforceeditor
1380 editor = cmdutil.commitforceeditor
1381 try:
1381 try:
1382 if opts.get('secret'):
1382 if opts.get('secret'):
1383 ui.setconfig('phases', 'new-commit', 'secret')
1383 ui.setconfig('phases', 'new-commit', 'secret')
1384
1384
1385 return repo.commit(message,
1385 return repo.commit(message,
1386 opts.get('user') or old.user(),
1386 opts.get('user') or old.user(),
1387 opts.get('date') or old.date(),
1387 opts.get('date') or old.date(),
1388 match,
1388 match,
1389 editor=editor,
1389 editor=editor,
1390 extra=extra)
1390 extra=extra)
1391 finally:
1391 finally:
1392 ui.setconfig('phases', 'new-commit', oldcommitphase)
1392 ui.setconfig('phases', 'new-commit', oldcommitphase)
1393
1393
1394 current = repo._bookmarkcurrent
1394 current = repo._bookmarkcurrent
1395 marks = old.bookmarks()
1395 marks = old.bookmarks()
1396 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1396 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1397 if node == old.node():
1397 if node == old.node():
1398 ui.status(_("nothing changed\n"))
1398 ui.status(_("nothing changed\n"))
1399 return 1
1399 return 1
1400 elif marks:
1400 elif marks:
1401 ui.debug('moving bookmarks %r from %s to %s\n' %
1401 ui.debug('moving bookmarks %r from %s to %s\n' %
1402 (marks, old.hex(), hex(node)))
1402 (marks, old.hex(), hex(node)))
1403 newmarks = repo._bookmarks
1403 newmarks = repo._bookmarks
1404 for bm in marks:
1404 for bm in marks:
1405 newmarks[bm] = node
1405 newmarks[bm] = node
1406 if bm == current:
1406 if bm == current:
1407 bookmarks.setcurrent(repo, bm)
1407 bookmarks.setcurrent(repo, bm)
1408 newmarks.write()
1408 newmarks.write()
1409 else:
1409 else:
1410 e = cmdutil.commiteditor
1410 e = cmdutil.commiteditor
1411 if opts.get('force_editor'):
1411 if opts.get('force_editor'):
1412 e = cmdutil.commitforceeditor
1412 e = cmdutil.commitforceeditor
1413
1413
1414 def commitfunc(ui, repo, message, match, opts):
1414 def commitfunc(ui, repo, message, match, opts):
1415 try:
1415 try:
1416 if opts.get('secret'):
1416 if opts.get('secret'):
1417 ui.setconfig('phases', 'new-commit', 'secret')
1417 ui.setconfig('phases', 'new-commit', 'secret')
1418
1418
1419 return repo.commit(message, opts.get('user'), opts.get('date'),
1419 return repo.commit(message, opts.get('user'), opts.get('date'),
1420 match, editor=e, extra=extra)
1420 match, editor=e, extra=extra)
1421 finally:
1421 finally:
1422 ui.setconfig('phases', 'new-commit', oldcommitphase)
1422 ui.setconfig('phases', 'new-commit', oldcommitphase)
1423
1423
1424
1424
1425 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1425 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1426
1426
1427 if not node:
1427 if not node:
1428 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1428 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1429 if stat[3]:
1429 if stat[3]:
1430 ui.status(_("nothing changed (%d missing files, see "
1430 ui.status(_("nothing changed (%d missing files, see "
1431 "'hg status')\n") % len(stat[3]))
1431 "'hg status')\n") % len(stat[3]))
1432 else:
1432 else:
1433 ui.status(_("nothing changed\n"))
1433 ui.status(_("nothing changed\n"))
1434 return 1
1434 return 1
1435
1435
1436 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1436 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1437
1437
1438 @command('copy|cp',
1438 @command('copy|cp',
1439 [('A', 'after', None, _('record a copy that has already occurred')),
1439 [('A', 'after', None, _('record a copy that has already occurred')),
1440 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1440 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1441 ] + walkopts + dryrunopts,
1441 ] + walkopts + dryrunopts,
1442 _('[OPTION]... [SOURCE]... DEST'))
1442 _('[OPTION]... [SOURCE]... DEST'))
1443 def copy(ui, repo, *pats, **opts):
1443 def copy(ui, repo, *pats, **opts):
1444 """mark files as copied for the next commit
1444 """mark files as copied for the next commit
1445
1445
1446 Mark dest as having copies of source files. If dest is a
1446 Mark dest as having copies of source files. If dest is a
1447 directory, copies are put in that directory. If dest is a file,
1447 directory, copies are put in that directory. If dest is a file,
1448 the source must be a single file.
1448 the source must be a single file.
1449
1449
1450 By default, this command copies the contents of files as they
1450 By default, this command copies the contents of files as they
1451 exist in the working directory. If invoked with -A/--after, the
1451 exist in the working directory. If invoked with -A/--after, the
1452 operation is recorded, but no copying is performed.
1452 operation is recorded, but no copying is performed.
1453
1453
1454 This command takes effect with the next commit. To undo a copy
1454 This command takes effect with the next commit. To undo a copy
1455 before that, see :hg:`revert`.
1455 before that, see :hg:`revert`.
1456
1456
1457 Returns 0 on success, 1 if errors are encountered.
1457 Returns 0 on success, 1 if errors are encountered.
1458 """
1458 """
1459 wlock = repo.wlock(False)
1459 wlock = repo.wlock(False)
1460 try:
1460 try:
1461 return cmdutil.copy(ui, repo, pats, opts)
1461 return cmdutil.copy(ui, repo, pats, opts)
1462 finally:
1462 finally:
1463 wlock.release()
1463 wlock.release()
1464
1464
1465 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1465 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1466 def debugancestor(ui, repo, *args):
1466 def debugancestor(ui, repo, *args):
1467 """find the ancestor revision of two revisions in a given index"""
1467 """find the ancestor revision of two revisions in a given index"""
1468 if len(args) == 3:
1468 if len(args) == 3:
1469 index, rev1, rev2 = args
1469 index, rev1, rev2 = args
1470 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1470 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1471 lookup = r.lookup
1471 lookup = r.lookup
1472 elif len(args) == 2:
1472 elif len(args) == 2:
1473 if not repo:
1473 if not repo:
1474 raise util.Abort(_("there is no Mercurial repository here "
1474 raise util.Abort(_("there is no Mercurial repository here "
1475 "(.hg not found)"))
1475 "(.hg not found)"))
1476 rev1, rev2 = args
1476 rev1, rev2 = args
1477 r = repo.changelog
1477 r = repo.changelog
1478 lookup = repo.lookup
1478 lookup = repo.lookup
1479 else:
1479 else:
1480 raise util.Abort(_('either two or three arguments required'))
1480 raise util.Abort(_('either two or three arguments required'))
1481 a = r.ancestor(lookup(rev1), lookup(rev2))
1481 a = r.ancestor(lookup(rev1), lookup(rev2))
1482 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1482 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1483
1483
1484 @command('debugbuilddag',
1484 @command('debugbuilddag',
1485 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1485 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1486 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1486 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1487 ('n', 'new-file', None, _('add new file at each rev'))],
1487 ('n', 'new-file', None, _('add new file at each rev'))],
1488 _('[OPTION]... [TEXT]'))
1488 _('[OPTION]... [TEXT]'))
1489 def debugbuilddag(ui, repo, text=None,
1489 def debugbuilddag(ui, repo, text=None,
1490 mergeable_file=False,
1490 mergeable_file=False,
1491 overwritten_file=False,
1491 overwritten_file=False,
1492 new_file=False):
1492 new_file=False):
1493 """builds a repo with a given DAG from scratch in the current empty repo
1493 """builds a repo with a given DAG from scratch in the current empty repo
1494
1494
1495 The description of the DAG is read from stdin if not given on the
1495 The description of the DAG is read from stdin if not given on the
1496 command line.
1496 command line.
1497
1497
1498 Elements:
1498 Elements:
1499
1499
1500 - "+n" is a linear run of n nodes based on the current default parent
1500 - "+n" is a linear run of n nodes based on the current default parent
1501 - "." is a single node based on the current default parent
1501 - "." is a single node based on the current default parent
1502 - "$" resets the default parent to null (implied at the start);
1502 - "$" resets the default parent to null (implied at the start);
1503 otherwise the default parent is always the last node created
1503 otherwise the default parent is always the last node created
1504 - "<p" sets the default parent to the backref p
1504 - "<p" sets the default parent to the backref p
1505 - "*p" is a fork at parent p, which is a backref
1505 - "*p" is a fork at parent p, which is a backref
1506 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1506 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1507 - "/p2" is a merge of the preceding node and p2
1507 - "/p2" is a merge of the preceding node and p2
1508 - ":tag" defines a local tag for the preceding node
1508 - ":tag" defines a local tag for the preceding node
1509 - "@branch" sets the named branch for subsequent nodes
1509 - "@branch" sets the named branch for subsequent nodes
1510 - "#...\\n" is a comment up to the end of the line
1510 - "#...\\n" is a comment up to the end of the line
1511
1511
1512 Whitespace between the above elements is ignored.
1512 Whitespace between the above elements is ignored.
1513
1513
1514 A backref is either
1514 A backref is either
1515
1515
1516 - a number n, which references the node curr-n, where curr is the current
1516 - a number n, which references the node curr-n, where curr is the current
1517 node, or
1517 node, or
1518 - the name of a local tag you placed earlier using ":tag", or
1518 - the name of a local tag you placed earlier using ":tag", or
1519 - empty to denote the default parent.
1519 - empty to denote the default parent.
1520
1520
1521 All string valued-elements are either strictly alphanumeric, or must
1521 All string valued-elements are either strictly alphanumeric, or must
1522 be enclosed in double quotes ("..."), with "\\" as escape character.
1522 be enclosed in double quotes ("..."), with "\\" as escape character.
1523 """
1523 """
1524
1524
1525 if text is None:
1525 if text is None:
1526 ui.status(_("reading DAG from stdin\n"))
1526 ui.status(_("reading DAG from stdin\n"))
1527 text = ui.fin.read()
1527 text = ui.fin.read()
1528
1528
1529 cl = repo.changelog
1529 cl = repo.changelog
1530 if len(cl) > 0:
1530 if len(cl) > 0:
1531 raise util.Abort(_('repository is not empty'))
1531 raise util.Abort(_('repository is not empty'))
1532
1532
1533 # determine number of revs in DAG
1533 # determine number of revs in DAG
1534 total = 0
1534 total = 0
1535 for type, data in dagparser.parsedag(text):
1535 for type, data in dagparser.parsedag(text):
1536 if type == 'n':
1536 if type == 'n':
1537 total += 1
1537 total += 1
1538
1538
1539 if mergeable_file:
1539 if mergeable_file:
1540 linesperrev = 2
1540 linesperrev = 2
1541 # make a file with k lines per rev
1541 # make a file with k lines per rev
1542 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1542 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1543 initialmergedlines.append("")
1543 initialmergedlines.append("")
1544
1544
1545 tags = []
1545 tags = []
1546
1546
1547 lock = tr = None
1547 lock = tr = None
1548 try:
1548 try:
1549 lock = repo.lock()
1549 lock = repo.lock()
1550 tr = repo.transaction("builddag")
1550 tr = repo.transaction("builddag")
1551
1551
1552 at = -1
1552 at = -1
1553 atbranch = 'default'
1553 atbranch = 'default'
1554 nodeids = []
1554 nodeids = []
1555 id = 0
1555 id = 0
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 for type, data in dagparser.parsedag(text):
1557 for type, data in dagparser.parsedag(text):
1558 if type == 'n':
1558 if type == 'n':
1559 ui.note(('node %s\n' % str(data)))
1559 ui.note(('node %s\n' % str(data)))
1560 id, ps = data
1560 id, ps = data
1561
1561
1562 files = []
1562 files = []
1563 fctxs = {}
1563 fctxs = {}
1564
1564
1565 p2 = None
1565 p2 = None
1566 if mergeable_file:
1566 if mergeable_file:
1567 fn = "mf"
1567 fn = "mf"
1568 p1 = repo[ps[0]]
1568 p1 = repo[ps[0]]
1569 if len(ps) > 1:
1569 if len(ps) > 1:
1570 p2 = repo[ps[1]]
1570 p2 = repo[ps[1]]
1571 pa = p1.ancestor(p2)
1571 pa = p1.ancestor(p2)
1572 base, local, other = [x[fn].data() for x in (pa, p1,
1572 base, local, other = [x[fn].data() for x in (pa, p1,
1573 p2)]
1573 p2)]
1574 m3 = simplemerge.Merge3Text(base, local, other)
1574 m3 = simplemerge.Merge3Text(base, local, other)
1575 ml = [l.strip() for l in m3.merge_lines()]
1575 ml = [l.strip() for l in m3.merge_lines()]
1576 ml.append("")
1576 ml.append("")
1577 elif at > 0:
1577 elif at > 0:
1578 ml = p1[fn].data().split("\n")
1578 ml = p1[fn].data().split("\n")
1579 else:
1579 else:
1580 ml = initialmergedlines
1580 ml = initialmergedlines
1581 ml[id * linesperrev] += " r%i" % id
1581 ml[id * linesperrev] += " r%i" % id
1582 mergedtext = "\n".join(ml)
1582 mergedtext = "\n".join(ml)
1583 files.append(fn)
1583 files.append(fn)
1584 fctxs[fn] = context.memfilectx(fn, mergedtext)
1584 fctxs[fn] = context.memfilectx(fn, mergedtext)
1585
1585
1586 if overwritten_file:
1586 if overwritten_file:
1587 fn = "of"
1587 fn = "of"
1588 files.append(fn)
1588 files.append(fn)
1589 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1589 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1590
1590
1591 if new_file:
1591 if new_file:
1592 fn = "nf%i" % id
1592 fn = "nf%i" % id
1593 files.append(fn)
1593 files.append(fn)
1594 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1594 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1595 if len(ps) > 1:
1595 if len(ps) > 1:
1596 if not p2:
1596 if not p2:
1597 p2 = repo[ps[1]]
1597 p2 = repo[ps[1]]
1598 for fn in p2:
1598 for fn in p2:
1599 if fn.startswith("nf"):
1599 if fn.startswith("nf"):
1600 files.append(fn)
1600 files.append(fn)
1601 fctxs[fn] = p2[fn]
1601 fctxs[fn] = p2[fn]
1602
1602
1603 def fctxfn(repo, cx, path):
1603 def fctxfn(repo, cx, path):
1604 return fctxs.get(path)
1604 return fctxs.get(path)
1605
1605
1606 if len(ps) == 0 or ps[0] < 0:
1606 if len(ps) == 0 or ps[0] < 0:
1607 pars = [None, None]
1607 pars = [None, None]
1608 elif len(ps) == 1:
1608 elif len(ps) == 1:
1609 pars = [nodeids[ps[0]], None]
1609 pars = [nodeids[ps[0]], None]
1610 else:
1610 else:
1611 pars = [nodeids[p] for p in ps]
1611 pars = [nodeids[p] for p in ps]
1612 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1612 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1613 date=(id, 0),
1613 date=(id, 0),
1614 user="debugbuilddag",
1614 user="debugbuilddag",
1615 extra={'branch': atbranch})
1615 extra={'branch': atbranch})
1616 nodeid = repo.commitctx(cx)
1616 nodeid = repo.commitctx(cx)
1617 nodeids.append(nodeid)
1617 nodeids.append(nodeid)
1618 at = id
1618 at = id
1619 elif type == 'l':
1619 elif type == 'l':
1620 id, name = data
1620 id, name = data
1621 ui.note(('tag %s\n' % name))
1621 ui.note(('tag %s\n' % name))
1622 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1622 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1623 elif type == 'a':
1623 elif type == 'a':
1624 ui.note(('branch %s\n' % data))
1624 ui.note(('branch %s\n' % data))
1625 atbranch = data
1625 atbranch = data
1626 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1626 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1627 tr.close()
1627 tr.close()
1628
1628
1629 if tags:
1629 if tags:
1630 repo.opener.write("localtags", "".join(tags))
1630 repo.opener.write("localtags", "".join(tags))
1631 finally:
1631 finally:
1632 ui.progress(_('building'), None)
1632 ui.progress(_('building'), None)
1633 release(tr, lock)
1633 release(tr, lock)
1634
1634
1635 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1635 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1636 def debugbundle(ui, bundlepath, all=None, **opts):
1636 def debugbundle(ui, bundlepath, all=None, **opts):
1637 """lists the contents of a bundle"""
1637 """lists the contents of a bundle"""
1638 f = hg.openpath(ui, bundlepath)
1638 f = hg.openpath(ui, bundlepath)
1639 try:
1639 try:
1640 gen = changegroup.readbundle(f, bundlepath)
1640 gen = changegroup.readbundle(f, bundlepath)
1641 if all:
1641 if all:
1642 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1642 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1643
1643
1644 def showchunks(named):
1644 def showchunks(named):
1645 ui.write("\n%s\n" % named)
1645 ui.write("\n%s\n" % named)
1646 chain = None
1646 chain = None
1647 while True:
1647 while True:
1648 chunkdata = gen.deltachunk(chain)
1648 chunkdata = gen.deltachunk(chain)
1649 if not chunkdata:
1649 if not chunkdata:
1650 break
1650 break
1651 node = chunkdata['node']
1651 node = chunkdata['node']
1652 p1 = chunkdata['p1']
1652 p1 = chunkdata['p1']
1653 p2 = chunkdata['p2']
1653 p2 = chunkdata['p2']
1654 cs = chunkdata['cs']
1654 cs = chunkdata['cs']
1655 deltabase = chunkdata['deltabase']
1655 deltabase = chunkdata['deltabase']
1656 delta = chunkdata['delta']
1656 delta = chunkdata['delta']
1657 ui.write("%s %s %s %s %s %s\n" %
1657 ui.write("%s %s %s %s %s %s\n" %
1658 (hex(node), hex(p1), hex(p2),
1658 (hex(node), hex(p1), hex(p2),
1659 hex(cs), hex(deltabase), len(delta)))
1659 hex(cs), hex(deltabase), len(delta)))
1660 chain = node
1660 chain = node
1661
1661
1662 chunkdata = gen.changelogheader()
1662 chunkdata = gen.changelogheader()
1663 showchunks("changelog")
1663 showchunks("changelog")
1664 chunkdata = gen.manifestheader()
1664 chunkdata = gen.manifestheader()
1665 showchunks("manifest")
1665 showchunks("manifest")
1666 while True:
1666 while True:
1667 chunkdata = gen.filelogheader()
1667 chunkdata = gen.filelogheader()
1668 if not chunkdata:
1668 if not chunkdata:
1669 break
1669 break
1670 fname = chunkdata['filename']
1670 fname = chunkdata['filename']
1671 showchunks(fname)
1671 showchunks(fname)
1672 else:
1672 else:
1673 chunkdata = gen.changelogheader()
1673 chunkdata = gen.changelogheader()
1674 chain = None
1674 chain = None
1675 while True:
1675 while True:
1676 chunkdata = gen.deltachunk(chain)
1676 chunkdata = gen.deltachunk(chain)
1677 if not chunkdata:
1677 if not chunkdata:
1678 break
1678 break
1679 node = chunkdata['node']
1679 node = chunkdata['node']
1680 ui.write("%s\n" % hex(node))
1680 ui.write("%s\n" % hex(node))
1681 chain = node
1681 chain = node
1682 finally:
1682 finally:
1683 f.close()
1683 f.close()
1684
1684
1685 @command('debugcheckstate', [], '')
1685 @command('debugcheckstate', [], '')
1686 def debugcheckstate(ui, repo):
1686 def debugcheckstate(ui, repo):
1687 """validate the correctness of the current dirstate"""
1687 """validate the correctness of the current dirstate"""
1688 parent1, parent2 = repo.dirstate.parents()
1688 parent1, parent2 = repo.dirstate.parents()
1689 m1 = repo[parent1].manifest()
1689 m1 = repo[parent1].manifest()
1690 m2 = repo[parent2].manifest()
1690 m2 = repo[parent2].manifest()
1691 errors = 0
1691 errors = 0
1692 for f in repo.dirstate:
1692 for f in repo.dirstate:
1693 state = repo.dirstate[f]
1693 state = repo.dirstate[f]
1694 if state in "nr" and f not in m1:
1694 if state in "nr" and f not in m1:
1695 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1695 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1696 errors += 1
1696 errors += 1
1697 if state in "a" and f in m1:
1697 if state in "a" and f in m1:
1698 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1698 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1699 errors += 1
1699 errors += 1
1700 if state in "m" and f not in m1 and f not in m2:
1700 if state in "m" and f not in m1 and f not in m2:
1701 ui.warn(_("%s in state %s, but not in either manifest\n") %
1701 ui.warn(_("%s in state %s, but not in either manifest\n") %
1702 (f, state))
1702 (f, state))
1703 errors += 1
1703 errors += 1
1704 for f in m1:
1704 for f in m1:
1705 state = repo.dirstate[f]
1705 state = repo.dirstate[f]
1706 if state not in "nrm":
1706 if state not in "nrm":
1707 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1707 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1708 errors += 1
1708 errors += 1
1709 if errors:
1709 if errors:
1710 error = _(".hg/dirstate inconsistent with current parent's manifest")
1710 error = _(".hg/dirstate inconsistent with current parent's manifest")
1711 raise util.Abort(error)
1711 raise util.Abort(error)
1712
1712
1713 @command('debugcommands', [], _('[COMMAND]'))
1713 @command('debugcommands', [], _('[COMMAND]'))
1714 def debugcommands(ui, cmd='', *args):
1714 def debugcommands(ui, cmd='', *args):
1715 """list all available commands and options"""
1715 """list all available commands and options"""
1716 for cmd, vals in sorted(table.iteritems()):
1716 for cmd, vals in sorted(table.iteritems()):
1717 cmd = cmd.split('|')[0].strip('^')
1717 cmd = cmd.split('|')[0].strip('^')
1718 opts = ', '.join([i[1] for i in vals[1]])
1718 opts = ', '.join([i[1] for i in vals[1]])
1719 ui.write('%s: %s\n' % (cmd, opts))
1719 ui.write('%s: %s\n' % (cmd, opts))
1720
1720
1721 @command('debugcomplete',
1721 @command('debugcomplete',
1722 [('o', 'options', None, _('show the command options'))],
1722 [('o', 'options', None, _('show the command options'))],
1723 _('[-o] CMD'))
1723 _('[-o] CMD'))
1724 def debugcomplete(ui, cmd='', **opts):
1724 def debugcomplete(ui, cmd='', **opts):
1725 """returns the completion list associated with the given command"""
1725 """returns the completion list associated with the given command"""
1726
1726
1727 if opts.get('options'):
1727 if opts.get('options'):
1728 options = []
1728 options = []
1729 otables = [globalopts]
1729 otables = [globalopts]
1730 if cmd:
1730 if cmd:
1731 aliases, entry = cmdutil.findcmd(cmd, table, False)
1731 aliases, entry = cmdutil.findcmd(cmd, table, False)
1732 otables.append(entry[1])
1732 otables.append(entry[1])
1733 for t in otables:
1733 for t in otables:
1734 for o in t:
1734 for o in t:
1735 if "(DEPRECATED)" in o[3]:
1735 if "(DEPRECATED)" in o[3]:
1736 continue
1736 continue
1737 if o[0]:
1737 if o[0]:
1738 options.append('-%s' % o[0])
1738 options.append('-%s' % o[0])
1739 options.append('--%s' % o[1])
1739 options.append('--%s' % o[1])
1740 ui.write("%s\n" % "\n".join(options))
1740 ui.write("%s\n" % "\n".join(options))
1741 return
1741 return
1742
1742
1743 cmdlist = cmdutil.findpossible(cmd, table)
1743 cmdlist = cmdutil.findpossible(cmd, table)
1744 if ui.verbose:
1744 if ui.verbose:
1745 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1745 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1746 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1746 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1747
1747
1748 @command('debugdag',
1748 @command('debugdag',
1749 [('t', 'tags', None, _('use tags as labels')),
1749 [('t', 'tags', None, _('use tags as labels')),
1750 ('b', 'branches', None, _('annotate with branch names')),
1750 ('b', 'branches', None, _('annotate with branch names')),
1751 ('', 'dots', None, _('use dots for runs')),
1751 ('', 'dots', None, _('use dots for runs')),
1752 ('s', 'spaces', None, _('separate elements by spaces'))],
1752 ('s', 'spaces', None, _('separate elements by spaces'))],
1753 _('[OPTION]... [FILE [REV]...]'))
1753 _('[OPTION]... [FILE [REV]...]'))
1754 def debugdag(ui, repo, file_=None, *revs, **opts):
1754 def debugdag(ui, repo, file_=None, *revs, **opts):
1755 """format the changelog or an index DAG as a concise textual description
1755 """format the changelog or an index DAG as a concise textual description
1756
1756
1757 If you pass a revlog index, the revlog's DAG is emitted. If you list
1757 If you pass a revlog index, the revlog's DAG is emitted. If you list
1758 revision numbers, they get labeled in the output as rN.
1758 revision numbers, they get labeled in the output as rN.
1759
1759
1760 Otherwise, the changelog DAG of the current repo is emitted.
1760 Otherwise, the changelog DAG of the current repo is emitted.
1761 """
1761 """
1762 spaces = opts.get('spaces')
1762 spaces = opts.get('spaces')
1763 dots = opts.get('dots')
1763 dots = opts.get('dots')
1764 if file_:
1764 if file_:
1765 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1765 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1766 revs = set((int(r) for r in revs))
1766 revs = set((int(r) for r in revs))
1767 def events():
1767 def events():
1768 for r in rlog:
1768 for r in rlog:
1769 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1769 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1770 if p != -1)))
1770 if p != -1)))
1771 if r in revs:
1771 if r in revs:
1772 yield 'l', (r, "r%i" % r)
1772 yield 'l', (r, "r%i" % r)
1773 elif repo:
1773 elif repo:
1774 cl = repo.changelog
1774 cl = repo.changelog
1775 tags = opts.get('tags')
1775 tags = opts.get('tags')
1776 branches = opts.get('branches')
1776 branches = opts.get('branches')
1777 if tags:
1777 if tags:
1778 labels = {}
1778 labels = {}
1779 for l, n in repo.tags().items():
1779 for l, n in repo.tags().items():
1780 labels.setdefault(cl.rev(n), []).append(l)
1780 labels.setdefault(cl.rev(n), []).append(l)
1781 def events():
1781 def events():
1782 b = "default"
1782 b = "default"
1783 for r in cl:
1783 for r in cl:
1784 if branches:
1784 if branches:
1785 newb = cl.read(cl.node(r))[5]['branch']
1785 newb = cl.read(cl.node(r))[5]['branch']
1786 if newb != b:
1786 if newb != b:
1787 yield 'a', newb
1787 yield 'a', newb
1788 b = newb
1788 b = newb
1789 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1789 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1790 if p != -1)))
1790 if p != -1)))
1791 if tags:
1791 if tags:
1792 ls = labels.get(r)
1792 ls = labels.get(r)
1793 if ls:
1793 if ls:
1794 for l in ls:
1794 for l in ls:
1795 yield 'l', (r, l)
1795 yield 'l', (r, l)
1796 else:
1796 else:
1797 raise util.Abort(_('need repo for changelog dag'))
1797 raise util.Abort(_('need repo for changelog dag'))
1798
1798
1799 for line in dagparser.dagtextlines(events(),
1799 for line in dagparser.dagtextlines(events(),
1800 addspaces=spaces,
1800 addspaces=spaces,
1801 wraplabels=True,
1801 wraplabels=True,
1802 wrapannotations=True,
1802 wrapannotations=True,
1803 wrapnonlinear=dots,
1803 wrapnonlinear=dots,
1804 usedots=dots,
1804 usedots=dots,
1805 maxlinewidth=70):
1805 maxlinewidth=70):
1806 ui.write(line)
1806 ui.write(line)
1807 ui.write("\n")
1807 ui.write("\n")
1808
1808
1809 @command('debugdata',
1809 @command('debugdata',
1810 [('c', 'changelog', False, _('open changelog')),
1810 [('c', 'changelog', False, _('open changelog')),
1811 ('m', 'manifest', False, _('open manifest'))],
1811 ('m', 'manifest', False, _('open manifest'))],
1812 _('-c|-m|FILE REV'))
1812 _('-c|-m|FILE REV'))
1813 def debugdata(ui, repo, file_, rev=None, **opts):
1813 def debugdata(ui, repo, file_, rev=None, **opts):
1814 """dump the contents of a data file revision"""
1814 """dump the contents of a data file revision"""
1815 if opts.get('changelog') or opts.get('manifest'):
1815 if opts.get('changelog') or opts.get('manifest'):
1816 file_, rev = None, file_
1816 file_, rev = None, file_
1817 elif rev is None:
1817 elif rev is None:
1818 raise error.CommandError('debugdata', _('invalid arguments'))
1818 raise error.CommandError('debugdata', _('invalid arguments'))
1819 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1819 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1820 try:
1820 try:
1821 ui.write(r.revision(r.lookup(rev)))
1821 ui.write(r.revision(r.lookup(rev)))
1822 except KeyError:
1822 except KeyError:
1823 raise util.Abort(_('invalid revision identifier %s') % rev)
1823 raise util.Abort(_('invalid revision identifier %s') % rev)
1824
1824
1825 @command('debugdate',
1825 @command('debugdate',
1826 [('e', 'extended', None, _('try extended date formats'))],
1826 [('e', 'extended', None, _('try extended date formats'))],
1827 _('[-e] DATE [RANGE]'))
1827 _('[-e] DATE [RANGE]'))
1828 def debugdate(ui, date, range=None, **opts):
1828 def debugdate(ui, date, range=None, **opts):
1829 """parse and display a date"""
1829 """parse and display a date"""
1830 if opts["extended"]:
1830 if opts["extended"]:
1831 d = util.parsedate(date, util.extendeddateformats)
1831 d = util.parsedate(date, util.extendeddateformats)
1832 else:
1832 else:
1833 d = util.parsedate(date)
1833 d = util.parsedate(date)
1834 ui.write(("internal: %s %s\n") % d)
1834 ui.write(("internal: %s %s\n") % d)
1835 ui.write(("standard: %s\n") % util.datestr(d))
1835 ui.write(("standard: %s\n") % util.datestr(d))
1836 if range:
1836 if range:
1837 m = util.matchdate(range)
1837 m = util.matchdate(range)
1838 ui.write(("match: %s\n") % m(d[0]))
1838 ui.write(("match: %s\n") % m(d[0]))
1839
1839
1840 @command('debugdiscovery',
1840 @command('debugdiscovery',
1841 [('', 'old', None, _('use old-style discovery')),
1841 [('', 'old', None, _('use old-style discovery')),
1842 ('', 'nonheads', None,
1842 ('', 'nonheads', None,
1843 _('use old-style discovery with non-heads included')),
1843 _('use old-style discovery with non-heads included')),
1844 ] + remoteopts,
1844 ] + remoteopts,
1845 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1845 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1846 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1846 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1847 """runs the changeset discovery protocol in isolation"""
1847 """runs the changeset discovery protocol in isolation"""
1848 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1848 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1849 opts.get('branch'))
1849 opts.get('branch'))
1850 remote = hg.peer(repo, opts, remoteurl)
1850 remote = hg.peer(repo, opts, remoteurl)
1851 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1851 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1852
1852
1853 # make sure tests are repeatable
1853 # make sure tests are repeatable
1854 random.seed(12323)
1854 random.seed(12323)
1855
1855
1856 def doit(localheads, remoteheads, remote=remote):
1856 def doit(localheads, remoteheads, remote=remote):
1857 if opts.get('old'):
1857 if opts.get('old'):
1858 if localheads:
1858 if localheads:
1859 raise util.Abort('cannot use localheads with old style '
1859 raise util.Abort('cannot use localheads with old style '
1860 'discovery')
1860 'discovery')
1861 if not util.safehasattr(remote, 'branches'):
1861 if not util.safehasattr(remote, 'branches'):
1862 # enable in-client legacy support
1862 # enable in-client legacy support
1863 remote = localrepo.locallegacypeer(remote.local())
1863 remote = localrepo.locallegacypeer(remote.local())
1864 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1864 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1865 force=True)
1865 force=True)
1866 common = set(common)
1866 common = set(common)
1867 if not opts.get('nonheads'):
1867 if not opts.get('nonheads'):
1868 ui.write(("unpruned common: %s\n") %
1868 ui.write(("unpruned common: %s\n") %
1869 " ".join(sorted(short(n) for n in common)))
1869 " ".join(sorted(short(n) for n in common)))
1870 dag = dagutil.revlogdag(repo.changelog)
1870 dag = dagutil.revlogdag(repo.changelog)
1871 all = dag.ancestorset(dag.internalizeall(common))
1871 all = dag.ancestorset(dag.internalizeall(common))
1872 common = dag.externalizeall(dag.headsetofconnecteds(all))
1872 common = dag.externalizeall(dag.headsetofconnecteds(all))
1873 else:
1873 else:
1874 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1874 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1875 common = set(common)
1875 common = set(common)
1876 rheads = set(hds)
1876 rheads = set(hds)
1877 lheads = set(repo.heads())
1877 lheads = set(repo.heads())
1878 ui.write(("common heads: %s\n") %
1878 ui.write(("common heads: %s\n") %
1879 " ".join(sorted(short(n) for n in common)))
1879 " ".join(sorted(short(n) for n in common)))
1880 if lheads <= common:
1880 if lheads <= common:
1881 ui.write(("local is subset\n"))
1881 ui.write(("local is subset\n"))
1882 elif rheads <= common:
1882 elif rheads <= common:
1883 ui.write(("remote is subset\n"))
1883 ui.write(("remote is subset\n"))
1884
1884
1885 serverlogs = opts.get('serverlog')
1885 serverlogs = opts.get('serverlog')
1886 if serverlogs:
1886 if serverlogs:
1887 for filename in serverlogs:
1887 for filename in serverlogs:
1888 logfile = open(filename, 'r')
1888 logfile = open(filename, 'r')
1889 try:
1889 try:
1890 line = logfile.readline()
1890 line = logfile.readline()
1891 while line:
1891 while line:
1892 parts = line.strip().split(';')
1892 parts = line.strip().split(';')
1893 op = parts[1]
1893 op = parts[1]
1894 if op == 'cg':
1894 if op == 'cg':
1895 pass
1895 pass
1896 elif op == 'cgss':
1896 elif op == 'cgss':
1897 doit(parts[2].split(' '), parts[3].split(' '))
1897 doit(parts[2].split(' '), parts[3].split(' '))
1898 elif op == 'unb':
1898 elif op == 'unb':
1899 doit(parts[3].split(' '), parts[2].split(' '))
1899 doit(parts[3].split(' '), parts[2].split(' '))
1900 line = logfile.readline()
1900 line = logfile.readline()
1901 finally:
1901 finally:
1902 logfile.close()
1902 logfile.close()
1903
1903
1904 else:
1904 else:
1905 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1905 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1906 opts.get('remote_head'))
1906 opts.get('remote_head'))
1907 localrevs = opts.get('local_head')
1907 localrevs = opts.get('local_head')
1908 doit(localrevs, remoterevs)
1908 doit(localrevs, remoterevs)
1909
1909
1910 @command('debugfileset',
1910 @command('debugfileset',
1911 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1911 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1912 _('[-r REV] FILESPEC'))
1912 _('[-r REV] FILESPEC'))
1913 def debugfileset(ui, repo, expr, **opts):
1913 def debugfileset(ui, repo, expr, **opts):
1914 '''parse and apply a fileset specification'''
1914 '''parse and apply a fileset specification'''
1915 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1915 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1916 if ui.verbose:
1916 if ui.verbose:
1917 tree = fileset.parse(expr)[0]
1917 tree = fileset.parse(expr)[0]
1918 ui.note(tree, "\n")
1918 ui.note(tree, "\n")
1919
1919
1920 for f in fileset.getfileset(ctx, expr):
1920 for f in fileset.getfileset(ctx, expr):
1921 ui.write("%s\n" % f)
1921 ui.write("%s\n" % f)
1922
1922
1923 @command('debugfsinfo', [], _('[PATH]'))
1923 @command('debugfsinfo', [], _('[PATH]'))
1924 def debugfsinfo(ui, path="."):
1924 def debugfsinfo(ui, path="."):
1925 """show information detected about current filesystem"""
1925 """show information detected about current filesystem"""
1926 util.writefile('.debugfsinfo', '')
1926 util.writefile('.debugfsinfo', '')
1927 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1927 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1928 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1928 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1929 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1929 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1930 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1930 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1931 and 'yes' or 'no'))
1931 and 'yes' or 'no'))
1932 os.unlink('.debugfsinfo')
1932 os.unlink('.debugfsinfo')
1933
1933
1934 @command('debuggetbundle',
1934 @command('debuggetbundle',
1935 [('H', 'head', [], _('id of head node'), _('ID')),
1935 [('H', 'head', [], _('id of head node'), _('ID')),
1936 ('C', 'common', [], _('id of common node'), _('ID')),
1936 ('C', 'common', [], _('id of common node'), _('ID')),
1937 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1937 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1938 _('REPO FILE [-H|-C ID]...'))
1938 _('REPO FILE [-H|-C ID]...'))
1939 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1939 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1940 """retrieves a bundle from a repo
1940 """retrieves a bundle from a repo
1941
1941
1942 Every ID must be a full-length hex node id string. Saves the bundle to the
1942 Every ID must be a full-length hex node id string. Saves the bundle to the
1943 given file.
1943 given file.
1944 """
1944 """
1945 repo = hg.peer(ui, opts, repopath)
1945 repo = hg.peer(ui, opts, repopath)
1946 if not repo.capable('getbundle'):
1946 if not repo.capable('getbundle'):
1947 raise util.Abort("getbundle() not supported by target repository")
1947 raise util.Abort("getbundle() not supported by target repository")
1948 args = {}
1948 args = {}
1949 if common:
1949 if common:
1950 args['common'] = [bin(s) for s in common]
1950 args['common'] = [bin(s) for s in common]
1951 if head:
1951 if head:
1952 args['heads'] = [bin(s) for s in head]
1952 args['heads'] = [bin(s) for s in head]
1953 # TODO: get desired bundlecaps from command line.
1953 # TODO: get desired bundlecaps from command line.
1954 args['bundlecaps'] = None
1954 args['bundlecaps'] = None
1955 bundle = repo.getbundle('debug', **args)
1955 bundle = repo.getbundle('debug', **args)
1956
1956
1957 bundletype = opts.get('type', 'bzip2').lower()
1957 bundletype = opts.get('type', 'bzip2').lower()
1958 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1958 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1959 bundletype = btypes.get(bundletype)
1959 bundletype = btypes.get(bundletype)
1960 if bundletype not in changegroup.bundletypes:
1960 if bundletype not in changegroup.bundletypes:
1961 raise util.Abort(_('unknown bundle type specified with --type'))
1961 raise util.Abort(_('unknown bundle type specified with --type'))
1962 changegroup.writebundle(bundle, bundlepath, bundletype)
1962 changegroup.writebundle(bundle, bundlepath, bundletype)
1963
1963
1964 @command('debugignore', [], '')
1964 @command('debugignore', [], '')
1965 def debugignore(ui, repo, *values, **opts):
1965 def debugignore(ui, repo, *values, **opts):
1966 """display the combined ignore pattern"""
1966 """display the combined ignore pattern"""
1967 ignore = repo.dirstate._ignore
1967 ignore = repo.dirstate._ignore
1968 includepat = getattr(ignore, 'includepat', None)
1968 includepat = getattr(ignore, 'includepat', None)
1969 if includepat is not None:
1969 if includepat is not None:
1970 ui.write("%s\n" % includepat)
1970 ui.write("%s\n" % includepat)
1971 else:
1971 else:
1972 raise util.Abort(_("no ignore patterns found"))
1972 raise util.Abort(_("no ignore patterns found"))
1973
1973
1974 @command('debugindex',
1974 @command('debugindex',
1975 [('c', 'changelog', False, _('open changelog')),
1975 [('c', 'changelog', False, _('open changelog')),
1976 ('m', 'manifest', False, _('open manifest')),
1976 ('m', 'manifest', False, _('open manifest')),
1977 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1977 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1978 _('[-f FORMAT] -c|-m|FILE'))
1978 _('[-f FORMAT] -c|-m|FILE'))
1979 def debugindex(ui, repo, file_=None, **opts):
1979 def debugindex(ui, repo, file_=None, **opts):
1980 """dump the contents of an index file"""
1980 """dump the contents of an index file"""
1981 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1981 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1982 format = opts.get('format', 0)
1982 format = opts.get('format', 0)
1983 if format not in (0, 1):
1983 if format not in (0, 1):
1984 raise util.Abort(_("unknown format %d") % format)
1984 raise util.Abort(_("unknown format %d") % format)
1985
1985
1986 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1986 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1987 if generaldelta:
1987 if generaldelta:
1988 basehdr = ' delta'
1988 basehdr = ' delta'
1989 else:
1989 else:
1990 basehdr = ' base'
1990 basehdr = ' base'
1991
1991
1992 if format == 0:
1992 if format == 0:
1993 ui.write(" rev offset length " + basehdr + " linkrev"
1993 ui.write(" rev offset length " + basehdr + " linkrev"
1994 " nodeid p1 p2\n")
1994 " nodeid p1 p2\n")
1995 elif format == 1:
1995 elif format == 1:
1996 ui.write(" rev flag offset length"
1996 ui.write(" rev flag offset length"
1997 " size " + basehdr + " link p1 p2"
1997 " size " + basehdr + " link p1 p2"
1998 " nodeid\n")
1998 " nodeid\n")
1999
1999
2000 for i in r:
2000 for i in r:
2001 node = r.node(i)
2001 node = r.node(i)
2002 if generaldelta:
2002 if generaldelta:
2003 base = r.deltaparent(i)
2003 base = r.deltaparent(i)
2004 else:
2004 else:
2005 base = r.chainbase(i)
2005 base = r.chainbase(i)
2006 if format == 0:
2006 if format == 0:
2007 try:
2007 try:
2008 pp = r.parents(node)
2008 pp = r.parents(node)
2009 except Exception:
2009 except Exception:
2010 pp = [nullid, nullid]
2010 pp = [nullid, nullid]
2011 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2011 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2012 i, r.start(i), r.length(i), base, r.linkrev(i),
2012 i, r.start(i), r.length(i), base, r.linkrev(i),
2013 short(node), short(pp[0]), short(pp[1])))
2013 short(node), short(pp[0]), short(pp[1])))
2014 elif format == 1:
2014 elif format == 1:
2015 pr = r.parentrevs(i)
2015 pr = r.parentrevs(i)
2016 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2016 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2017 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2017 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2018 base, r.linkrev(i), pr[0], pr[1], short(node)))
2018 base, r.linkrev(i), pr[0], pr[1], short(node)))
2019
2019
2020 @command('debugindexdot', [], _('FILE'))
2020 @command('debugindexdot', [], _('FILE'))
2021 def debugindexdot(ui, repo, file_):
2021 def debugindexdot(ui, repo, file_):
2022 """dump an index DAG as a graphviz dot file"""
2022 """dump an index DAG as a graphviz dot file"""
2023 r = None
2023 r = None
2024 if repo:
2024 if repo:
2025 filelog = repo.file(file_)
2025 filelog = repo.file(file_)
2026 if len(filelog):
2026 if len(filelog):
2027 r = filelog
2027 r = filelog
2028 if not r:
2028 if not r:
2029 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2029 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2030 ui.write(("digraph G {\n"))
2030 ui.write(("digraph G {\n"))
2031 for i in r:
2031 for i in r:
2032 node = r.node(i)
2032 node = r.node(i)
2033 pp = r.parents(node)
2033 pp = r.parents(node)
2034 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2034 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2035 if pp[1] != nullid:
2035 if pp[1] != nullid:
2036 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2036 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2037 ui.write("}\n")
2037 ui.write("}\n")
2038
2038
2039 @command('debuginstall', [], '')
2039 @command('debuginstall', [], '')
2040 def debuginstall(ui):
2040 def debuginstall(ui):
2041 '''test Mercurial installation
2041 '''test Mercurial installation
2042
2042
2043 Returns 0 on success.
2043 Returns 0 on success.
2044 '''
2044 '''
2045
2045
2046 def writetemp(contents):
2046 def writetemp(contents):
2047 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2047 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2048 f = os.fdopen(fd, "wb")
2048 f = os.fdopen(fd, "wb")
2049 f.write(contents)
2049 f.write(contents)
2050 f.close()
2050 f.close()
2051 return name
2051 return name
2052
2052
2053 problems = 0
2053 problems = 0
2054
2054
2055 # encoding
2055 # encoding
2056 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2056 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2057 try:
2057 try:
2058 encoding.fromlocal("test")
2058 encoding.fromlocal("test")
2059 except util.Abort, inst:
2059 except util.Abort, inst:
2060 ui.write(" %s\n" % inst)
2060 ui.write(" %s\n" % inst)
2061 ui.write(_(" (check that your locale is properly set)\n"))
2061 ui.write(_(" (check that your locale is properly set)\n"))
2062 problems += 1
2062 problems += 1
2063
2063
2064 # Python lib
2064 # Python lib
2065 ui.status(_("checking Python lib (%s)...\n")
2065 ui.status(_("checking Python lib (%s)...\n")
2066 % os.path.dirname(os.__file__))
2066 % os.path.dirname(os.__file__))
2067
2067
2068 # compiled modules
2068 # compiled modules
2069 ui.status(_("checking installed modules (%s)...\n")
2069 ui.status(_("checking installed modules (%s)...\n")
2070 % os.path.dirname(__file__))
2070 % os.path.dirname(__file__))
2071 try:
2071 try:
2072 import bdiff, mpatch, base85, osutil
2072 import bdiff, mpatch, base85, osutil
2073 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2073 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2074 except Exception, inst:
2074 except Exception, inst:
2075 ui.write(" %s\n" % inst)
2075 ui.write(" %s\n" % inst)
2076 ui.write(_(" One or more extensions could not be found"))
2076 ui.write(_(" One or more extensions could not be found"))
2077 ui.write(_(" (check that you compiled the extensions)\n"))
2077 ui.write(_(" (check that you compiled the extensions)\n"))
2078 problems += 1
2078 problems += 1
2079
2079
2080 # templates
2080 # templates
2081 import templater
2081 import templater
2082 p = templater.templatepath()
2082 p = templater.templatepath()
2083 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2083 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2084 try:
2084 try:
2085 templater.templater(templater.templatepath("map-cmdline.default"))
2085 templater.templater(templater.templatepath("map-cmdline.default"))
2086 except Exception, inst:
2086 except Exception, inst:
2087 ui.write(" %s\n" % inst)
2087 ui.write(" %s\n" % inst)
2088 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2088 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2089 problems += 1
2089 problems += 1
2090
2090
2091 # editor
2091 # editor
2092 ui.status(_("checking commit editor...\n"))
2092 ui.status(_("checking commit editor...\n"))
2093 editor = ui.geteditor()
2093 editor = ui.geteditor()
2094 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2094 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2095 if not cmdpath:
2095 if not cmdpath:
2096 if editor == 'vi':
2096 if editor == 'vi':
2097 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2097 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2098 ui.write(_(" (specify a commit editor in your configuration"
2098 ui.write(_(" (specify a commit editor in your configuration"
2099 " file)\n"))
2099 " file)\n"))
2100 else:
2100 else:
2101 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2101 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2102 ui.write(_(" (specify a commit editor in your configuration"
2102 ui.write(_(" (specify a commit editor in your configuration"
2103 " file)\n"))
2103 " file)\n"))
2104 problems += 1
2104 problems += 1
2105
2105
2106 # check username
2106 # check username
2107 ui.status(_("checking username...\n"))
2107 ui.status(_("checking username...\n"))
2108 try:
2108 try:
2109 ui.username()
2109 ui.username()
2110 except util.Abort, e:
2110 except util.Abort, e:
2111 ui.write(" %s\n" % e)
2111 ui.write(" %s\n" % e)
2112 ui.write(_(" (specify a username in your configuration file)\n"))
2112 ui.write(_(" (specify a username in your configuration file)\n"))
2113 problems += 1
2113 problems += 1
2114
2114
2115 if not problems:
2115 if not problems:
2116 ui.status(_("no problems detected\n"))
2116 ui.status(_("no problems detected\n"))
2117 else:
2117 else:
2118 ui.write(_("%s problems detected,"
2118 ui.write(_("%s problems detected,"
2119 " please check your install!\n") % problems)
2119 " please check your install!\n") % problems)
2120
2120
2121 return problems
2121 return problems
2122
2122
2123 @command('debugknown', [], _('REPO ID...'))
2123 @command('debugknown', [], _('REPO ID...'))
2124 def debugknown(ui, repopath, *ids, **opts):
2124 def debugknown(ui, repopath, *ids, **opts):
2125 """test whether node ids are known to a repo
2125 """test whether node ids are known to a repo
2126
2126
2127 Every ID must be a full-length hex node id string. Returns a list of 0s
2127 Every ID must be a full-length hex node id string. Returns a list of 0s
2128 and 1s indicating unknown/known.
2128 and 1s indicating unknown/known.
2129 """
2129 """
2130 repo = hg.peer(ui, opts, repopath)
2130 repo = hg.peer(ui, opts, repopath)
2131 if not repo.capable('known'):
2131 if not repo.capable('known'):
2132 raise util.Abort("known() not supported by target repository")
2132 raise util.Abort("known() not supported by target repository")
2133 flags = repo.known([bin(s) for s in ids])
2133 flags = repo.known([bin(s) for s in ids])
2134 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2134 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2135
2135
2136 @command('debuglabelcomplete', [], _('LABEL...'))
2136 @command('debuglabelcomplete', [], _('LABEL...'))
2137 def debuglabelcomplete(ui, repo, *args):
2137 def debuglabelcomplete(ui, repo, *args):
2138 '''complete "labels" - tags, open branch names, bookmark names'''
2138 '''complete "labels" - tags, open branch names, bookmark names'''
2139
2139
2140 labels = set()
2140 labels = set()
2141 labels.update(t[0] for t in repo.tagslist())
2141 labels.update(t[0] for t in repo.tagslist())
2142 labels.update(repo._bookmarks.keys())
2142 labels.update(repo._bookmarks.keys())
2143 for heads in repo.branchmap().itervalues():
2143 for heads in repo.branchmap().itervalues():
2144 for h in heads:
2144 for h in heads:
2145 ctx = repo[h]
2145 ctx = repo[h]
2146 if not ctx.closesbranch():
2146 if not ctx.closesbranch():
2147 labels.add(ctx.branch())
2147 labels.add(ctx.branch())
2148 completions = set()
2148 completions = set()
2149 if not args:
2149 if not args:
2150 args = ['']
2150 args = ['']
2151 for a in args:
2151 for a in args:
2152 completions.update(l for l in labels if l.startswith(a))
2152 completions.update(l for l in labels if l.startswith(a))
2153 ui.write('\n'.join(sorted(completions)))
2153 ui.write('\n'.join(sorted(completions)))
2154 ui.write('\n')
2154 ui.write('\n')
2155
2155
2156 @command('debugobsolete',
2156 @command('debugobsolete',
2157 [('', 'flags', 0, _('markers flag')),
2157 [('', 'flags', 0, _('markers flag')),
2158 ] + commitopts2,
2158 ] + commitopts2,
2159 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2159 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2160 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2160 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2161 """create arbitrary obsolete marker
2161 """create arbitrary obsolete marker
2162
2162
2163 With no arguments, displays the list of obsolescence markers."""
2163 With no arguments, displays the list of obsolescence markers."""
2164 def parsenodeid(s):
2164 def parsenodeid(s):
2165 try:
2165 try:
2166 # We do not use revsingle/revrange functions here to accept
2166 # We do not use revsingle/revrange functions here to accept
2167 # arbitrary node identifiers, possibly not present in the
2167 # arbitrary node identifiers, possibly not present in the
2168 # local repository.
2168 # local repository.
2169 n = bin(s)
2169 n = bin(s)
2170 if len(n) != len(nullid):
2170 if len(n) != len(nullid):
2171 raise TypeError()
2171 raise TypeError()
2172 return n
2172 return n
2173 except TypeError:
2173 except TypeError:
2174 raise util.Abort('changeset references must be full hexadecimal '
2174 raise util.Abort('changeset references must be full hexadecimal '
2175 'node identifiers')
2175 'node identifiers')
2176
2176
2177 if precursor is not None:
2177 if precursor is not None:
2178 metadata = {}
2178 metadata = {}
2179 if 'date' in opts:
2179 if 'date' in opts:
2180 metadata['date'] = opts['date']
2180 metadata['date'] = opts['date']
2181 metadata['user'] = opts['user'] or ui.username()
2181 metadata['user'] = opts['user'] or ui.username()
2182 succs = tuple(parsenodeid(succ) for succ in successors)
2182 succs = tuple(parsenodeid(succ) for succ in successors)
2183 l = repo.lock()
2183 l = repo.lock()
2184 try:
2184 try:
2185 tr = repo.transaction('debugobsolete')
2185 tr = repo.transaction('debugobsolete')
2186 try:
2186 try:
2187 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2187 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2188 opts['flags'], metadata)
2188 opts['flags'], metadata)
2189 tr.close()
2189 tr.close()
2190 finally:
2190 finally:
2191 tr.release()
2191 tr.release()
2192 finally:
2192 finally:
2193 l.release()
2193 l.release()
2194 else:
2194 else:
2195 for m in obsolete.allmarkers(repo):
2195 for m in obsolete.allmarkers(repo):
2196 ui.write(hex(m.precnode()))
2196 ui.write(hex(m.precnode()))
2197 for repl in m.succnodes():
2197 for repl in m.succnodes():
2198 ui.write(' ')
2198 ui.write(' ')
2199 ui.write(hex(repl))
2199 ui.write(hex(repl))
2200 ui.write(' %X ' % m._data[2])
2200 ui.write(' %X ' % m._data[2])
2201 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2201 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2202 sorted(m.metadata().items()))))
2202 sorted(m.metadata().items()))))
2203 ui.write('\n')
2203 ui.write('\n')
2204
2204
2205 @command('debugpathcomplete',
2205 @command('debugpathcomplete',
2206 [('f', 'full', None, _('complete an entire path')),
2206 [('f', 'full', None, _('complete an entire path')),
2207 ('n', 'normal', None, _('show only normal files')),
2207 ('n', 'normal', None, _('show only normal files')),
2208 ('a', 'added', None, _('show only added files')),
2208 ('a', 'added', None, _('show only added files')),
2209 ('r', 'removed', None, _('show only removed files'))],
2209 ('r', 'removed', None, _('show only removed files'))],
2210 _('FILESPEC...'))
2210 _('FILESPEC...'))
2211 def debugpathcomplete(ui, repo, *specs, **opts):
2211 def debugpathcomplete(ui, repo, *specs, **opts):
2212 '''complete part or all of a tracked path
2212 '''complete part or all of a tracked path
2213
2213
2214 This command supports shells that offer path name completion. It
2214 This command supports shells that offer path name completion. It
2215 currently completes only files already known to the dirstate.
2215 currently completes only files already known to the dirstate.
2216
2216
2217 Completion extends only to the next path segment unless
2217 Completion extends only to the next path segment unless
2218 --full is specified, in which case entire paths are used.'''
2218 --full is specified, in which case entire paths are used.'''
2219
2219
2220 def complete(path, acceptable):
2220 def complete(path, acceptable):
2221 dirstate = repo.dirstate
2221 dirstate = repo.dirstate
2222 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2222 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2223 rootdir = repo.root + os.sep
2223 rootdir = repo.root + os.sep
2224 if spec != repo.root and not spec.startswith(rootdir):
2224 if spec != repo.root and not spec.startswith(rootdir):
2225 return [], []
2225 return [], []
2226 if os.path.isdir(spec):
2226 if os.path.isdir(spec):
2227 spec += '/'
2227 spec += '/'
2228 spec = spec[len(rootdir):]
2228 spec = spec[len(rootdir):]
2229 fixpaths = os.sep != '/'
2229 fixpaths = os.sep != '/'
2230 if fixpaths:
2230 if fixpaths:
2231 spec = spec.replace(os.sep, '/')
2231 spec = spec.replace(os.sep, '/')
2232 speclen = len(spec)
2232 speclen = len(spec)
2233 fullpaths = opts['full']
2233 fullpaths = opts['full']
2234 files, dirs = set(), set()
2234 files, dirs = set(), set()
2235 adddir, addfile = dirs.add, files.add
2235 adddir, addfile = dirs.add, files.add
2236 for f, st in dirstate.iteritems():
2236 for f, st in dirstate.iteritems():
2237 if f.startswith(spec) and st[0] in acceptable:
2237 if f.startswith(spec) and st[0] in acceptable:
2238 if fixpaths:
2238 if fixpaths:
2239 f = f.replace('/', os.sep)
2239 f = f.replace('/', os.sep)
2240 if fullpaths:
2240 if fullpaths:
2241 addfile(f)
2241 addfile(f)
2242 continue
2242 continue
2243 s = f.find(os.sep, speclen)
2243 s = f.find(os.sep, speclen)
2244 if s >= 0:
2244 if s >= 0:
2245 adddir(f[:s + 1])
2245 adddir(f[:s + 1])
2246 else:
2246 else:
2247 addfile(f)
2247 addfile(f)
2248 return files, dirs
2248 return files, dirs
2249
2249
2250 acceptable = ''
2250 acceptable = ''
2251 if opts['normal']:
2251 if opts['normal']:
2252 acceptable += 'nm'
2252 acceptable += 'nm'
2253 if opts['added']:
2253 if opts['added']:
2254 acceptable += 'a'
2254 acceptable += 'a'
2255 if opts['removed']:
2255 if opts['removed']:
2256 acceptable += 'r'
2256 acceptable += 'r'
2257 cwd = repo.getcwd()
2257 cwd = repo.getcwd()
2258 if not specs:
2258 if not specs:
2259 specs = ['.']
2259 specs = ['.']
2260
2260
2261 files, dirs = set(), set()
2261 files, dirs = set(), set()
2262 for spec in specs:
2262 for spec in specs:
2263 f, d = complete(spec, acceptable or 'nmar')
2263 f, d = complete(spec, acceptable or 'nmar')
2264 files.update(f)
2264 files.update(f)
2265 dirs.update(d)
2265 dirs.update(d)
2266 if not files and len(dirs) == 1:
2266 if not files and len(dirs) == 1:
2267 # force the shell to consider a completion that matches one
2267 # force the shell to consider a completion that matches one
2268 # directory and zero files to be ambiguous
2268 # directory and zero files to be ambiguous
2269 dirs.add(iter(dirs).next() + '.')
2269 dirs.add(iter(dirs).next() + '.')
2270 files.update(dirs)
2270 files.update(dirs)
2271 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2271 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2272 ui.write('\n')
2272 ui.write('\n')
2273
2273
2274 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2274 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2275 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2275 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2276 '''access the pushkey key/value protocol
2276 '''access the pushkey key/value protocol
2277
2277
2278 With two args, list the keys in the given namespace.
2278 With two args, list the keys in the given namespace.
2279
2279
2280 With five args, set a key to new if it currently is set to old.
2280 With five args, set a key to new if it currently is set to old.
2281 Reports success or failure.
2281 Reports success or failure.
2282 '''
2282 '''
2283
2283
2284 target = hg.peer(ui, {}, repopath)
2284 target = hg.peer(ui, {}, repopath)
2285 if keyinfo:
2285 if keyinfo:
2286 key, old, new = keyinfo
2286 key, old, new = keyinfo
2287 r = target.pushkey(namespace, key, old, new)
2287 r = target.pushkey(namespace, key, old, new)
2288 ui.status(str(r) + '\n')
2288 ui.status(str(r) + '\n')
2289 return not r
2289 return not r
2290 else:
2290 else:
2291 for k, v in sorted(target.listkeys(namespace).iteritems()):
2291 for k, v in sorted(target.listkeys(namespace).iteritems()):
2292 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2292 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2293 v.encode('string-escape')))
2293 v.encode('string-escape')))
2294
2294
2295 @command('debugpvec', [], _('A B'))
2295 @command('debugpvec', [], _('A B'))
2296 def debugpvec(ui, repo, a, b=None):
2296 def debugpvec(ui, repo, a, b=None):
2297 ca = scmutil.revsingle(repo, a)
2297 ca = scmutil.revsingle(repo, a)
2298 cb = scmutil.revsingle(repo, b)
2298 cb = scmutil.revsingle(repo, b)
2299 pa = pvec.ctxpvec(ca)
2299 pa = pvec.ctxpvec(ca)
2300 pb = pvec.ctxpvec(cb)
2300 pb = pvec.ctxpvec(cb)
2301 if pa == pb:
2301 if pa == pb:
2302 rel = "="
2302 rel = "="
2303 elif pa > pb:
2303 elif pa > pb:
2304 rel = ">"
2304 rel = ">"
2305 elif pa < pb:
2305 elif pa < pb:
2306 rel = "<"
2306 rel = "<"
2307 elif pa | pb:
2307 elif pa | pb:
2308 rel = "|"
2308 rel = "|"
2309 ui.write(_("a: %s\n") % pa)
2309 ui.write(_("a: %s\n") % pa)
2310 ui.write(_("b: %s\n") % pb)
2310 ui.write(_("b: %s\n") % pb)
2311 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2311 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2312 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2312 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2313 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2313 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2314 pa.distance(pb), rel))
2314 pa.distance(pb), rel))
2315
2315
2316 @command('debugrebuilddirstate|debugrebuildstate',
2316 @command('debugrebuilddirstate|debugrebuildstate',
2317 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2317 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2318 _('[-r REV]'))
2318 _('[-r REV]'))
2319 def debugrebuilddirstate(ui, repo, rev):
2319 def debugrebuilddirstate(ui, repo, rev):
2320 """rebuild the dirstate as it would look like for the given revision
2320 """rebuild the dirstate as it would look like for the given revision
2321
2321
2322 If no revision is specified the first current parent will be used.
2322 If no revision is specified the first current parent will be used.
2323
2323
2324 The dirstate will be set to the files of the given revision.
2324 The dirstate will be set to the files of the given revision.
2325 The actual working directory content or existing dirstate
2325 The actual working directory content or existing dirstate
2326 information such as adds or removes is not considered.
2326 information such as adds or removes is not considered.
2327
2327
2328 One use of this command is to make the next :hg:`status` invocation
2328 One use of this command is to make the next :hg:`status` invocation
2329 check the actual file content.
2329 check the actual file content.
2330 """
2330 """
2331 ctx = scmutil.revsingle(repo, rev)
2331 ctx = scmutil.revsingle(repo, rev)
2332 wlock = repo.wlock()
2332 wlock = repo.wlock()
2333 try:
2333 try:
2334 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2334 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2335 finally:
2335 finally:
2336 wlock.release()
2336 wlock.release()
2337
2337
2338 @command('debugrename',
2338 @command('debugrename',
2339 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2339 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2340 _('[-r REV] FILE'))
2340 _('[-r REV] FILE'))
2341 def debugrename(ui, repo, file1, *pats, **opts):
2341 def debugrename(ui, repo, file1, *pats, **opts):
2342 """dump rename information"""
2342 """dump rename information"""
2343
2343
2344 ctx = scmutil.revsingle(repo, opts.get('rev'))
2344 ctx = scmutil.revsingle(repo, opts.get('rev'))
2345 m = scmutil.match(ctx, (file1,) + pats, opts)
2345 m = scmutil.match(ctx, (file1,) + pats, opts)
2346 for abs in ctx.walk(m):
2346 for abs in ctx.walk(m):
2347 fctx = ctx[abs]
2347 fctx = ctx[abs]
2348 o = fctx.filelog().renamed(fctx.filenode())
2348 o = fctx.filelog().renamed(fctx.filenode())
2349 rel = m.rel(abs)
2349 rel = m.rel(abs)
2350 if o:
2350 if o:
2351 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2351 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2352 else:
2352 else:
2353 ui.write(_("%s not renamed\n") % rel)
2353 ui.write(_("%s not renamed\n") % rel)
2354
2354
2355 @command('debugrevlog',
2355 @command('debugrevlog',
2356 [('c', 'changelog', False, _('open changelog')),
2356 [('c', 'changelog', False, _('open changelog')),
2357 ('m', 'manifest', False, _('open manifest')),
2357 ('m', 'manifest', False, _('open manifest')),
2358 ('d', 'dump', False, _('dump index data'))],
2358 ('d', 'dump', False, _('dump index data'))],
2359 _('-c|-m|FILE'))
2359 _('-c|-m|FILE'))
2360 def debugrevlog(ui, repo, file_=None, **opts):
2360 def debugrevlog(ui, repo, file_=None, **opts):
2361 """show data and statistics about a revlog"""
2361 """show data and statistics about a revlog"""
2362 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2362 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2363
2363
2364 if opts.get("dump"):
2364 if opts.get("dump"):
2365 numrevs = len(r)
2365 numrevs = len(r)
2366 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2366 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2367 " rawsize totalsize compression heads\n")
2367 " rawsize totalsize compression heads\n")
2368 ts = 0
2368 ts = 0
2369 heads = set()
2369 heads = set()
2370 for rev in xrange(numrevs):
2370 for rev in xrange(numrevs):
2371 dbase = r.deltaparent(rev)
2371 dbase = r.deltaparent(rev)
2372 if dbase == -1:
2372 if dbase == -1:
2373 dbase = rev
2373 dbase = rev
2374 cbase = r.chainbase(rev)
2374 cbase = r.chainbase(rev)
2375 p1, p2 = r.parentrevs(rev)
2375 p1, p2 = r.parentrevs(rev)
2376 rs = r.rawsize(rev)
2376 rs = r.rawsize(rev)
2377 ts = ts + rs
2377 ts = ts + rs
2378 heads -= set(r.parentrevs(rev))
2378 heads -= set(r.parentrevs(rev))
2379 heads.add(rev)
2379 heads.add(rev)
2380 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2380 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2381 (rev, p1, p2, r.start(rev), r.end(rev),
2381 (rev, p1, p2, r.start(rev), r.end(rev),
2382 r.start(dbase), r.start(cbase),
2382 r.start(dbase), r.start(cbase),
2383 r.start(p1), r.start(p2),
2383 r.start(p1), r.start(p2),
2384 rs, ts, ts / r.end(rev), len(heads)))
2384 rs, ts, ts / r.end(rev), len(heads)))
2385 return 0
2385 return 0
2386
2386
2387 v = r.version
2387 v = r.version
2388 format = v & 0xFFFF
2388 format = v & 0xFFFF
2389 flags = []
2389 flags = []
2390 gdelta = False
2390 gdelta = False
2391 if v & revlog.REVLOGNGINLINEDATA:
2391 if v & revlog.REVLOGNGINLINEDATA:
2392 flags.append('inline')
2392 flags.append('inline')
2393 if v & revlog.REVLOGGENERALDELTA:
2393 if v & revlog.REVLOGGENERALDELTA:
2394 gdelta = True
2394 gdelta = True
2395 flags.append('generaldelta')
2395 flags.append('generaldelta')
2396 if not flags:
2396 if not flags:
2397 flags = ['(none)']
2397 flags = ['(none)']
2398
2398
2399 nummerges = 0
2399 nummerges = 0
2400 numfull = 0
2400 numfull = 0
2401 numprev = 0
2401 numprev = 0
2402 nump1 = 0
2402 nump1 = 0
2403 nump2 = 0
2403 nump2 = 0
2404 numother = 0
2404 numother = 0
2405 nump1prev = 0
2405 nump1prev = 0
2406 nump2prev = 0
2406 nump2prev = 0
2407 chainlengths = []
2407 chainlengths = []
2408
2408
2409 datasize = [None, 0, 0L]
2409 datasize = [None, 0, 0L]
2410 fullsize = [None, 0, 0L]
2410 fullsize = [None, 0, 0L]
2411 deltasize = [None, 0, 0L]
2411 deltasize = [None, 0, 0L]
2412
2412
2413 def addsize(size, l):
2413 def addsize(size, l):
2414 if l[0] is None or size < l[0]:
2414 if l[0] is None or size < l[0]:
2415 l[0] = size
2415 l[0] = size
2416 if size > l[1]:
2416 if size > l[1]:
2417 l[1] = size
2417 l[1] = size
2418 l[2] += size
2418 l[2] += size
2419
2419
2420 numrevs = len(r)
2420 numrevs = len(r)
2421 for rev in xrange(numrevs):
2421 for rev in xrange(numrevs):
2422 p1, p2 = r.parentrevs(rev)
2422 p1, p2 = r.parentrevs(rev)
2423 delta = r.deltaparent(rev)
2423 delta = r.deltaparent(rev)
2424 if format > 0:
2424 if format > 0:
2425 addsize(r.rawsize(rev), datasize)
2425 addsize(r.rawsize(rev), datasize)
2426 if p2 != nullrev:
2426 if p2 != nullrev:
2427 nummerges += 1
2427 nummerges += 1
2428 size = r.length(rev)
2428 size = r.length(rev)
2429 if delta == nullrev:
2429 if delta == nullrev:
2430 chainlengths.append(0)
2430 chainlengths.append(0)
2431 numfull += 1
2431 numfull += 1
2432 addsize(size, fullsize)
2432 addsize(size, fullsize)
2433 else:
2433 else:
2434 chainlengths.append(chainlengths[delta] + 1)
2434 chainlengths.append(chainlengths[delta] + 1)
2435 addsize(size, deltasize)
2435 addsize(size, deltasize)
2436 if delta == rev - 1:
2436 if delta == rev - 1:
2437 numprev += 1
2437 numprev += 1
2438 if delta == p1:
2438 if delta == p1:
2439 nump1prev += 1
2439 nump1prev += 1
2440 elif delta == p2:
2440 elif delta == p2:
2441 nump2prev += 1
2441 nump2prev += 1
2442 elif delta == p1:
2442 elif delta == p1:
2443 nump1 += 1
2443 nump1 += 1
2444 elif delta == p2:
2444 elif delta == p2:
2445 nump2 += 1
2445 nump2 += 1
2446 elif delta != nullrev:
2446 elif delta != nullrev:
2447 numother += 1
2447 numother += 1
2448
2448
2449 # Adjust size min value for empty cases
2449 # Adjust size min value for empty cases
2450 for size in (datasize, fullsize, deltasize):
2450 for size in (datasize, fullsize, deltasize):
2451 if size[0] is None:
2451 if size[0] is None:
2452 size[0] = 0
2452 size[0] = 0
2453
2453
2454 numdeltas = numrevs - numfull
2454 numdeltas = numrevs - numfull
2455 numoprev = numprev - nump1prev - nump2prev
2455 numoprev = numprev - nump1prev - nump2prev
2456 totalrawsize = datasize[2]
2456 totalrawsize = datasize[2]
2457 datasize[2] /= numrevs
2457 datasize[2] /= numrevs
2458 fulltotal = fullsize[2]
2458 fulltotal = fullsize[2]
2459 fullsize[2] /= numfull
2459 fullsize[2] /= numfull
2460 deltatotal = deltasize[2]
2460 deltatotal = deltasize[2]
2461 if numrevs - numfull > 0:
2461 if numrevs - numfull > 0:
2462 deltasize[2] /= numrevs - numfull
2462 deltasize[2] /= numrevs - numfull
2463 totalsize = fulltotal + deltatotal
2463 totalsize = fulltotal + deltatotal
2464 avgchainlen = sum(chainlengths) / numrevs
2464 avgchainlen = sum(chainlengths) / numrevs
2465 compratio = totalrawsize / totalsize
2465 compratio = totalrawsize / totalsize
2466
2466
2467 basedfmtstr = '%%%dd\n'
2467 basedfmtstr = '%%%dd\n'
2468 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2468 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2469
2469
2470 def dfmtstr(max):
2470 def dfmtstr(max):
2471 return basedfmtstr % len(str(max))
2471 return basedfmtstr % len(str(max))
2472 def pcfmtstr(max, padding=0):
2472 def pcfmtstr(max, padding=0):
2473 return basepcfmtstr % (len(str(max)), ' ' * padding)
2473 return basepcfmtstr % (len(str(max)), ' ' * padding)
2474
2474
2475 def pcfmt(value, total):
2475 def pcfmt(value, total):
2476 return (value, 100 * float(value) / total)
2476 return (value, 100 * float(value) / total)
2477
2477
2478 ui.write(('format : %d\n') % format)
2478 ui.write(('format : %d\n') % format)
2479 ui.write(('flags : %s\n') % ', '.join(flags))
2479 ui.write(('flags : %s\n') % ', '.join(flags))
2480
2480
2481 ui.write('\n')
2481 ui.write('\n')
2482 fmt = pcfmtstr(totalsize)
2482 fmt = pcfmtstr(totalsize)
2483 fmt2 = dfmtstr(totalsize)
2483 fmt2 = dfmtstr(totalsize)
2484 ui.write(('revisions : ') + fmt2 % numrevs)
2484 ui.write(('revisions : ') + fmt2 % numrevs)
2485 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2485 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2486 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2486 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2487 ui.write(('revisions : ') + fmt2 % numrevs)
2487 ui.write(('revisions : ') + fmt2 % numrevs)
2488 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2488 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2489 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2489 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2490 ui.write(('revision size : ') + fmt2 % totalsize)
2490 ui.write(('revision size : ') + fmt2 % totalsize)
2491 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2491 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2492 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2492 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2493
2493
2494 ui.write('\n')
2494 ui.write('\n')
2495 fmt = dfmtstr(max(avgchainlen, compratio))
2495 fmt = dfmtstr(max(avgchainlen, compratio))
2496 ui.write(('avg chain length : ') + fmt % avgchainlen)
2496 ui.write(('avg chain length : ') + fmt % avgchainlen)
2497 ui.write(('compression ratio : ') + fmt % compratio)
2497 ui.write(('compression ratio : ') + fmt % compratio)
2498
2498
2499 if format > 0:
2499 if format > 0:
2500 ui.write('\n')
2500 ui.write('\n')
2501 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2501 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2502 % tuple(datasize))
2502 % tuple(datasize))
2503 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2503 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2504 % tuple(fullsize))
2504 % tuple(fullsize))
2505 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2505 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2506 % tuple(deltasize))
2506 % tuple(deltasize))
2507
2507
2508 if numdeltas > 0:
2508 if numdeltas > 0:
2509 ui.write('\n')
2509 ui.write('\n')
2510 fmt = pcfmtstr(numdeltas)
2510 fmt = pcfmtstr(numdeltas)
2511 fmt2 = pcfmtstr(numdeltas, 4)
2511 fmt2 = pcfmtstr(numdeltas, 4)
2512 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2512 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2513 if numprev > 0:
2513 if numprev > 0:
2514 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2514 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2515 numprev))
2515 numprev))
2516 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2516 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2517 numprev))
2517 numprev))
2518 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2518 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2519 numprev))
2519 numprev))
2520 if gdelta:
2520 if gdelta:
2521 ui.write(('deltas against p1 : ')
2521 ui.write(('deltas against p1 : ')
2522 + fmt % pcfmt(nump1, numdeltas))
2522 + fmt % pcfmt(nump1, numdeltas))
2523 ui.write(('deltas against p2 : ')
2523 ui.write(('deltas against p2 : ')
2524 + fmt % pcfmt(nump2, numdeltas))
2524 + fmt % pcfmt(nump2, numdeltas))
2525 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2525 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2526 numdeltas))
2526 numdeltas))
2527
2527
2528 @command('debugrevspec', [], ('REVSPEC'))
2528 @command('debugrevspec', [], ('REVSPEC'))
2529 def debugrevspec(ui, repo, expr):
2529 def debugrevspec(ui, repo, expr):
2530 """parse and apply a revision specification
2530 """parse and apply a revision specification
2531
2531
2532 Use --verbose to print the parsed tree before and after aliases
2532 Use --verbose to print the parsed tree before and after aliases
2533 expansion.
2533 expansion.
2534 """
2534 """
2535 if ui.verbose:
2535 if ui.verbose:
2536 tree = revset.parse(expr)[0]
2536 tree = revset.parse(expr)[0]
2537 ui.note(revset.prettyformat(tree), "\n")
2537 ui.note(revset.prettyformat(tree), "\n")
2538 newtree = revset.findaliases(ui, tree)
2538 newtree = revset.findaliases(ui, tree)
2539 if newtree != tree:
2539 if newtree != tree:
2540 ui.note(revset.prettyformat(newtree), "\n")
2540 ui.note(revset.prettyformat(newtree), "\n")
2541 func = revset.match(ui, expr)
2541 func = revset.match(ui, expr)
2542 for c in func(repo, range(len(repo))):
2542 for c in func(repo, range(len(repo))):
2543 ui.write("%s\n" % c)
2543 ui.write("%s\n" % c)
2544
2544
2545 @command('debugsetparents', [], _('REV1 [REV2]'))
2545 @command('debugsetparents', [], _('REV1 [REV2]'))
2546 def debugsetparents(ui, repo, rev1, rev2=None):
2546 def debugsetparents(ui, repo, rev1, rev2=None):
2547 """manually set the parents of the current working directory
2547 """manually set the parents of the current working directory
2548
2548
2549 This is useful for writing repository conversion tools, but should
2549 This is useful for writing repository conversion tools, but should
2550 be used with care.
2550 be used with care.
2551
2551
2552 Returns 0 on success.
2552 Returns 0 on success.
2553 """
2553 """
2554
2554
2555 r1 = scmutil.revsingle(repo, rev1).node()
2555 r1 = scmutil.revsingle(repo, rev1).node()
2556 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2556 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2557
2557
2558 wlock = repo.wlock()
2558 wlock = repo.wlock()
2559 try:
2559 try:
2560 repo.setparents(r1, r2)
2560 repo.setparents(r1, r2)
2561 finally:
2561 finally:
2562 wlock.release()
2562 wlock.release()
2563
2563
2564 @command('debugdirstate|debugstate',
2564 @command('debugdirstate|debugstate',
2565 [('', 'nodates', None, _('do not display the saved mtime')),
2565 [('', 'nodates', None, _('do not display the saved mtime')),
2566 ('', 'datesort', None, _('sort by saved mtime'))],
2566 ('', 'datesort', None, _('sort by saved mtime'))],
2567 _('[OPTION]...'))
2567 _('[OPTION]...'))
2568 def debugstate(ui, repo, nodates=None, datesort=None):
2568 def debugstate(ui, repo, nodates=None, datesort=None):
2569 """show the contents of the current dirstate"""
2569 """show the contents of the current dirstate"""
2570 timestr = ""
2570 timestr = ""
2571 showdate = not nodates
2571 showdate = not nodates
2572 if datesort:
2572 if datesort:
2573 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2573 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2574 else:
2574 else:
2575 keyfunc = None # sort by filename
2575 keyfunc = None # sort by filename
2576 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2576 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2577 if showdate:
2577 if showdate:
2578 if ent[3] == -1:
2578 if ent[3] == -1:
2579 # Pad or slice to locale representation
2579 # Pad or slice to locale representation
2580 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2580 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2581 time.localtime(0)))
2581 time.localtime(0)))
2582 timestr = 'unset'
2582 timestr = 'unset'
2583 timestr = (timestr[:locale_len] +
2583 timestr = (timestr[:locale_len] +
2584 ' ' * (locale_len - len(timestr)))
2584 ' ' * (locale_len - len(timestr)))
2585 else:
2585 else:
2586 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2586 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2587 time.localtime(ent[3]))
2587 time.localtime(ent[3]))
2588 if ent[1] & 020000:
2588 if ent[1] & 020000:
2589 mode = 'lnk'
2589 mode = 'lnk'
2590 else:
2590 else:
2591 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2591 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2592 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2592 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2593 for f in repo.dirstate.copies():
2593 for f in repo.dirstate.copies():
2594 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2594 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2595
2595
2596 @command('debugsub',
2596 @command('debugsub',
2597 [('r', 'rev', '',
2597 [('r', 'rev', '',
2598 _('revision to check'), _('REV'))],
2598 _('revision to check'), _('REV'))],
2599 _('[-r REV] [REV]'))
2599 _('[-r REV] [REV]'))
2600 def debugsub(ui, repo, rev=None):
2600 def debugsub(ui, repo, rev=None):
2601 ctx = scmutil.revsingle(repo, rev, None)
2601 ctx = scmutil.revsingle(repo, rev, None)
2602 for k, v in sorted(ctx.substate.items()):
2602 for k, v in sorted(ctx.substate.items()):
2603 ui.write(('path %s\n') % k)
2603 ui.write(('path %s\n') % k)
2604 ui.write((' source %s\n') % v[0])
2604 ui.write((' source %s\n') % v[0])
2605 ui.write((' revision %s\n') % v[1])
2605 ui.write((' revision %s\n') % v[1])
2606
2606
2607 @command('debugsuccessorssets',
2607 @command('debugsuccessorssets',
2608 [],
2608 [],
2609 _('[REV]'))
2609 _('[REV]'))
2610 def debugsuccessorssets(ui, repo, *revs):
2610 def debugsuccessorssets(ui, repo, *revs):
2611 """show set of successors for revision
2611 """show set of successors for revision
2612
2612
2613 A successors set of changeset A is a consistent group of revisions that
2613 A successors set of changeset A is a consistent group of revisions that
2614 succeed A. It contains non-obsolete changesets only.
2614 succeed A. It contains non-obsolete changesets only.
2615
2615
2616 In most cases a changeset A has a single successors set containing a single
2616 In most cases a changeset A has a single successors set containing a single
2617 successor (changeset A replaced by A').
2617 successor (changeset A replaced by A').
2618
2618
2619 A changeset that is made obsolete with no successors are called "pruned".
2619 A changeset that is made obsolete with no successors are called "pruned".
2620 Such changesets have no successors sets at all.
2620 Such changesets have no successors sets at all.
2621
2621
2622 A changeset that has been "split" will have a successors set containing
2622 A changeset that has been "split" will have a successors set containing
2623 more than one successor.
2623 more than one successor.
2624
2624
2625 A changeset that has been rewritten in multiple different ways is called
2625 A changeset that has been rewritten in multiple different ways is called
2626 "divergent". Such changesets have multiple successor sets (each of which
2626 "divergent". Such changesets have multiple successor sets (each of which
2627 may also be split, i.e. have multiple successors).
2627 may also be split, i.e. have multiple successors).
2628
2628
2629 Results are displayed as follows::
2629 Results are displayed as follows::
2630
2630
2631 <rev1>
2631 <rev1>
2632 <successors-1A>
2632 <successors-1A>
2633 <rev2>
2633 <rev2>
2634 <successors-2A>
2634 <successors-2A>
2635 <successors-2B1> <successors-2B2> <successors-2B3>
2635 <successors-2B1> <successors-2B2> <successors-2B3>
2636
2636
2637 Here rev2 has two possible (i.e. divergent) successors sets. The first
2637 Here rev2 has two possible (i.e. divergent) successors sets. The first
2638 holds one element, whereas the second holds three (i.e. the changeset has
2638 holds one element, whereas the second holds three (i.e. the changeset has
2639 been split).
2639 been split).
2640 """
2640 """
2641 # passed to successorssets caching computation from one call to another
2641 # passed to successorssets caching computation from one call to another
2642 cache = {}
2642 cache = {}
2643 ctx2str = str
2643 ctx2str = str
2644 node2str = short
2644 node2str = short
2645 if ui.debug():
2645 if ui.debug():
2646 def ctx2str(ctx):
2646 def ctx2str(ctx):
2647 return ctx.hex()
2647 return ctx.hex()
2648 node2str = hex
2648 node2str = hex
2649 for rev in scmutil.revrange(repo, revs):
2649 for rev in scmutil.revrange(repo, revs):
2650 ctx = repo[rev]
2650 ctx = repo[rev]
2651 ui.write('%s\n'% ctx2str(ctx))
2651 ui.write('%s\n'% ctx2str(ctx))
2652 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2652 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2653 if succsset:
2653 if succsset:
2654 ui.write(' ')
2654 ui.write(' ')
2655 ui.write(node2str(succsset[0]))
2655 ui.write(node2str(succsset[0]))
2656 for node in succsset[1:]:
2656 for node in succsset[1:]:
2657 ui.write(' ')
2657 ui.write(' ')
2658 ui.write(node2str(node))
2658 ui.write(node2str(node))
2659 ui.write('\n')
2659 ui.write('\n')
2660
2660
2661 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2661 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2662 def debugwalk(ui, repo, *pats, **opts):
2662 def debugwalk(ui, repo, *pats, **opts):
2663 """show how files match on given patterns"""
2663 """show how files match on given patterns"""
2664 m = scmutil.match(repo[None], pats, opts)
2664 m = scmutil.match(repo[None], pats, opts)
2665 items = list(repo.walk(m))
2665 items = list(repo.walk(m))
2666 if not items:
2666 if not items:
2667 return
2667 return
2668 f = lambda fn: fn
2668 f = lambda fn: fn
2669 if ui.configbool('ui', 'slash') and os.sep != '/':
2669 if ui.configbool('ui', 'slash') and os.sep != '/':
2670 f = lambda fn: util.normpath(fn)
2670 f = lambda fn: util.normpath(fn)
2671 fmt = 'f %%-%ds %%-%ds %%s' % (
2671 fmt = 'f %%-%ds %%-%ds %%s' % (
2672 max([len(abs) for abs in items]),
2672 max([len(abs) for abs in items]),
2673 max([len(m.rel(abs)) for abs in items]))
2673 max([len(m.rel(abs)) for abs in items]))
2674 for abs in items:
2674 for abs in items:
2675 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2675 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2676 ui.write("%s\n" % line.rstrip())
2676 ui.write("%s\n" % line.rstrip())
2677
2677
2678 @command('debugwireargs',
2678 @command('debugwireargs',
2679 [('', 'three', '', 'three'),
2679 [('', 'three', '', 'three'),
2680 ('', 'four', '', 'four'),
2680 ('', 'four', '', 'four'),
2681 ('', 'five', '', 'five'),
2681 ('', 'five', '', 'five'),
2682 ] + remoteopts,
2682 ] + remoteopts,
2683 _('REPO [OPTIONS]... [ONE [TWO]]'))
2683 _('REPO [OPTIONS]... [ONE [TWO]]'))
2684 def debugwireargs(ui, repopath, *vals, **opts):
2684 def debugwireargs(ui, repopath, *vals, **opts):
2685 repo = hg.peer(ui, opts, repopath)
2685 repo = hg.peer(ui, opts, repopath)
2686 for opt in remoteopts:
2686 for opt in remoteopts:
2687 del opts[opt[1]]
2687 del opts[opt[1]]
2688 args = {}
2688 args = {}
2689 for k, v in opts.iteritems():
2689 for k, v in opts.iteritems():
2690 if v:
2690 if v:
2691 args[k] = v
2691 args[k] = v
2692 # run twice to check that we don't mess up the stream for the next command
2692 # run twice to check that we don't mess up the stream for the next command
2693 res1 = repo.debugwireargs(*vals, **args)
2693 res1 = repo.debugwireargs(*vals, **args)
2694 res2 = repo.debugwireargs(*vals, **args)
2694 res2 = repo.debugwireargs(*vals, **args)
2695 ui.write("%s\n" % res1)
2695 ui.write("%s\n" % res1)
2696 if res1 != res2:
2696 if res1 != res2:
2697 ui.warn("%s\n" % res2)
2697 ui.warn("%s\n" % res2)
2698
2698
2699 @command('^diff',
2699 @command('^diff',
2700 [('r', 'rev', [], _('revision'), _('REV')),
2700 [('r', 'rev', [], _('revision'), _('REV')),
2701 ('c', 'change', '', _('change made by revision'), _('REV'))
2701 ('c', 'change', '', _('change made by revision'), _('REV'))
2702 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2702 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2703 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2703 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2704 def diff(ui, repo, *pats, **opts):
2704 def diff(ui, repo, *pats, **opts):
2705 """diff repository (or selected files)
2705 """diff repository (or selected files)
2706
2706
2707 Show differences between revisions for the specified files.
2707 Show differences between revisions for the specified files.
2708
2708
2709 Differences between files are shown using the unified diff format.
2709 Differences between files are shown using the unified diff format.
2710
2710
2711 .. note::
2711 .. note::
2712
2712
2713 diff may generate unexpected results for merges, as it will
2713 diff may generate unexpected results for merges, as it will
2714 default to comparing against the working directory's first
2714 default to comparing against the working directory's first
2715 parent changeset if no revisions are specified.
2715 parent changeset if no revisions are specified.
2716
2716
2717 When two revision arguments are given, then changes are shown
2717 When two revision arguments are given, then changes are shown
2718 between those revisions. If only one revision is specified then
2718 between those revisions. If only one revision is specified then
2719 that revision is compared to the working directory, and, when no
2719 that revision is compared to the working directory, and, when no
2720 revisions are specified, the working directory files are compared
2720 revisions are specified, the working directory files are compared
2721 to its parent.
2721 to its parent.
2722
2722
2723 Alternatively you can specify -c/--change with a revision to see
2723 Alternatively you can specify -c/--change with a revision to see
2724 the changes in that changeset relative to its first parent.
2724 the changes in that changeset relative to its first parent.
2725
2725
2726 Without the -a/--text option, diff will avoid generating diffs of
2726 Without the -a/--text option, diff will avoid generating diffs of
2727 files it detects as binary. With -a, diff will generate a diff
2727 files it detects as binary. With -a, diff will generate a diff
2728 anyway, probably with undesirable results.
2728 anyway, probably with undesirable results.
2729
2729
2730 Use the -g/--git option to generate diffs in the git extended diff
2730 Use the -g/--git option to generate diffs in the git extended diff
2731 format. For more information, read :hg:`help diffs`.
2731 format. For more information, read :hg:`help diffs`.
2732
2732
2733 .. container:: verbose
2733 .. container:: verbose
2734
2734
2735 Examples:
2735 Examples:
2736
2736
2737 - compare a file in the current working directory to its parent::
2737 - compare a file in the current working directory to its parent::
2738
2738
2739 hg diff foo.c
2739 hg diff foo.c
2740
2740
2741 - compare two historical versions of a directory, with rename info::
2741 - compare two historical versions of a directory, with rename info::
2742
2742
2743 hg diff --git -r 1.0:1.2 lib/
2743 hg diff --git -r 1.0:1.2 lib/
2744
2744
2745 - get change stats relative to the last change on some date::
2745 - get change stats relative to the last change on some date::
2746
2746
2747 hg diff --stat -r "date('may 2')"
2747 hg diff --stat -r "date('may 2')"
2748
2748
2749 - diff all newly-added files that contain a keyword::
2749 - diff all newly-added files that contain a keyword::
2750
2750
2751 hg diff "set:added() and grep(GNU)"
2751 hg diff "set:added() and grep(GNU)"
2752
2752
2753 - compare a revision and its parents::
2753 - compare a revision and its parents::
2754
2754
2755 hg diff -c 9353 # compare against first parent
2755 hg diff -c 9353 # compare against first parent
2756 hg diff -r 9353^:9353 # same using revset syntax
2756 hg diff -r 9353^:9353 # same using revset syntax
2757 hg diff -r 9353^2:9353 # compare against the second parent
2757 hg diff -r 9353^2:9353 # compare against the second parent
2758
2758
2759 Returns 0 on success.
2759 Returns 0 on success.
2760 """
2760 """
2761
2761
2762 revs = opts.get('rev')
2762 revs = opts.get('rev')
2763 change = opts.get('change')
2763 change = opts.get('change')
2764 stat = opts.get('stat')
2764 stat = opts.get('stat')
2765 reverse = opts.get('reverse')
2765 reverse = opts.get('reverse')
2766
2766
2767 if revs and change:
2767 if revs and change:
2768 msg = _('cannot specify --rev and --change at the same time')
2768 msg = _('cannot specify --rev and --change at the same time')
2769 raise util.Abort(msg)
2769 raise util.Abort(msg)
2770 elif change:
2770 elif change:
2771 node2 = scmutil.revsingle(repo, change, None).node()
2771 node2 = scmutil.revsingle(repo, change, None).node()
2772 node1 = repo[node2].p1().node()
2772 node1 = repo[node2].p1().node()
2773 else:
2773 else:
2774 node1, node2 = scmutil.revpair(repo, revs)
2774 node1, node2 = scmutil.revpair(repo, revs)
2775
2775
2776 if reverse:
2776 if reverse:
2777 node1, node2 = node2, node1
2777 node1, node2 = node2, node1
2778
2778
2779 diffopts = patch.diffopts(ui, opts)
2779 diffopts = patch.diffopts(ui, opts)
2780 m = scmutil.match(repo[node2], pats, opts)
2780 m = scmutil.match(repo[node2], pats, opts)
2781 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2781 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2782 listsubrepos=opts.get('subrepos'))
2782 listsubrepos=opts.get('subrepos'))
2783
2783
2784 @command('^export',
2784 @command('^export',
2785 [('o', 'output', '',
2785 [('o', 'output', '',
2786 _('print output to file with formatted name'), _('FORMAT')),
2786 _('print output to file with formatted name'), _('FORMAT')),
2787 ('', 'switch-parent', None, _('diff against the second parent')),
2787 ('', 'switch-parent', None, _('diff against the second parent')),
2788 ('r', 'rev', [], _('revisions to export'), _('REV')),
2788 ('r', 'rev', [], _('revisions to export'), _('REV')),
2789 ] + diffopts,
2789 ] + diffopts,
2790 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2790 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2791 def export(ui, repo, *changesets, **opts):
2791 def export(ui, repo, *changesets, **opts):
2792 """dump the header and diffs for one or more changesets
2792 """dump the header and diffs for one or more changesets
2793
2793
2794 Print the changeset header and diffs for one or more revisions.
2794 Print the changeset header and diffs for one or more revisions.
2795 If no revision is given, the parent of the working directory is used.
2795 If no revision is given, the parent of the working directory is used.
2796
2796
2797 The information shown in the changeset header is: author, date,
2797 The information shown in the changeset header is: author, date,
2798 branch name (if non-default), changeset hash, parent(s) and commit
2798 branch name (if non-default), changeset hash, parent(s) and commit
2799 comment.
2799 comment.
2800
2800
2801 .. note::
2801 .. note::
2802
2802
2803 export may generate unexpected diff output for merge
2803 export may generate unexpected diff output for merge
2804 changesets, as it will compare the merge changeset against its
2804 changesets, as it will compare the merge changeset against its
2805 first parent only.
2805 first parent only.
2806
2806
2807 Output may be to a file, in which case the name of the file is
2807 Output may be to a file, in which case the name of the file is
2808 given using a format string. The formatting rules are as follows:
2808 given using a format string. The formatting rules are as follows:
2809
2809
2810 :``%%``: literal "%" character
2810 :``%%``: literal "%" character
2811 :``%H``: changeset hash (40 hexadecimal digits)
2811 :``%H``: changeset hash (40 hexadecimal digits)
2812 :``%N``: number of patches being generated
2812 :``%N``: number of patches being generated
2813 :``%R``: changeset revision number
2813 :``%R``: changeset revision number
2814 :``%b``: basename of the exporting repository
2814 :``%b``: basename of the exporting repository
2815 :``%h``: short-form changeset hash (12 hexadecimal digits)
2815 :``%h``: short-form changeset hash (12 hexadecimal digits)
2816 :``%m``: first line of the commit message (only alphanumeric characters)
2816 :``%m``: first line of the commit message (only alphanumeric characters)
2817 :``%n``: zero-padded sequence number, starting at 1
2817 :``%n``: zero-padded sequence number, starting at 1
2818 :``%r``: zero-padded changeset revision number
2818 :``%r``: zero-padded changeset revision number
2819
2819
2820 Without the -a/--text option, export will avoid generating diffs
2820 Without the -a/--text option, export will avoid generating diffs
2821 of files it detects as binary. With -a, export will generate a
2821 of files it detects as binary. With -a, export will generate a
2822 diff anyway, probably with undesirable results.
2822 diff anyway, probably with undesirable results.
2823
2823
2824 Use the -g/--git option to generate diffs in the git extended diff
2824 Use the -g/--git option to generate diffs in the git extended diff
2825 format. See :hg:`help diffs` for more information.
2825 format. See :hg:`help diffs` for more information.
2826
2826
2827 With the --switch-parent option, the diff will be against the
2827 With the --switch-parent option, the diff will be against the
2828 second parent. It can be useful to review a merge.
2828 second parent. It can be useful to review a merge.
2829
2829
2830 .. container:: verbose
2830 .. container:: verbose
2831
2831
2832 Examples:
2832 Examples:
2833
2833
2834 - use export and import to transplant a bugfix to the current
2834 - use export and import to transplant a bugfix to the current
2835 branch::
2835 branch::
2836
2836
2837 hg export -r 9353 | hg import -
2837 hg export -r 9353 | hg import -
2838
2838
2839 - export all the changesets between two revisions to a file with
2839 - export all the changesets between two revisions to a file with
2840 rename information::
2840 rename information::
2841
2841
2842 hg export --git -r 123:150 > changes.txt
2842 hg export --git -r 123:150 > changes.txt
2843
2843
2844 - split outgoing changes into a series of patches with
2844 - split outgoing changes into a series of patches with
2845 descriptive names::
2845 descriptive names::
2846
2846
2847 hg export -r "outgoing()" -o "%n-%m.patch"
2847 hg export -r "outgoing()" -o "%n-%m.patch"
2848
2848
2849 Returns 0 on success.
2849 Returns 0 on success.
2850 """
2850 """
2851 changesets += tuple(opts.get('rev', []))
2851 changesets += tuple(opts.get('rev', []))
2852 if not changesets:
2852 if not changesets:
2853 changesets = ['.']
2853 changesets = ['.']
2854 revs = scmutil.revrange(repo, changesets)
2854 revs = scmutil.revrange(repo, changesets)
2855 if not revs:
2855 if not revs:
2856 raise util.Abort(_("export requires at least one changeset"))
2856 raise util.Abort(_("export requires at least one changeset"))
2857 if len(revs) > 1:
2857 if len(revs) > 1:
2858 ui.note(_('exporting patches:\n'))
2858 ui.note(_('exporting patches:\n'))
2859 else:
2859 else:
2860 ui.note(_('exporting patch:\n'))
2860 ui.note(_('exporting patch:\n'))
2861 cmdutil.export(repo, revs, template=opts.get('output'),
2861 cmdutil.export(repo, revs, template=opts.get('output'),
2862 switch_parent=opts.get('switch_parent'),
2862 switch_parent=opts.get('switch_parent'),
2863 opts=patch.diffopts(ui, opts))
2863 opts=patch.diffopts(ui, opts))
2864
2864
2865 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2865 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2866 def forget(ui, repo, *pats, **opts):
2866 def forget(ui, repo, *pats, **opts):
2867 """forget the specified files on the next commit
2867 """forget the specified files on the next commit
2868
2868
2869 Mark the specified files so they will no longer be tracked
2869 Mark the specified files so they will no longer be tracked
2870 after the next commit.
2870 after the next commit.
2871
2871
2872 This only removes files from the current branch, not from the
2872 This only removes files from the current branch, not from the
2873 entire project history, and it does not delete them from the
2873 entire project history, and it does not delete them from the
2874 working directory.
2874 working directory.
2875
2875
2876 To undo a forget before the next commit, see :hg:`add`.
2876 To undo a forget before the next commit, see :hg:`add`.
2877
2877
2878 .. container:: verbose
2878 .. container:: verbose
2879
2879
2880 Examples:
2880 Examples:
2881
2881
2882 - forget newly-added binary files::
2882 - forget newly-added binary files::
2883
2883
2884 hg forget "set:added() and binary()"
2884 hg forget "set:added() and binary()"
2885
2885
2886 - forget files that would be excluded by .hgignore::
2886 - forget files that would be excluded by .hgignore::
2887
2887
2888 hg forget "set:hgignore()"
2888 hg forget "set:hgignore()"
2889
2889
2890 Returns 0 on success.
2890 Returns 0 on success.
2891 """
2891 """
2892
2892
2893 if not pats:
2893 if not pats:
2894 raise util.Abort(_('no files specified'))
2894 raise util.Abort(_('no files specified'))
2895
2895
2896 m = scmutil.match(repo[None], pats, opts)
2896 m = scmutil.match(repo[None], pats, opts)
2897 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2897 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2898 return rejected and 1 or 0
2898 return rejected and 1 or 0
2899
2899
2900 @command(
2900 @command(
2901 'graft',
2901 'graft',
2902 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2902 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2903 ('c', 'continue', False, _('resume interrupted graft')),
2903 ('c', 'continue', False, _('resume interrupted graft')),
2904 ('e', 'edit', False, _('invoke editor on commit messages')),
2904 ('e', 'edit', False, _('invoke editor on commit messages')),
2905 ('', 'log', None, _('append graft info to log message')),
2905 ('', 'log', None, _('append graft info to log message')),
2906 ('D', 'currentdate', False,
2906 ('D', 'currentdate', False,
2907 _('record the current date as commit date')),
2907 _('record the current date as commit date')),
2908 ('U', 'currentuser', False,
2908 ('U', 'currentuser', False,
2909 _('record the current user as committer'), _('DATE'))]
2909 _('record the current user as committer'), _('DATE'))]
2910 + commitopts2 + mergetoolopts + dryrunopts,
2910 + commitopts2 + mergetoolopts + dryrunopts,
2911 _('[OPTION]... [-r] REV...'))
2911 _('[OPTION]... [-r] REV...'))
2912 def graft(ui, repo, *revs, **opts):
2912 def graft(ui, repo, *revs, **opts):
2913 '''copy changes from other branches onto the current branch
2913 '''copy changes from other branches onto the current branch
2914
2914
2915 This command uses Mercurial's merge logic to copy individual
2915 This command uses Mercurial's merge logic to copy individual
2916 changes from other branches without merging branches in the
2916 changes from other branches without merging branches in the
2917 history graph. This is sometimes known as 'backporting' or
2917 history graph. This is sometimes known as 'backporting' or
2918 'cherry-picking'. By default, graft will copy user, date, and
2918 'cherry-picking'. By default, graft will copy user, date, and
2919 description from the source changesets.
2919 description from the source changesets.
2920
2920
2921 Changesets that are ancestors of the current revision, that have
2921 Changesets that are ancestors of the current revision, that have
2922 already been grafted, or that are merges will be skipped.
2922 already been grafted, or that are merges will be skipped.
2923
2923
2924 If --log is specified, log messages will have a comment appended
2924 If --log is specified, log messages will have a comment appended
2925 of the form::
2925 of the form::
2926
2926
2927 (grafted from CHANGESETHASH)
2927 (grafted from CHANGESETHASH)
2928
2928
2929 If a graft merge results in conflicts, the graft process is
2929 If a graft merge results in conflicts, the graft process is
2930 interrupted so that the current merge can be manually resolved.
2930 interrupted so that the current merge can be manually resolved.
2931 Once all conflicts are addressed, the graft process can be
2931 Once all conflicts are addressed, the graft process can be
2932 continued with the -c/--continue option.
2932 continued with the -c/--continue option.
2933
2933
2934 .. note::
2934 .. note::
2935
2935
2936 The -c/--continue option does not reapply earlier options.
2936 The -c/--continue option does not reapply earlier options.
2937
2937
2938 .. container:: verbose
2938 .. container:: verbose
2939
2939
2940 Examples:
2940 Examples:
2941
2941
2942 - copy a single change to the stable branch and edit its description::
2942 - copy a single change to the stable branch and edit its description::
2943
2943
2944 hg update stable
2944 hg update stable
2945 hg graft --edit 9393
2945 hg graft --edit 9393
2946
2946
2947 - graft a range of changesets with one exception, updating dates::
2947 - graft a range of changesets with one exception, updating dates::
2948
2948
2949 hg graft -D "2085::2093 and not 2091"
2949 hg graft -D "2085::2093 and not 2091"
2950
2950
2951 - continue a graft after resolving conflicts::
2951 - continue a graft after resolving conflicts::
2952
2952
2953 hg graft -c
2953 hg graft -c
2954
2954
2955 - show the source of a grafted changeset::
2955 - show the source of a grafted changeset::
2956
2956
2957 hg log --debug -r .
2957 hg log --debug -r .
2958
2958
2959 Returns 0 on successful completion.
2959 Returns 0 on successful completion.
2960 '''
2960 '''
2961
2961
2962 revs = list(revs)
2962 revs = list(revs)
2963 revs.extend(opts['rev'])
2963 revs.extend(opts['rev'])
2964
2964
2965 if not opts.get('user') and opts.get('currentuser'):
2965 if not opts.get('user') and opts.get('currentuser'):
2966 opts['user'] = ui.username()
2966 opts['user'] = ui.username()
2967 if not opts.get('date') and opts.get('currentdate'):
2967 if not opts.get('date') and opts.get('currentdate'):
2968 opts['date'] = "%d %d" % util.makedate()
2968 opts['date'] = "%d %d" % util.makedate()
2969
2969
2970 editor = None
2970 editor = None
2971 if opts.get('edit'):
2971 if opts.get('edit'):
2972 editor = cmdutil.commitforceeditor
2972 editor = cmdutil.commitforceeditor
2973
2973
2974 cont = False
2974 cont = False
2975 if opts['continue']:
2975 if opts['continue']:
2976 cont = True
2976 cont = True
2977 if revs:
2977 if revs:
2978 raise util.Abort(_("can't specify --continue and revisions"))
2978 raise util.Abort(_("can't specify --continue and revisions"))
2979 # read in unfinished revisions
2979 # read in unfinished revisions
2980 try:
2980 try:
2981 nodes = repo.opener.read('graftstate').splitlines()
2981 nodes = repo.opener.read('graftstate').splitlines()
2982 revs = [repo[node].rev() for node in nodes]
2982 revs = [repo[node].rev() for node in nodes]
2983 except IOError, inst:
2983 except IOError, inst:
2984 if inst.errno != errno.ENOENT:
2984 if inst.errno != errno.ENOENT:
2985 raise
2985 raise
2986 raise util.Abort(_("no graft state found, can't continue"))
2986 raise util.Abort(_("no graft state found, can't continue"))
2987 else:
2987 else:
2988 cmdutil.checkunfinished(repo)
2988 cmdutil.checkunfinished(repo)
2989 cmdutil.bailifchanged(repo)
2989 cmdutil.bailifchanged(repo)
2990 if not revs:
2990 if not revs:
2991 raise util.Abort(_('no revisions specified'))
2991 raise util.Abort(_('no revisions specified'))
2992 revs = scmutil.revrange(repo, revs)
2992 revs = scmutil.revrange(repo, revs)
2993
2993
2994 # check for merges
2994 # check for merges
2995 for rev in repo.revs('%ld and merge()', revs):
2995 for rev in repo.revs('%ld and merge()', revs):
2996 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2996 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2997 revs.remove(rev)
2997 revs.remove(rev)
2998 if not revs:
2998 if not revs:
2999 return -1
2999 return -1
3000
3000
3001 # check for ancestors of dest branch
3001 # check for ancestors of dest branch
3002 crev = repo['.'].rev()
3002 crev = repo['.'].rev()
3003 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3003 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3004 # don't mutate while iterating, create a copy
3004 # don't mutate while iterating, create a copy
3005 for rev in list(revs):
3005 for rev in list(revs):
3006 if rev in ancestors:
3006 if rev in ancestors:
3007 ui.warn(_('skipping ancestor revision %s\n') % rev)
3007 ui.warn(_('skipping ancestor revision %s\n') % rev)
3008 revs.remove(rev)
3008 revs.remove(rev)
3009 if not revs:
3009 if not revs:
3010 return -1
3010 return -1
3011
3011
3012 # analyze revs for earlier grafts
3012 # analyze revs for earlier grafts
3013 ids = {}
3013 ids = {}
3014 for ctx in repo.set("%ld", revs):
3014 for ctx in repo.set("%ld", revs):
3015 ids[ctx.hex()] = ctx.rev()
3015 ids[ctx.hex()] = ctx.rev()
3016 n = ctx.extra().get('source')
3016 n = ctx.extra().get('source')
3017 if n:
3017 if n:
3018 ids[n] = ctx.rev()
3018 ids[n] = ctx.rev()
3019
3019
3020 # check ancestors for earlier grafts
3020 # check ancestors for earlier grafts
3021 ui.debug('scanning for duplicate grafts\n')
3021 ui.debug('scanning for duplicate grafts\n')
3022
3022
3023 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3023 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3024 ctx = repo[rev]
3024 ctx = repo[rev]
3025 n = ctx.extra().get('source')
3025 n = ctx.extra().get('source')
3026 if n in ids:
3026 if n in ids:
3027 r = repo[n].rev()
3027 r = repo[n].rev()
3028 if r in revs:
3028 if r in revs:
3029 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3029 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3030 % (r, rev))
3030 % (r, rev))
3031 revs.remove(r)
3031 revs.remove(r)
3032 elif ids[n] in revs:
3032 elif ids[n] in revs:
3033 ui.warn(_('skipping already grafted revision %s '
3033 ui.warn(_('skipping already grafted revision %s '
3034 '(%s also has origin %d)\n') % (ids[n], rev, r))
3034 '(%s also has origin %d)\n') % (ids[n], rev, r))
3035 revs.remove(ids[n])
3035 revs.remove(ids[n])
3036 elif ctx.hex() in ids:
3036 elif ctx.hex() in ids:
3037 r = ids[ctx.hex()]
3037 r = ids[ctx.hex()]
3038 ui.warn(_('skipping already grafted revision %s '
3038 ui.warn(_('skipping already grafted revision %s '
3039 '(was grafted from %d)\n') % (r, rev))
3039 '(was grafted from %d)\n') % (r, rev))
3040 revs.remove(r)
3040 revs.remove(r)
3041 if not revs:
3041 if not revs:
3042 return -1
3042 return -1
3043
3043
3044 wlock = repo.wlock()
3044 wlock = repo.wlock()
3045 try:
3045 try:
3046 current = repo['.']
3046 current = repo['.']
3047 for pos, ctx in enumerate(repo.set("%ld", revs)):
3047 for pos, ctx in enumerate(repo.set("%ld", revs)):
3048
3048
3049 ui.status(_('grafting revision %s\n') % ctx.rev())
3049 ui.status(_('grafting revision %s\n') % ctx.rev())
3050 if opts.get('dry_run'):
3050 if opts.get('dry_run'):
3051 continue
3051 continue
3052
3052
3053 source = ctx.extra().get('source')
3053 source = ctx.extra().get('source')
3054 if not source:
3054 if not source:
3055 source = ctx.hex()
3055 source = ctx.hex()
3056 extra = {'source': source}
3056 extra = {'source': source}
3057 user = ctx.user()
3057 user = ctx.user()
3058 if opts.get('user'):
3058 if opts.get('user'):
3059 user = opts['user']
3059 user = opts['user']
3060 date = ctx.date()
3060 date = ctx.date()
3061 if opts.get('date'):
3061 if opts.get('date'):
3062 date = opts['date']
3062 date = opts['date']
3063 message = ctx.description()
3063 message = ctx.description()
3064 if opts.get('log'):
3064 if opts.get('log'):
3065 message += '\n(grafted from %s)' % ctx.hex()
3065 message += '\n(grafted from %s)' % ctx.hex()
3066
3066
3067 # we don't merge the first commit when continuing
3067 # we don't merge the first commit when continuing
3068 if not cont:
3068 if not cont:
3069 # perform the graft merge with p1(rev) as 'ancestor'
3069 # perform the graft merge with p1(rev) as 'ancestor'
3070 try:
3070 try:
3071 # ui.forcemerge is an internal variable, do not document
3071 # ui.forcemerge is an internal variable, do not document
3072 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3072 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3073 stats = mergemod.update(repo, ctx.node(), True, True, False,
3073 stats = mergemod.update(repo, ctx.node(), True, True, False,
3074 ctx.p1().node())
3074 ctx.p1().node())
3075 finally:
3075 finally:
3076 repo.ui.setconfig('ui', 'forcemerge', '')
3076 repo.ui.setconfig('ui', 'forcemerge', '')
3077 # report any conflicts
3077 # report any conflicts
3078 if stats and stats[3] > 0:
3078 if stats and stats[3] > 0:
3079 # write out state for --continue
3079 # write out state for --continue
3080 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3080 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3081 repo.opener.write('graftstate', ''.join(nodelines))
3081 repo.opener.write('graftstate', ''.join(nodelines))
3082 raise util.Abort(
3082 raise util.Abort(
3083 _("unresolved conflicts, can't continue"),
3083 _("unresolved conflicts, can't continue"),
3084 hint=_('use hg resolve and hg graft --continue'))
3084 hint=_('use hg resolve and hg graft --continue'))
3085 else:
3085 else:
3086 cont = False
3086 cont = False
3087
3087
3088 # drop the second merge parent
3088 # drop the second merge parent
3089 repo.setparents(current.node(), nullid)
3089 repo.setparents(current.node(), nullid)
3090 repo.dirstate.write()
3090 repo.dirstate.write()
3091 # fix up dirstate for copies and renames
3091 # fix up dirstate for copies and renames
3092 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3092 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3093
3093
3094 # commit
3094 # commit
3095 node = repo.commit(text=message, user=user,
3095 node = repo.commit(text=message, user=user,
3096 date=date, extra=extra, editor=editor)
3096 date=date, extra=extra, editor=editor)
3097 if node is None:
3097 if node is None:
3098 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3098 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3099 else:
3099 else:
3100 current = repo[node]
3100 current = repo[node]
3101 finally:
3101 finally:
3102 wlock.release()
3102 wlock.release()
3103
3103
3104 # remove state when we complete successfully
3104 # remove state when we complete successfully
3105 if not opts.get('dry_run'):
3105 if not opts.get('dry_run'):
3106 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3106 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3107
3107
3108 return 0
3108 return 0
3109
3109
3110 @command('grep',
3110 @command('grep',
3111 [('0', 'print0', None, _('end fields with NUL')),
3111 [('0', 'print0', None, _('end fields with NUL')),
3112 ('', 'all', None, _('print all revisions that match')),
3112 ('', 'all', None, _('print all revisions that match')),
3113 ('a', 'text', None, _('treat all files as text')),
3113 ('a', 'text', None, _('treat all files as text')),
3114 ('f', 'follow', None,
3114 ('f', 'follow', None,
3115 _('follow changeset history,'
3115 _('follow changeset history,'
3116 ' or file history across copies and renames')),
3116 ' or file history across copies and renames')),
3117 ('i', 'ignore-case', None, _('ignore case when matching')),
3117 ('i', 'ignore-case', None, _('ignore case when matching')),
3118 ('l', 'files-with-matches', None,
3118 ('l', 'files-with-matches', None,
3119 _('print only filenames and revisions that match')),
3119 _('print only filenames and revisions that match')),
3120 ('n', 'line-number', None, _('print matching line numbers')),
3120 ('n', 'line-number', None, _('print matching line numbers')),
3121 ('r', 'rev', [],
3121 ('r', 'rev', [],
3122 _('only search files changed within revision range'), _('REV')),
3122 _('only search files changed within revision range'), _('REV')),
3123 ('u', 'user', None, _('list the author (long with -v)')),
3123 ('u', 'user', None, _('list the author (long with -v)')),
3124 ('d', 'date', None, _('list the date (short with -q)')),
3124 ('d', 'date', None, _('list the date (short with -q)')),
3125 ] + walkopts,
3125 ] + walkopts,
3126 _('[OPTION]... PATTERN [FILE]...'))
3126 _('[OPTION]... PATTERN [FILE]...'))
3127 def grep(ui, repo, pattern, *pats, **opts):
3127 def grep(ui, repo, pattern, *pats, **opts):
3128 """search for a pattern in specified files and revisions
3128 """search for a pattern in specified files and revisions
3129
3129
3130 Search revisions of files for a regular expression.
3130 Search revisions of files for a regular expression.
3131
3131
3132 This command behaves differently than Unix grep. It only accepts
3132 This command behaves differently than Unix grep. It only accepts
3133 Python/Perl regexps. It searches repository history, not the
3133 Python/Perl regexps. It searches repository history, not the
3134 working directory. It always prints the revision number in which a
3134 working directory. It always prints the revision number in which a
3135 match appears.
3135 match appears.
3136
3136
3137 By default, grep only prints output for the first revision of a
3137 By default, grep only prints output for the first revision of a
3138 file in which it finds a match. To get it to print every revision
3138 file in which it finds a match. To get it to print every revision
3139 that contains a change in match status ("-" for a match that
3139 that contains a change in match status ("-" for a match that
3140 becomes a non-match, or "+" for a non-match that becomes a match),
3140 becomes a non-match, or "+" for a non-match that becomes a match),
3141 use the --all flag.
3141 use the --all flag.
3142
3142
3143 Returns 0 if a match is found, 1 otherwise.
3143 Returns 0 if a match is found, 1 otherwise.
3144 """
3144 """
3145 reflags = re.M
3145 reflags = re.M
3146 if opts.get('ignore_case'):
3146 if opts.get('ignore_case'):
3147 reflags |= re.I
3147 reflags |= re.I
3148 try:
3148 try:
3149 regexp = util.compilere(pattern, reflags)
3149 regexp = util.compilere(pattern, reflags)
3150 except re.error, inst:
3150 except re.error, inst:
3151 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3151 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3152 return 1
3152 return 1
3153 sep, eol = ':', '\n'
3153 sep, eol = ':', '\n'
3154 if opts.get('print0'):
3154 if opts.get('print0'):
3155 sep = eol = '\0'
3155 sep = eol = '\0'
3156
3156
3157 getfile = util.lrucachefunc(repo.file)
3157 getfile = util.lrucachefunc(repo.file)
3158
3158
3159 def matchlines(body):
3159 def matchlines(body):
3160 begin = 0
3160 begin = 0
3161 linenum = 0
3161 linenum = 0
3162 while begin < len(body):
3162 while begin < len(body):
3163 match = regexp.search(body, begin)
3163 match = regexp.search(body, begin)
3164 if not match:
3164 if not match:
3165 break
3165 break
3166 mstart, mend = match.span()
3166 mstart, mend = match.span()
3167 linenum += body.count('\n', begin, mstart) + 1
3167 linenum += body.count('\n', begin, mstart) + 1
3168 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3168 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3169 begin = body.find('\n', mend) + 1 or len(body) + 1
3169 begin = body.find('\n', mend) + 1 or len(body) + 1
3170 lend = begin - 1
3170 lend = begin - 1
3171 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3171 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3172
3172
3173 class linestate(object):
3173 class linestate(object):
3174 def __init__(self, line, linenum, colstart, colend):
3174 def __init__(self, line, linenum, colstart, colend):
3175 self.line = line
3175 self.line = line
3176 self.linenum = linenum
3176 self.linenum = linenum
3177 self.colstart = colstart
3177 self.colstart = colstart
3178 self.colend = colend
3178 self.colend = colend
3179
3179
3180 def __hash__(self):
3180 def __hash__(self):
3181 return hash((self.linenum, self.line))
3181 return hash((self.linenum, self.line))
3182
3182
3183 def __eq__(self, other):
3183 def __eq__(self, other):
3184 return self.line == other.line
3184 return self.line == other.line
3185
3185
3186 matches = {}
3186 matches = {}
3187 copies = {}
3187 copies = {}
3188 def grepbody(fn, rev, body):
3188 def grepbody(fn, rev, body):
3189 matches[rev].setdefault(fn, [])
3189 matches[rev].setdefault(fn, [])
3190 m = matches[rev][fn]
3190 m = matches[rev][fn]
3191 for lnum, cstart, cend, line in matchlines(body):
3191 for lnum, cstart, cend, line in matchlines(body):
3192 s = linestate(line, lnum, cstart, cend)
3192 s = linestate(line, lnum, cstart, cend)
3193 m.append(s)
3193 m.append(s)
3194
3194
3195 def difflinestates(a, b):
3195 def difflinestates(a, b):
3196 sm = difflib.SequenceMatcher(None, a, b)
3196 sm = difflib.SequenceMatcher(None, a, b)
3197 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3197 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3198 if tag == 'insert':
3198 if tag == 'insert':
3199 for i in xrange(blo, bhi):
3199 for i in xrange(blo, bhi):
3200 yield ('+', b[i])
3200 yield ('+', b[i])
3201 elif tag == 'delete':
3201 elif tag == 'delete':
3202 for i in xrange(alo, ahi):
3202 for i in xrange(alo, ahi):
3203 yield ('-', a[i])
3203 yield ('-', a[i])
3204 elif tag == 'replace':
3204 elif tag == 'replace':
3205 for i in xrange(alo, ahi):
3205 for i in xrange(alo, ahi):
3206 yield ('-', a[i])
3206 yield ('-', a[i])
3207 for i in xrange(blo, bhi):
3207 for i in xrange(blo, bhi):
3208 yield ('+', b[i])
3208 yield ('+', b[i])
3209
3209
3210 def display(fn, ctx, pstates, states):
3210 def display(fn, ctx, pstates, states):
3211 rev = ctx.rev()
3211 rev = ctx.rev()
3212 datefunc = ui.quiet and util.shortdate or util.datestr
3212 datefunc = ui.quiet and util.shortdate or util.datestr
3213 found = False
3213 found = False
3214 filerevmatches = {}
3214 filerevmatches = {}
3215 def binary():
3215 def binary():
3216 flog = getfile(fn)
3216 flog = getfile(fn)
3217 return util.binary(flog.read(ctx.filenode(fn)))
3217 return util.binary(flog.read(ctx.filenode(fn)))
3218
3218
3219 if opts.get('all'):
3219 if opts.get('all'):
3220 iter = difflinestates(pstates, states)
3220 iter = difflinestates(pstates, states)
3221 else:
3221 else:
3222 iter = [('', l) for l in states]
3222 iter = [('', l) for l in states]
3223 for change, l in iter:
3223 for change, l in iter:
3224 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3224 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3225 before, match, after = None, None, None
3225 before, match, after = None, None, None
3226
3226
3227 if opts.get('line_number'):
3227 if opts.get('line_number'):
3228 cols.append((str(l.linenum), 'grep.linenumber'))
3228 cols.append((str(l.linenum), 'grep.linenumber'))
3229 if opts.get('all'):
3229 if opts.get('all'):
3230 cols.append((change, 'grep.change'))
3230 cols.append((change, 'grep.change'))
3231 if opts.get('user'):
3231 if opts.get('user'):
3232 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3232 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3233 if opts.get('date'):
3233 if opts.get('date'):
3234 cols.append((datefunc(ctx.date()), 'grep.date'))
3234 cols.append((datefunc(ctx.date()), 'grep.date'))
3235 if opts.get('files_with_matches'):
3235 if opts.get('files_with_matches'):
3236 c = (fn, rev)
3236 c = (fn, rev)
3237 if c in filerevmatches:
3237 if c in filerevmatches:
3238 continue
3238 continue
3239 filerevmatches[c] = 1
3239 filerevmatches[c] = 1
3240 else:
3240 else:
3241 before = l.line[:l.colstart]
3241 before = l.line[:l.colstart]
3242 match = l.line[l.colstart:l.colend]
3242 match = l.line[l.colstart:l.colend]
3243 after = l.line[l.colend:]
3243 after = l.line[l.colend:]
3244 for col, label in cols[:-1]:
3244 for col, label in cols[:-1]:
3245 ui.write(col, label=label)
3245 ui.write(col, label=label)
3246 ui.write(sep, label='grep.sep')
3246 ui.write(sep, label='grep.sep')
3247 ui.write(cols[-1][0], label=cols[-1][1])
3247 ui.write(cols[-1][0], label=cols[-1][1])
3248 if before is not None:
3248 if before is not None:
3249 ui.write(sep, label='grep.sep')
3249 ui.write(sep, label='grep.sep')
3250 if not opts.get('text') and binary():
3250 if not opts.get('text') and binary():
3251 ui.write(" Binary file matches")
3251 ui.write(" Binary file matches")
3252 else:
3252 else:
3253 ui.write(before)
3253 ui.write(before)
3254 ui.write(match, label='grep.match')
3254 ui.write(match, label='grep.match')
3255 ui.write(after)
3255 ui.write(after)
3256 ui.write(eol)
3256 ui.write(eol)
3257 found = True
3257 found = True
3258 return found
3258 return found
3259
3259
3260 skip = {}
3260 skip = {}
3261 revfiles = {}
3261 revfiles = {}
3262 matchfn = scmutil.match(repo[None], pats, opts)
3262 matchfn = scmutil.match(repo[None], pats, opts)
3263 found = False
3263 found = False
3264 follow = opts.get('follow')
3264 follow = opts.get('follow')
3265
3265
3266 def prep(ctx, fns):
3266 def prep(ctx, fns):
3267 rev = ctx.rev()
3267 rev = ctx.rev()
3268 pctx = ctx.p1()
3268 pctx = ctx.p1()
3269 parent = pctx.rev()
3269 parent = pctx.rev()
3270 matches.setdefault(rev, {})
3270 matches.setdefault(rev, {})
3271 matches.setdefault(parent, {})
3271 matches.setdefault(parent, {})
3272 files = revfiles.setdefault(rev, [])
3272 files = revfiles.setdefault(rev, [])
3273 for fn in fns:
3273 for fn in fns:
3274 flog = getfile(fn)
3274 flog = getfile(fn)
3275 try:
3275 try:
3276 fnode = ctx.filenode(fn)
3276 fnode = ctx.filenode(fn)
3277 except error.LookupError:
3277 except error.LookupError:
3278 continue
3278 continue
3279
3279
3280 copied = flog.renamed(fnode)
3280 copied = flog.renamed(fnode)
3281 copy = follow and copied and copied[0]
3281 copy = follow and copied and copied[0]
3282 if copy:
3282 if copy:
3283 copies.setdefault(rev, {})[fn] = copy
3283 copies.setdefault(rev, {})[fn] = copy
3284 if fn in skip:
3284 if fn in skip:
3285 if copy:
3285 if copy:
3286 skip[copy] = True
3286 skip[copy] = True
3287 continue
3287 continue
3288 files.append(fn)
3288 files.append(fn)
3289
3289
3290 if fn not in matches[rev]:
3290 if fn not in matches[rev]:
3291 grepbody(fn, rev, flog.read(fnode))
3291 grepbody(fn, rev, flog.read(fnode))
3292
3292
3293 pfn = copy or fn
3293 pfn = copy or fn
3294 if pfn not in matches[parent]:
3294 if pfn not in matches[parent]:
3295 try:
3295 try:
3296 fnode = pctx.filenode(pfn)
3296 fnode = pctx.filenode(pfn)
3297 grepbody(pfn, parent, flog.read(fnode))
3297 grepbody(pfn, parent, flog.read(fnode))
3298 except error.LookupError:
3298 except error.LookupError:
3299 pass
3299 pass
3300
3300
3301 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3301 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3302 rev = ctx.rev()
3302 rev = ctx.rev()
3303 parent = ctx.p1().rev()
3303 parent = ctx.p1().rev()
3304 for fn in sorted(revfiles.get(rev, [])):
3304 for fn in sorted(revfiles.get(rev, [])):
3305 states = matches[rev][fn]
3305 states = matches[rev][fn]
3306 copy = copies.get(rev, {}).get(fn)
3306 copy = copies.get(rev, {}).get(fn)
3307 if fn in skip:
3307 if fn in skip:
3308 if copy:
3308 if copy:
3309 skip[copy] = True
3309 skip[copy] = True
3310 continue
3310 continue
3311 pstates = matches.get(parent, {}).get(copy or fn, [])
3311 pstates = matches.get(parent, {}).get(copy or fn, [])
3312 if pstates or states:
3312 if pstates or states:
3313 r = display(fn, ctx, pstates, states)
3313 r = display(fn, ctx, pstates, states)
3314 found = found or r
3314 found = found or r
3315 if r and not opts.get('all'):
3315 if r and not opts.get('all'):
3316 skip[fn] = True
3316 skip[fn] = True
3317 if copy:
3317 if copy:
3318 skip[copy] = True
3318 skip[copy] = True
3319 del matches[rev]
3319 del matches[rev]
3320 del revfiles[rev]
3320 del revfiles[rev]
3321
3321
3322 return not found
3322 return not found
3323
3323
3324 @command('heads',
3324 @command('heads',
3325 [('r', 'rev', '',
3325 [('r', 'rev', '',
3326 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3326 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3327 ('t', 'topo', False, _('show topological heads only')),
3327 ('t', 'topo', False, _('show topological heads only')),
3328 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3328 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3329 ('c', 'closed', False, _('show normal and closed branch heads')),
3329 ('c', 'closed', False, _('show normal and closed branch heads')),
3330 ] + templateopts,
3330 ] + templateopts,
3331 _('[-ct] [-r STARTREV] [REV]...'))
3331 _('[-ct] [-r STARTREV] [REV]...'))
3332 def heads(ui, repo, *branchrevs, **opts):
3332 def heads(ui, repo, *branchrevs, **opts):
3333 """show branch heads
3333 """show branch heads
3334
3334
3335 With no arguments, show all open branch heads in the repository.
3335 With no arguments, show all open branch heads in the repository.
3336 Branch heads are changesets that have no descendants on the
3336 Branch heads are changesets that have no descendants on the
3337 same branch. They are where development generally takes place and
3337 same branch. They are where development generally takes place and
3338 are the usual targets for update and merge operations.
3338 are the usual targets for update and merge operations.
3339
3339
3340 If one or more REVs are given, only open branch heads on the
3340 If one or more REVs are given, only open branch heads on the
3341 branches associated with the specified changesets are shown. This
3341 branches associated with the specified changesets are shown. This
3342 means that you can use :hg:`heads .` to see the heads on the
3342 means that you can use :hg:`heads .` to see the heads on the
3343 currently checked-out branch.
3343 currently checked-out branch.
3344
3344
3345 If -c/--closed is specified, also show branch heads marked closed
3345 If -c/--closed is specified, also show branch heads marked closed
3346 (see :hg:`commit --close-branch`).
3346 (see :hg:`commit --close-branch`).
3347
3347
3348 If STARTREV is specified, only those heads that are descendants of
3348 If STARTREV is specified, only those heads that are descendants of
3349 STARTREV will be displayed.
3349 STARTREV will be displayed.
3350
3350
3351 If -t/--topo is specified, named branch mechanics will be ignored and only
3351 If -t/--topo is specified, named branch mechanics will be ignored and only
3352 topological heads (changesets with no children) will be shown.
3352 topological heads (changesets with no children) will be shown.
3353
3353
3354 Returns 0 if matching heads are found, 1 if not.
3354 Returns 0 if matching heads are found, 1 if not.
3355 """
3355 """
3356
3356
3357 start = None
3357 start = None
3358 if 'rev' in opts:
3358 if 'rev' in opts:
3359 start = scmutil.revsingle(repo, opts['rev'], None).node()
3359 start = scmutil.revsingle(repo, opts['rev'], None).node()
3360
3360
3361 if opts.get('topo'):
3361 if opts.get('topo'):
3362 heads = [repo[h] for h in repo.heads(start)]
3362 heads = [repo[h] for h in repo.heads(start)]
3363 else:
3363 else:
3364 heads = []
3364 heads = []
3365 for branch in repo.branchmap():
3365 for branch in repo.branchmap():
3366 heads += repo.branchheads(branch, start, opts.get('closed'))
3366 heads += repo.branchheads(branch, start, opts.get('closed'))
3367 heads = [repo[h] for h in heads]
3367 heads = [repo[h] for h in heads]
3368
3368
3369 if branchrevs:
3369 if branchrevs:
3370 branches = set(repo[br].branch() for br in branchrevs)
3370 branches = set(repo[br].branch() for br in branchrevs)
3371 heads = [h for h in heads if h.branch() in branches]
3371 heads = [h for h in heads if h.branch() in branches]
3372
3372
3373 if opts.get('active') and branchrevs:
3373 if opts.get('active') and branchrevs:
3374 dagheads = repo.heads(start)
3374 dagheads = repo.heads(start)
3375 heads = [h for h in heads if h.node() in dagheads]
3375 heads = [h for h in heads if h.node() in dagheads]
3376
3376
3377 if branchrevs:
3377 if branchrevs:
3378 haveheads = set(h.branch() for h in heads)
3378 haveheads = set(h.branch() for h in heads)
3379 if branches - haveheads:
3379 if branches - haveheads:
3380 headless = ', '.join(b for b in branches - haveheads)
3380 headless = ', '.join(b for b in branches - haveheads)
3381 msg = _('no open branch heads found on branches %s')
3381 msg = _('no open branch heads found on branches %s')
3382 if opts.get('rev'):
3382 if opts.get('rev'):
3383 msg += _(' (started at %s)') % opts['rev']
3383 msg += _(' (started at %s)') % opts['rev']
3384 ui.warn((msg + '\n') % headless)
3384 ui.warn((msg + '\n') % headless)
3385
3385
3386 if not heads:
3386 if not heads:
3387 return 1
3387 return 1
3388
3388
3389 heads = sorted(heads, key=lambda x: -x.rev())
3389 heads = sorted(heads, key=lambda x: -x.rev())
3390 displayer = cmdutil.show_changeset(ui, repo, opts)
3390 displayer = cmdutil.show_changeset(ui, repo, opts)
3391 for ctx in heads:
3391 for ctx in heads:
3392 displayer.show(ctx)
3392 displayer.show(ctx)
3393 displayer.close()
3393 displayer.close()
3394
3394
3395 @command('help',
3395 @command('help',
3396 [('e', 'extension', None, _('show only help for extensions')),
3396 [('e', 'extension', None, _('show only help for extensions')),
3397 ('c', 'command', None, _('show only help for commands')),
3397 ('c', 'command', None, _('show only help for commands')),
3398 ('k', 'keyword', '', _('show topics matching keyword')),
3398 ('k', 'keyword', '', _('show topics matching keyword')),
3399 ],
3399 ],
3400 _('[-ec] [TOPIC]'))
3400 _('[-ec] [TOPIC]'))
3401 def help_(ui, name=None, **opts):
3401 def help_(ui, name=None, **opts):
3402 """show help for a given topic or a help overview
3402 """show help for a given topic or a help overview
3403
3403
3404 With no arguments, print a list of commands with short help messages.
3404 With no arguments, print a list of commands with short help messages.
3405
3405
3406 Given a topic, extension, or command name, print help for that
3406 Given a topic, extension, or command name, print help for that
3407 topic.
3407 topic.
3408
3408
3409 Returns 0 if successful.
3409 Returns 0 if successful.
3410 """
3410 """
3411
3411
3412 textwidth = min(ui.termwidth(), 80) - 2
3412 textwidth = min(ui.termwidth(), 80) - 2
3413
3413
3414 keep = ui.verbose and ['verbose'] or []
3414 keep = ui.verbose and ['verbose'] or []
3415 text = help.help_(ui, name, **opts)
3415 text = help.help_(ui, name, **opts)
3416
3416
3417 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3417 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3418 if 'verbose' in pruned:
3418 if 'verbose' in pruned:
3419 keep.append('omitted')
3419 keep.append('omitted')
3420 else:
3420 else:
3421 keep.append('notomitted')
3421 keep.append('notomitted')
3422 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3422 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3423 ui.write(formatted)
3423 ui.write(formatted)
3424
3424
3425
3425
3426 @command('identify|id',
3426 @command('identify|id',
3427 [('r', 'rev', '',
3427 [('r', 'rev', '',
3428 _('identify the specified revision'), _('REV')),
3428 _('identify the specified revision'), _('REV')),
3429 ('n', 'num', None, _('show local revision number')),
3429 ('n', 'num', None, _('show local revision number')),
3430 ('i', 'id', None, _('show global revision id')),
3430 ('i', 'id', None, _('show global revision id')),
3431 ('b', 'branch', None, _('show branch')),
3431 ('b', 'branch', None, _('show branch')),
3432 ('t', 'tags', None, _('show tags')),
3432 ('t', 'tags', None, _('show tags')),
3433 ('B', 'bookmarks', None, _('show bookmarks')),
3433 ('B', 'bookmarks', None, _('show bookmarks')),
3434 ] + remoteopts,
3434 ] + remoteopts,
3435 _('[-nibtB] [-r REV] [SOURCE]'))
3435 _('[-nibtB] [-r REV] [SOURCE]'))
3436 def identify(ui, repo, source=None, rev=None,
3436 def identify(ui, repo, source=None, rev=None,
3437 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3437 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3438 """identify the working copy or specified revision
3438 """identify the working copy or specified revision
3439
3439
3440 Print a summary identifying the repository state at REV using one or
3440 Print a summary identifying the repository state at REV using one or
3441 two parent hash identifiers, followed by a "+" if the working
3441 two parent hash identifiers, followed by a "+" if the working
3442 directory has uncommitted changes, the branch name (if not default),
3442 directory has uncommitted changes, the branch name (if not default),
3443 a list of tags, and a list of bookmarks.
3443 a list of tags, and a list of bookmarks.
3444
3444
3445 When REV is not given, print a summary of the current state of the
3445 When REV is not given, print a summary of the current state of the
3446 repository.
3446 repository.
3447
3447
3448 Specifying a path to a repository root or Mercurial bundle will
3448 Specifying a path to a repository root or Mercurial bundle will
3449 cause lookup to operate on that repository/bundle.
3449 cause lookup to operate on that repository/bundle.
3450
3450
3451 .. container:: verbose
3451 .. container:: verbose
3452
3452
3453 Examples:
3453 Examples:
3454
3454
3455 - generate a build identifier for the working directory::
3455 - generate a build identifier for the working directory::
3456
3456
3457 hg id --id > build-id.dat
3457 hg id --id > build-id.dat
3458
3458
3459 - find the revision corresponding to a tag::
3459 - find the revision corresponding to a tag::
3460
3460
3461 hg id -n -r 1.3
3461 hg id -n -r 1.3
3462
3462
3463 - check the most recent revision of a remote repository::
3463 - check the most recent revision of a remote repository::
3464
3464
3465 hg id -r tip http://selenic.com/hg/
3465 hg id -r tip http://selenic.com/hg/
3466
3466
3467 Returns 0 if successful.
3467 Returns 0 if successful.
3468 """
3468 """
3469
3469
3470 if not repo and not source:
3470 if not repo and not source:
3471 raise util.Abort(_("there is no Mercurial repository here "
3471 raise util.Abort(_("there is no Mercurial repository here "
3472 "(.hg not found)"))
3472 "(.hg not found)"))
3473
3473
3474 hexfunc = ui.debugflag and hex or short
3474 hexfunc = ui.debugflag and hex or short
3475 default = not (num or id or branch or tags or bookmarks)
3475 default = not (num or id or branch or tags or bookmarks)
3476 output = []
3476 output = []
3477 revs = []
3477 revs = []
3478
3478
3479 if source:
3479 if source:
3480 source, branches = hg.parseurl(ui.expandpath(source))
3480 source, branches = hg.parseurl(ui.expandpath(source))
3481 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3481 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3482 repo = peer.local()
3482 repo = peer.local()
3483 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3483 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3484
3484
3485 if not repo:
3485 if not repo:
3486 if num or branch or tags:
3486 if num or branch or tags:
3487 raise util.Abort(
3487 raise util.Abort(
3488 _("can't query remote revision number, branch, or tags"))
3488 _("can't query remote revision number, branch, or tags"))
3489 if not rev and revs:
3489 if not rev and revs:
3490 rev = revs[0]
3490 rev = revs[0]
3491 if not rev:
3491 if not rev:
3492 rev = "tip"
3492 rev = "tip"
3493
3493
3494 remoterev = peer.lookup(rev)
3494 remoterev = peer.lookup(rev)
3495 if default or id:
3495 if default or id:
3496 output = [hexfunc(remoterev)]
3496 output = [hexfunc(remoterev)]
3497
3497
3498 def getbms():
3498 def getbms():
3499 bms = []
3499 bms = []
3500
3500
3501 if 'bookmarks' in peer.listkeys('namespaces'):
3501 if 'bookmarks' in peer.listkeys('namespaces'):
3502 hexremoterev = hex(remoterev)
3502 hexremoterev = hex(remoterev)
3503 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3503 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3504 if bmr == hexremoterev]
3504 if bmr == hexremoterev]
3505
3505
3506 return sorted(bms)
3506 return sorted(bms)
3507
3507
3508 if bookmarks:
3508 if bookmarks:
3509 output.extend(getbms())
3509 output.extend(getbms())
3510 elif default and not ui.quiet:
3510 elif default and not ui.quiet:
3511 # multiple bookmarks for a single parent separated by '/'
3511 # multiple bookmarks for a single parent separated by '/'
3512 bm = '/'.join(getbms())
3512 bm = '/'.join(getbms())
3513 if bm:
3513 if bm:
3514 output.append(bm)
3514 output.append(bm)
3515 else:
3515 else:
3516 if not rev:
3516 if not rev:
3517 ctx = repo[None]
3517 ctx = repo[None]
3518 parents = ctx.parents()
3518 parents = ctx.parents()
3519 changed = ""
3519 changed = ""
3520 if default or id or num:
3520 if default or id or num:
3521 if (util.any(repo.status())
3521 if (util.any(repo.status())
3522 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3522 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3523 changed = '+'
3523 changed = '+'
3524 if default or id:
3524 if default or id:
3525 output = ["%s%s" %
3525 output = ["%s%s" %
3526 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3526 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3527 if num:
3527 if num:
3528 output.append("%s%s" %
3528 output.append("%s%s" %
3529 ('+'.join([str(p.rev()) for p in parents]), changed))
3529 ('+'.join([str(p.rev()) for p in parents]), changed))
3530 else:
3530 else:
3531 ctx = scmutil.revsingle(repo, rev)
3531 ctx = scmutil.revsingle(repo, rev)
3532 if default or id:
3532 if default or id:
3533 output = [hexfunc(ctx.node())]
3533 output = [hexfunc(ctx.node())]
3534 if num:
3534 if num:
3535 output.append(str(ctx.rev()))
3535 output.append(str(ctx.rev()))
3536
3536
3537 if default and not ui.quiet:
3537 if default and not ui.quiet:
3538 b = ctx.branch()
3538 b = ctx.branch()
3539 if b != 'default':
3539 if b != 'default':
3540 output.append("(%s)" % b)
3540 output.append("(%s)" % b)
3541
3541
3542 # multiple tags for a single parent separated by '/'
3542 # multiple tags for a single parent separated by '/'
3543 t = '/'.join(ctx.tags())
3543 t = '/'.join(ctx.tags())
3544 if t:
3544 if t:
3545 output.append(t)
3545 output.append(t)
3546
3546
3547 # multiple bookmarks for a single parent separated by '/'
3547 # multiple bookmarks for a single parent separated by '/'
3548 bm = '/'.join(ctx.bookmarks())
3548 bm = '/'.join(ctx.bookmarks())
3549 if bm:
3549 if bm:
3550 output.append(bm)
3550 output.append(bm)
3551 else:
3551 else:
3552 if branch:
3552 if branch:
3553 output.append(ctx.branch())
3553 output.append(ctx.branch())
3554
3554
3555 if tags:
3555 if tags:
3556 output.extend(ctx.tags())
3556 output.extend(ctx.tags())
3557
3557
3558 if bookmarks:
3558 if bookmarks:
3559 output.extend(ctx.bookmarks())
3559 output.extend(ctx.bookmarks())
3560
3560
3561 ui.write("%s\n" % ' '.join(output))
3561 ui.write("%s\n" % ' '.join(output))
3562
3562
3563 @command('import|patch',
3563 @command('import|patch',
3564 [('p', 'strip', 1,
3564 [('p', 'strip', 1,
3565 _('directory strip option for patch. This has the same '
3565 _('directory strip option for patch. This has the same '
3566 'meaning as the corresponding patch option'), _('NUM')),
3566 'meaning as the corresponding patch option'), _('NUM')),
3567 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3567 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3568 ('e', 'edit', False, _('invoke editor on commit messages')),
3568 ('e', 'edit', False, _('invoke editor on commit messages')),
3569 ('f', 'force', None,
3569 ('f', 'force', None,
3570 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3570 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3571 ('', 'no-commit', None,
3571 ('', 'no-commit', None,
3572 _("don't commit, just update the working directory")),
3572 _("don't commit, just update the working directory")),
3573 ('', 'bypass', None,
3573 ('', 'bypass', None,
3574 _("apply patch without touching the working directory")),
3574 _("apply patch without touching the working directory")),
3575 ('', 'exact', None,
3575 ('', 'exact', None,
3576 _('apply patch to the nodes from which it was generated')),
3576 _('apply patch to the nodes from which it was generated')),
3577 ('', 'import-branch', None,
3577 ('', 'import-branch', None,
3578 _('use any branch information in patch (implied by --exact)'))] +
3578 _('use any branch information in patch (implied by --exact)'))] +
3579 commitopts + commitopts2 + similarityopts,
3579 commitopts + commitopts2 + similarityopts,
3580 _('[OPTION]... PATCH...'))
3580 _('[OPTION]... PATCH...'))
3581 def import_(ui, repo, patch1=None, *patches, **opts):
3581 def import_(ui, repo, patch1=None, *patches, **opts):
3582 """import an ordered set of patches
3582 """import an ordered set of patches
3583
3583
3584 Import a list of patches and commit them individually (unless
3584 Import a list of patches and commit them individually (unless
3585 --no-commit is specified).
3585 --no-commit is specified).
3586
3586
3587 Because import first applies changes to the working directory,
3587 Because import first applies changes to the working directory,
3588 import will abort if there are outstanding changes.
3588 import will abort if there are outstanding changes.
3589
3589
3590 You can import a patch straight from a mail message. Even patches
3590 You can import a patch straight from a mail message. Even patches
3591 as attachments work (to use the body part, it must have type
3591 as attachments work (to use the body part, it must have type
3592 text/plain or text/x-patch). From and Subject headers of email
3592 text/plain or text/x-patch). From and Subject headers of email
3593 message are used as default committer and commit message. All
3593 message are used as default committer and commit message. All
3594 text/plain body parts before first diff are added to commit
3594 text/plain body parts before first diff are added to commit
3595 message.
3595 message.
3596
3596
3597 If the imported patch was generated by :hg:`export`, user and
3597 If the imported patch was generated by :hg:`export`, user and
3598 description from patch override values from message headers and
3598 description from patch override values from message headers and
3599 body. Values given on command line with -m/--message and -u/--user
3599 body. Values given on command line with -m/--message and -u/--user
3600 override these.
3600 override these.
3601
3601
3602 If --exact is specified, import will set the working directory to
3602 If --exact is specified, import will set the working directory to
3603 the parent of each patch before applying it, and will abort if the
3603 the parent of each patch before applying it, and will abort if the
3604 resulting changeset has a different ID than the one recorded in
3604 resulting changeset has a different ID than the one recorded in
3605 the patch. This may happen due to character set problems or other
3605 the patch. This may happen due to character set problems or other
3606 deficiencies in the text patch format.
3606 deficiencies in the text patch format.
3607
3607
3608 Use --bypass to apply and commit patches directly to the
3608 Use --bypass to apply and commit patches directly to the
3609 repository, not touching the working directory. Without --exact,
3609 repository, not touching the working directory. Without --exact,
3610 patches will be applied on top of the working directory parent
3610 patches will be applied on top of the working directory parent
3611 revision.
3611 revision.
3612
3612
3613 With -s/--similarity, hg will attempt to discover renames and
3613 With -s/--similarity, hg will attempt to discover renames and
3614 copies in the patch in the same way as :hg:`addremove`.
3614 copies in the patch in the same way as :hg:`addremove`.
3615
3615
3616 To read a patch from standard input, use "-" as the patch name. If
3616 To read a patch from standard input, use "-" as the patch name. If
3617 a URL is specified, the patch will be downloaded from it.
3617 a URL is specified, the patch will be downloaded from it.
3618 See :hg:`help dates` for a list of formats valid for -d/--date.
3618 See :hg:`help dates` for a list of formats valid for -d/--date.
3619
3619
3620 .. container:: verbose
3620 .. container:: verbose
3621
3621
3622 Examples:
3622 Examples:
3623
3623
3624 - import a traditional patch from a website and detect renames::
3624 - import a traditional patch from a website and detect renames::
3625
3625
3626 hg import -s 80 http://example.com/bugfix.patch
3626 hg import -s 80 http://example.com/bugfix.patch
3627
3627
3628 - import a changeset from an hgweb server::
3628 - import a changeset from an hgweb server::
3629
3629
3630 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3630 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3631
3631
3632 - import all the patches in an Unix-style mbox::
3632 - import all the patches in an Unix-style mbox::
3633
3633
3634 hg import incoming-patches.mbox
3634 hg import incoming-patches.mbox
3635
3635
3636 - attempt to exactly restore an exported changeset (not always
3636 - attempt to exactly restore an exported changeset (not always
3637 possible)::
3637 possible)::
3638
3638
3639 hg import --exact proposed-fix.patch
3639 hg import --exact proposed-fix.patch
3640
3640
3641 Returns 0 on success.
3641 Returns 0 on success.
3642 """
3642 """
3643
3643
3644 if not patch1:
3644 if not patch1:
3645 raise util.Abort(_('need at least one patch to import'))
3645 raise util.Abort(_('need at least one patch to import'))
3646
3646
3647 patches = (patch1,) + patches
3647 patches = (patch1,) + patches
3648
3648
3649 date = opts.get('date')
3649 date = opts.get('date')
3650 if date:
3650 if date:
3651 opts['date'] = util.parsedate(date)
3651 opts['date'] = util.parsedate(date)
3652
3652
3653 editor = cmdutil.commiteditor
3653 editor = cmdutil.commiteditor
3654 if opts.get('edit'):
3654 if opts.get('edit'):
3655 editor = cmdutil.commitforceeditor
3655 editor = cmdutil.commitforceeditor
3656
3656
3657 update = not opts.get('bypass')
3657 update = not opts.get('bypass')
3658 if not update and opts.get('no_commit'):
3658 if not update and opts.get('no_commit'):
3659 raise util.Abort(_('cannot use --no-commit with --bypass'))
3659 raise util.Abort(_('cannot use --no-commit with --bypass'))
3660 try:
3660 try:
3661 sim = float(opts.get('similarity') or 0)
3661 sim = float(opts.get('similarity') or 0)
3662 except ValueError:
3662 except ValueError:
3663 raise util.Abort(_('similarity must be a number'))
3663 raise util.Abort(_('similarity must be a number'))
3664 if sim < 0 or sim > 100:
3664 if sim < 0 or sim > 100:
3665 raise util.Abort(_('similarity must be between 0 and 100'))
3665 raise util.Abort(_('similarity must be between 0 and 100'))
3666 if sim and not update:
3666 if sim and not update:
3667 raise util.Abort(_('cannot use --similarity with --bypass'))
3667 raise util.Abort(_('cannot use --similarity with --bypass'))
3668
3668
3669 if update:
3669 if update:
3670 cmdutil.checkunfinished(repo)
3670 cmdutil.checkunfinished(repo)
3671 if (opts.get('exact') or not opts.get('force')) and update:
3671 if (opts.get('exact') or not opts.get('force')) and update:
3672 cmdutil.bailifchanged(repo)
3672 cmdutil.bailifchanged(repo)
3673
3673
3674 base = opts["base"]
3674 base = opts["base"]
3675 strip = opts["strip"]
3675 strip = opts["strip"]
3676 wlock = lock = tr = None
3676 wlock = lock = tr = None
3677 msgs = []
3677 msgs = []
3678
3678
3679 def tryone(ui, hunk, parents):
3679 def tryone(ui, hunk, parents):
3680 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3680 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3681 patch.extract(ui, hunk)
3681 patch.extract(ui, hunk)
3682
3682
3683 if not tmpname:
3683 if not tmpname:
3684 return (None, None)
3684 return (None, None)
3685 msg = _('applied to working directory')
3685 msg = _('applied to working directory')
3686
3686
3687 try:
3687 try:
3688 cmdline_message = cmdutil.logmessage(ui, opts)
3688 cmdline_message = cmdutil.logmessage(ui, opts)
3689 if cmdline_message:
3689 if cmdline_message:
3690 # pickup the cmdline msg
3690 # pickup the cmdline msg
3691 message = cmdline_message
3691 message = cmdline_message
3692 elif message:
3692 elif message:
3693 # pickup the patch msg
3693 # pickup the patch msg
3694 message = message.strip()
3694 message = message.strip()
3695 else:
3695 else:
3696 # launch the editor
3696 # launch the editor
3697 message = None
3697 message = None
3698 ui.debug('message:\n%s\n' % message)
3698 ui.debug('message:\n%s\n' % message)
3699
3699
3700 if len(parents) == 1:
3700 if len(parents) == 1:
3701 parents.append(repo[nullid])
3701 parents.append(repo[nullid])
3702 if opts.get('exact'):
3702 if opts.get('exact'):
3703 if not nodeid or not p1:
3703 if not nodeid or not p1:
3704 raise util.Abort(_('not a Mercurial patch'))
3704 raise util.Abort(_('not a Mercurial patch'))
3705 p1 = repo[p1]
3705 p1 = repo[p1]
3706 p2 = repo[p2 or nullid]
3706 p2 = repo[p2 or nullid]
3707 elif p2:
3707 elif p2:
3708 try:
3708 try:
3709 p1 = repo[p1]
3709 p1 = repo[p1]
3710 p2 = repo[p2]
3710 p2 = repo[p2]
3711 # Without any options, consider p2 only if the
3711 # Without any options, consider p2 only if the
3712 # patch is being applied on top of the recorded
3712 # patch is being applied on top of the recorded
3713 # first parent.
3713 # first parent.
3714 if p1 != parents[0]:
3714 if p1 != parents[0]:
3715 p1 = parents[0]
3715 p1 = parents[0]
3716 p2 = repo[nullid]
3716 p2 = repo[nullid]
3717 except error.RepoError:
3717 except error.RepoError:
3718 p1, p2 = parents
3718 p1, p2 = parents
3719 else:
3719 else:
3720 p1, p2 = parents
3720 p1, p2 = parents
3721
3721
3722 n = None
3722 n = None
3723 if update:
3723 if update:
3724 if p1 != parents[0]:
3724 if p1 != parents[0]:
3725 hg.clean(repo, p1.node())
3725 hg.clean(repo, p1.node())
3726 if p2 != parents[1]:
3726 if p2 != parents[1]:
3727 repo.setparents(p1.node(), p2.node())
3727 repo.setparents(p1.node(), p2.node())
3728
3728
3729 if opts.get('exact') or opts.get('import_branch'):
3729 if opts.get('exact') or opts.get('import_branch'):
3730 repo.dirstate.setbranch(branch or 'default')
3730 repo.dirstate.setbranch(branch or 'default')
3731
3731
3732 files = set()
3732 files = set()
3733 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3733 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3734 eolmode=None, similarity=sim / 100.0)
3734 eolmode=None, similarity=sim / 100.0)
3735 files = list(files)
3735 files = list(files)
3736 if opts.get('no_commit'):
3736 if opts.get('no_commit'):
3737 if message:
3737 if message:
3738 msgs.append(message)
3738 msgs.append(message)
3739 else:
3739 else:
3740 if opts.get('exact') or p2:
3740 if opts.get('exact') or p2:
3741 # If you got here, you either use --force and know what
3741 # If you got here, you either use --force and know what
3742 # you are doing or used --exact or a merge patch while
3742 # you are doing or used --exact or a merge patch while
3743 # being updated to its first parent.
3743 # being updated to its first parent.
3744 m = None
3744 m = None
3745 else:
3745 else:
3746 m = scmutil.matchfiles(repo, files or [])
3746 m = scmutil.matchfiles(repo, files or [])
3747 n = repo.commit(message, opts.get('user') or user,
3747 n = repo.commit(message, opts.get('user') or user,
3748 opts.get('date') or date, match=m,
3748 opts.get('date') or date, match=m,
3749 editor=editor)
3749 editor=editor)
3750 else:
3750 else:
3751 if opts.get('exact') or opts.get('import_branch'):
3751 if opts.get('exact') or opts.get('import_branch'):
3752 branch = branch or 'default'
3752 branch = branch or 'default'
3753 else:
3753 else:
3754 branch = p1.branch()
3754 branch = p1.branch()
3755 store = patch.filestore()
3755 store = patch.filestore()
3756 try:
3756 try:
3757 files = set()
3757 files = set()
3758 try:
3758 try:
3759 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3759 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3760 files, eolmode=None)
3760 files, eolmode=None)
3761 except patch.PatchError, e:
3761 except patch.PatchError, e:
3762 raise util.Abort(str(e))
3762 raise util.Abort(str(e))
3763 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3763 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3764 message,
3764 message,
3765 opts.get('user') or user,
3765 opts.get('user') or user,
3766 opts.get('date') or date,
3766 opts.get('date') or date,
3767 branch, files, store,
3767 branch, files, store,
3768 editor=cmdutil.commiteditor)
3768 editor=cmdutil.commiteditor)
3769 repo.savecommitmessage(memctx.description())
3769 repo.savecommitmessage(memctx.description())
3770 n = memctx.commit()
3770 n = memctx.commit()
3771 finally:
3771 finally:
3772 store.close()
3772 store.close()
3773 if opts.get('exact') and hex(n) != nodeid:
3773 if opts.get('exact') and hex(n) != nodeid:
3774 raise util.Abort(_('patch is damaged or loses information'))
3774 raise util.Abort(_('patch is damaged or loses information'))
3775 if n:
3775 if n:
3776 # i18n: refers to a short changeset id
3776 # i18n: refers to a short changeset id
3777 msg = _('created %s') % short(n)
3777 msg = _('created %s') % short(n)
3778 return (msg, n)
3778 return (msg, n)
3779 finally:
3779 finally:
3780 os.unlink(tmpname)
3780 os.unlink(tmpname)
3781
3781
3782 try:
3782 try:
3783 try:
3783 try:
3784 wlock = repo.wlock()
3784 wlock = repo.wlock()
3785 if not opts.get('no_commit'):
3785 if not opts.get('no_commit'):
3786 lock = repo.lock()
3786 lock = repo.lock()
3787 tr = repo.transaction('import')
3787 tr = repo.transaction('import')
3788 parents = repo.parents()
3788 parents = repo.parents()
3789 for patchurl in patches:
3789 for patchurl in patches:
3790 if patchurl == '-':
3790 if patchurl == '-':
3791 ui.status(_('applying patch from stdin\n'))
3791 ui.status(_('applying patch from stdin\n'))
3792 patchfile = ui.fin
3792 patchfile = ui.fin
3793 patchurl = 'stdin' # for error message
3793 patchurl = 'stdin' # for error message
3794 else:
3794 else:
3795 patchurl = os.path.join(base, patchurl)
3795 patchurl = os.path.join(base, patchurl)
3796 ui.status(_('applying %s\n') % patchurl)
3796 ui.status(_('applying %s\n') % patchurl)
3797 patchfile = hg.openpath(ui, patchurl)
3797 patchfile = hg.openpath(ui, patchurl)
3798
3798
3799 haspatch = False
3799 haspatch = False
3800 for hunk in patch.split(patchfile):
3800 for hunk in patch.split(patchfile):
3801 (msg, node) = tryone(ui, hunk, parents)
3801 (msg, node) = tryone(ui, hunk, parents)
3802 if msg:
3802 if msg:
3803 haspatch = True
3803 haspatch = True
3804 ui.note(msg + '\n')
3804 ui.note(msg + '\n')
3805 if update or opts.get('exact'):
3805 if update or opts.get('exact'):
3806 parents = repo.parents()
3806 parents = repo.parents()
3807 else:
3807 else:
3808 parents = [repo[node]]
3808 parents = [repo[node]]
3809
3809
3810 if not haspatch:
3810 if not haspatch:
3811 raise util.Abort(_('%s: no diffs found') % patchurl)
3811 raise util.Abort(_('%s: no diffs found') % patchurl)
3812
3812
3813 if tr:
3813 if tr:
3814 tr.close()
3814 tr.close()
3815 if msgs:
3815 if msgs:
3816 repo.savecommitmessage('\n* * *\n'.join(msgs))
3816 repo.savecommitmessage('\n* * *\n'.join(msgs))
3817 except: # re-raises
3817 except: # re-raises
3818 # wlock.release() indirectly calls dirstate.write(): since
3818 # wlock.release() indirectly calls dirstate.write(): since
3819 # we're crashing, we do not want to change the working dir
3819 # we're crashing, we do not want to change the working dir
3820 # parent after all, so make sure it writes nothing
3820 # parent after all, so make sure it writes nothing
3821 repo.dirstate.invalidate()
3821 repo.dirstate.invalidate()
3822 raise
3822 raise
3823 finally:
3823 finally:
3824 if tr:
3824 if tr:
3825 tr.release()
3825 tr.release()
3826 release(lock, wlock)
3826 release(lock, wlock)
3827
3827
3828 @command('incoming|in',
3828 @command('incoming|in',
3829 [('f', 'force', None,
3829 [('f', 'force', None,
3830 _('run even if remote repository is unrelated')),
3830 _('run even if remote repository is unrelated')),
3831 ('n', 'newest-first', None, _('show newest record first')),
3831 ('n', 'newest-first', None, _('show newest record first')),
3832 ('', 'bundle', '',
3832 ('', 'bundle', '',
3833 _('file to store the bundles into'), _('FILE')),
3833 _('file to store the bundles into'), _('FILE')),
3834 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3834 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3835 ('B', 'bookmarks', False, _("compare bookmarks")),
3835 ('B', 'bookmarks', False, _("compare bookmarks")),
3836 ('b', 'branch', [],
3836 ('b', 'branch', [],
3837 _('a specific branch you would like to pull'), _('BRANCH')),
3837 _('a specific branch you would like to pull'), _('BRANCH')),
3838 ] + logopts + remoteopts + subrepoopts,
3838 ] + logopts + remoteopts + subrepoopts,
3839 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3839 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3840 def incoming(ui, repo, source="default", **opts):
3840 def incoming(ui, repo, source="default", **opts):
3841 """show new changesets found in source
3841 """show new changesets found in source
3842
3842
3843 Show new changesets found in the specified path/URL or the default
3843 Show new changesets found in the specified path/URL or the default
3844 pull location. These are the changesets that would have been pulled
3844 pull location. These are the changesets that would have been pulled
3845 if a pull at the time you issued this command.
3845 if a pull at the time you issued this command.
3846
3846
3847 For remote repository, using --bundle avoids downloading the
3847 For remote repository, using --bundle avoids downloading the
3848 changesets twice if the incoming is followed by a pull.
3848 changesets twice if the incoming is followed by a pull.
3849
3849
3850 See pull for valid source format details.
3850 See pull for valid source format details.
3851
3851
3852 Returns 0 if there are incoming changes, 1 otherwise.
3852 Returns 0 if there are incoming changes, 1 otherwise.
3853 """
3853 """
3854 if opts.get('graph'):
3854 if opts.get('graph'):
3855 cmdutil.checkunsupportedgraphflags([], opts)
3855 cmdutil.checkunsupportedgraphflags([], opts)
3856 def display(other, chlist, displayer):
3856 def display(other, chlist, displayer):
3857 revdag = cmdutil.graphrevs(other, chlist, opts)
3857 revdag = cmdutil.graphrevs(other, chlist, opts)
3858 showparents = [ctx.node() for ctx in repo[None].parents()]
3858 showparents = [ctx.node() for ctx in repo[None].parents()]
3859 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3859 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3860 graphmod.asciiedges)
3860 graphmod.asciiedges)
3861
3861
3862 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3862 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3863 return 0
3863 return 0
3864
3864
3865 if opts.get('bundle') and opts.get('subrepos'):
3865 if opts.get('bundle') and opts.get('subrepos'):
3866 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3866 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3867
3867
3868 if opts.get('bookmarks'):
3868 if opts.get('bookmarks'):
3869 source, branches = hg.parseurl(ui.expandpath(source),
3869 source, branches = hg.parseurl(ui.expandpath(source),
3870 opts.get('branch'))
3870 opts.get('branch'))
3871 other = hg.peer(repo, opts, source)
3871 other = hg.peer(repo, opts, source)
3872 if 'bookmarks' not in other.listkeys('namespaces'):
3872 if 'bookmarks' not in other.listkeys('namespaces'):
3873 ui.warn(_("remote doesn't support bookmarks\n"))
3873 ui.warn(_("remote doesn't support bookmarks\n"))
3874 return 0
3874 return 0
3875 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3875 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3876 return bookmarks.diff(ui, repo, other)
3876 return bookmarks.diff(ui, repo, other)
3877
3877
3878 repo._subtoppath = ui.expandpath(source)
3878 repo._subtoppath = ui.expandpath(source)
3879 try:
3879 try:
3880 return hg.incoming(ui, repo, source, opts)
3880 return hg.incoming(ui, repo, source, opts)
3881 finally:
3881 finally:
3882 del repo._subtoppath
3882 del repo._subtoppath
3883
3883
3884
3884
3885 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3885 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3886 def init(ui, dest=".", **opts):
3886 def init(ui, dest=".", **opts):
3887 """create a new repository in the given directory
3887 """create a new repository in the given directory
3888
3888
3889 Initialize a new repository in the given directory. If the given
3889 Initialize a new repository in the given directory. If the given
3890 directory does not exist, it will be created.
3890 directory does not exist, it will be created.
3891
3891
3892 If no directory is given, the current directory is used.
3892 If no directory is given, the current directory is used.
3893
3893
3894 It is possible to specify an ``ssh://`` URL as the destination.
3894 It is possible to specify an ``ssh://`` URL as the destination.
3895 See :hg:`help urls` for more information.
3895 See :hg:`help urls` for more information.
3896
3896
3897 Returns 0 on success.
3897 Returns 0 on success.
3898 """
3898 """
3899 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3899 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3900
3900
3901 @command('locate',
3901 @command('locate',
3902 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3902 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3903 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3903 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3904 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3904 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3905 ] + walkopts,
3905 ] + walkopts,
3906 _('[OPTION]... [PATTERN]...'))
3906 _('[OPTION]... [PATTERN]...'))
3907 def locate(ui, repo, *pats, **opts):
3907 def locate(ui, repo, *pats, **opts):
3908 """locate files matching specific patterns
3908 """locate files matching specific patterns
3909
3909
3910 Print files under Mercurial control in the working directory whose
3910 Print files under Mercurial control in the working directory whose
3911 names match the given patterns.
3911 names match the given patterns.
3912
3912
3913 By default, this command searches all directories in the working
3913 By default, this command searches all directories in the working
3914 directory. To search just the current directory and its
3914 directory. To search just the current directory and its
3915 subdirectories, use "--include .".
3915 subdirectories, use "--include .".
3916
3916
3917 If no patterns are given to match, this command prints the names
3917 If no patterns are given to match, this command prints the names
3918 of all files under Mercurial control in the working directory.
3918 of all files under Mercurial control in the working directory.
3919
3919
3920 If you want to feed the output of this command into the "xargs"
3920 If you want to feed the output of this command into the "xargs"
3921 command, use the -0 option to both this command and "xargs". This
3921 command, use the -0 option to both this command and "xargs". This
3922 will avoid the problem of "xargs" treating single filenames that
3922 will avoid the problem of "xargs" treating single filenames that
3923 contain whitespace as multiple filenames.
3923 contain whitespace as multiple filenames.
3924
3924
3925 Returns 0 if a match is found, 1 otherwise.
3925 Returns 0 if a match is found, 1 otherwise.
3926 """
3926 """
3927 end = opts.get('print0') and '\0' or '\n'
3927 end = opts.get('print0') and '\0' or '\n'
3928 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3928 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3929
3929
3930 ret = 1
3930 ret = 1
3931 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3931 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3932 m.bad = lambda x, y: False
3932 m.bad = lambda x, y: False
3933 for abs in repo[rev].walk(m):
3933 for abs in repo[rev].walk(m):
3934 if not rev and abs not in repo.dirstate:
3934 if not rev and abs not in repo.dirstate:
3935 continue
3935 continue
3936 if opts.get('fullpath'):
3936 if opts.get('fullpath'):
3937 ui.write(repo.wjoin(abs), end)
3937 ui.write(repo.wjoin(abs), end)
3938 else:
3938 else:
3939 ui.write(((pats and m.rel(abs)) or abs), end)
3939 ui.write(((pats and m.rel(abs)) or abs), end)
3940 ret = 0
3940 ret = 0
3941
3941
3942 return ret
3942 return ret
3943
3943
3944 @command('^log|history',
3944 @command('^log|history',
3945 [('f', 'follow', None,
3945 [('f', 'follow', None,
3946 _('follow changeset history, or file history across copies and renames')),
3946 _('follow changeset history, or file history across copies and renames')),
3947 ('', 'follow-first', None,
3947 ('', 'follow-first', None,
3948 _('only follow the first parent of merge changesets (DEPRECATED)')),
3948 _('only follow the first parent of merge changesets (DEPRECATED)')),
3949 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3949 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3950 ('C', 'copies', None, _('show copied files')),
3950 ('C', 'copies', None, _('show copied files')),
3951 ('k', 'keyword', [],
3951 ('k', 'keyword', [],
3952 _('do case-insensitive search for a given text'), _('TEXT')),
3952 _('do case-insensitive search for a given text'), _('TEXT')),
3953 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3953 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3954 ('', 'removed', None, _('include revisions where files were removed')),
3954 ('', 'removed', None, _('include revisions where files were removed')),
3955 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3955 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3956 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3956 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3957 ('', 'only-branch', [],
3957 ('', 'only-branch', [],
3958 _('show only changesets within the given named branch (DEPRECATED)'),
3958 _('show only changesets within the given named branch (DEPRECATED)'),
3959 _('BRANCH')),
3959 _('BRANCH')),
3960 ('b', 'branch', [],
3960 ('b', 'branch', [],
3961 _('show changesets within the given named branch'), _('BRANCH')),
3961 _('show changesets within the given named branch'), _('BRANCH')),
3962 ('P', 'prune', [],
3962 ('P', 'prune', [],
3963 _('do not display revision or any of its ancestors'), _('REV')),
3963 _('do not display revision or any of its ancestors'), _('REV')),
3964 ] + logopts + walkopts,
3964 ] + logopts + walkopts,
3965 _('[OPTION]... [FILE]'))
3965 _('[OPTION]... [FILE]'))
3966 def log(ui, repo, *pats, **opts):
3966 def log(ui, repo, *pats, **opts):
3967 """show revision history of entire repository or files
3967 """show revision history of entire repository or files
3968
3968
3969 Print the revision history of the specified files or the entire
3969 Print the revision history of the specified files or the entire
3970 project.
3970 project.
3971
3971
3972 If no revision range is specified, the default is ``tip:0`` unless
3972 If no revision range is specified, the default is ``tip:0`` unless
3973 --follow is set, in which case the working directory parent is
3973 --follow is set, in which case the working directory parent is
3974 used as the starting revision.
3974 used as the starting revision.
3975
3975
3976 File history is shown without following rename or copy history of
3976 File history is shown without following rename or copy history of
3977 files. Use -f/--follow with a filename to follow history across
3977 files. Use -f/--follow with a filename to follow history across
3978 renames and copies. --follow without a filename will only show
3978 renames and copies. --follow without a filename will only show
3979 ancestors or descendants of the starting revision.
3979 ancestors or descendants of the starting revision.
3980
3980
3981 By default this command prints revision number and changeset id,
3981 By default this command prints revision number and changeset id,
3982 tags, non-trivial parents, user, date and time, and a summary for
3982 tags, non-trivial parents, user, date and time, and a summary for
3983 each commit. When the -v/--verbose switch is used, the list of
3983 each commit. When the -v/--verbose switch is used, the list of
3984 changed files and full commit message are shown.
3984 changed files and full commit message are shown.
3985
3985
3986 .. note::
3986 .. note::
3987
3987
3988 log -p/--patch may generate unexpected diff output for merge
3988 log -p/--patch may generate unexpected diff output for merge
3989 changesets, as it will only compare the merge changeset against
3989 changesets, as it will only compare the merge changeset against
3990 its first parent. Also, only files different from BOTH parents
3990 its first parent. Also, only files different from BOTH parents
3991 will appear in files:.
3991 will appear in files:.
3992
3992
3993 .. note::
3993 .. note::
3994
3994
3995 for performance reasons, log FILE may omit duplicate changes
3995 for performance reasons, log FILE may omit duplicate changes
3996 made on branches and will not show deletions. To see all
3996 made on branches and will not show deletions. To see all
3997 changes including duplicates and deletions, use the --removed
3997 changes including duplicates and deletions, use the --removed
3998 switch.
3998 switch.
3999
3999
4000 .. container:: verbose
4000 .. container:: verbose
4001
4001
4002 Some examples:
4002 Some examples:
4003
4003
4004 - changesets with full descriptions and file lists::
4004 - changesets with full descriptions and file lists::
4005
4005
4006 hg log -v
4006 hg log -v
4007
4007
4008 - changesets ancestral to the working directory::
4008 - changesets ancestral to the working directory::
4009
4009
4010 hg log -f
4010 hg log -f
4011
4011
4012 - last 10 commits on the current branch::
4012 - last 10 commits on the current branch::
4013
4013
4014 hg log -l 10 -b .
4014 hg log -l 10 -b .
4015
4015
4016 - changesets showing all modifications of a file, including removals::
4016 - changesets showing all modifications of a file, including removals::
4017
4017
4018 hg log --removed file.c
4018 hg log --removed file.c
4019
4019
4020 - all changesets that touch a directory, with diffs, excluding merges::
4020 - all changesets that touch a directory, with diffs, excluding merges::
4021
4021
4022 hg log -Mp lib/
4022 hg log -Mp lib/
4023
4023
4024 - all revision numbers that match a keyword::
4024 - all revision numbers that match a keyword::
4025
4025
4026 hg log -k bug --template "{rev}\\n"
4026 hg log -k bug --template "{rev}\\n"
4027
4027
4028 - check if a given changeset is included is a tagged release::
4028 - check if a given changeset is included is a tagged release::
4029
4029
4030 hg log -r "a21ccf and ancestor(1.9)"
4030 hg log -r "a21ccf and ancestor(1.9)"
4031
4031
4032 - find all changesets by some user in a date range::
4032 - find all changesets by some user in a date range::
4033
4033
4034 hg log -k alice -d "may 2008 to jul 2008"
4034 hg log -k alice -d "may 2008 to jul 2008"
4035
4035
4036 - summary of all changesets after the last tag::
4036 - summary of all changesets after the last tag::
4037
4037
4038 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4038 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4039
4039
4040 See :hg:`help dates` for a list of formats valid for -d/--date.
4040 See :hg:`help dates` for a list of formats valid for -d/--date.
4041
4041
4042 See :hg:`help revisions` and :hg:`help revsets` for more about
4042 See :hg:`help revisions` and :hg:`help revsets` for more about
4043 specifying revisions.
4043 specifying revisions.
4044
4044
4045 See :hg:`help templates` for more about pre-packaged styles and
4045 See :hg:`help templates` for more about pre-packaged styles and
4046 specifying custom templates.
4046 specifying custom templates.
4047
4047
4048 Returns 0 on success.
4048 Returns 0 on success.
4049 """
4049 """
4050 if opts.get('graph'):
4050 if opts.get('graph'):
4051 return cmdutil.graphlog(ui, repo, *pats, **opts)
4051 return cmdutil.graphlog(ui, repo, *pats, **opts)
4052
4052
4053 matchfn = scmutil.match(repo[None], pats, opts)
4053 matchfn = scmutil.match(repo[None], pats, opts)
4054 limit = cmdutil.loglimit(opts)
4054 limit = cmdutil.loglimit(opts)
4055 count = 0
4055 count = 0
4056
4056
4057 getrenamed, endrev = None, None
4057 getrenamed, endrev = None, None
4058 if opts.get('copies'):
4058 if opts.get('copies'):
4059 if opts.get('rev'):
4059 if opts.get('rev'):
4060 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4060 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4061 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4061 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4062
4062
4063 df = False
4063 df = False
4064 if opts.get("date"):
4064 if opts.get("date"):
4065 df = util.matchdate(opts["date"])
4065 df = util.matchdate(opts["date"])
4066
4066
4067 branches = opts.get('branch', []) + opts.get('only_branch', [])
4067 branches = opts.get('branch', []) + opts.get('only_branch', [])
4068 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4068 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4069
4069
4070 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4070 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4071 def prep(ctx, fns):
4071 def prep(ctx, fns):
4072 rev = ctx.rev()
4072 rev = ctx.rev()
4073 parents = [p for p in repo.changelog.parentrevs(rev)
4073 parents = [p for p in repo.changelog.parentrevs(rev)
4074 if p != nullrev]
4074 if p != nullrev]
4075 if opts.get('no_merges') and len(parents) == 2:
4075 if opts.get('no_merges') and len(parents) == 2:
4076 return
4076 return
4077 if opts.get('only_merges') and len(parents) != 2:
4077 if opts.get('only_merges') and len(parents) != 2:
4078 return
4078 return
4079 if opts.get('branch') and ctx.branch() not in opts['branch']:
4079 if opts.get('branch') and ctx.branch() not in opts['branch']:
4080 return
4080 return
4081 if df and not df(ctx.date()[0]):
4081 if df and not df(ctx.date()[0]):
4082 return
4082 return
4083
4083
4084 lower = encoding.lower
4084 lower = encoding.lower
4085 if opts.get('user'):
4085 if opts.get('user'):
4086 luser = lower(ctx.user())
4086 luser = lower(ctx.user())
4087 for k in [lower(x) for x in opts['user']]:
4087 for k in [lower(x) for x in opts['user']]:
4088 if (k in luser):
4088 if (k in luser):
4089 break
4089 break
4090 else:
4090 else:
4091 return
4091 return
4092 if opts.get('keyword'):
4092 if opts.get('keyword'):
4093 luser = lower(ctx.user())
4093 luser = lower(ctx.user())
4094 ldesc = lower(ctx.description())
4094 ldesc = lower(ctx.description())
4095 lfiles = lower(" ".join(ctx.files()))
4095 lfiles = lower(" ".join(ctx.files()))
4096 for k in [lower(x) for x in opts['keyword']]:
4096 for k in [lower(x) for x in opts['keyword']]:
4097 if (k in luser or k in ldesc or k in lfiles):
4097 if (k in luser or k in ldesc or k in lfiles):
4098 break
4098 break
4099 else:
4099 else:
4100 return
4100 return
4101
4101
4102 copies = None
4102 copies = None
4103 if getrenamed is not None and rev:
4103 if getrenamed is not None and rev:
4104 copies = []
4104 copies = []
4105 for fn in ctx.files():
4105 for fn in ctx.files():
4106 rename = getrenamed(fn, rev)
4106 rename = getrenamed(fn, rev)
4107 if rename:
4107 if rename:
4108 copies.append((fn, rename[0]))
4108 copies.append((fn, rename[0]))
4109
4109
4110 revmatchfn = None
4110 revmatchfn = None
4111 if opts.get('patch') or opts.get('stat'):
4111 if opts.get('patch') or opts.get('stat'):
4112 if opts.get('follow') or opts.get('follow_first'):
4112 if opts.get('follow') or opts.get('follow_first'):
4113 # note: this might be wrong when following through merges
4113 # note: this might be wrong when following through merges
4114 revmatchfn = scmutil.match(repo[None], fns, default='path')
4114 revmatchfn = scmutil.match(repo[None], fns, default='path')
4115 else:
4115 else:
4116 revmatchfn = matchfn
4116 revmatchfn = matchfn
4117
4117
4118 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4118 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4119
4119
4120 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4120 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4121 if displayer.flush(ctx.rev()):
4121 if displayer.flush(ctx.rev()):
4122 count += 1
4122 count += 1
4123 if count == limit:
4123 if count == limit:
4124 break
4124 break
4125 displayer.close()
4125 displayer.close()
4126
4126
4127 @command('manifest',
4127 @command('manifest',
4128 [('r', 'rev', '', _('revision to display'), _('REV')),
4128 [('r', 'rev', '', _('revision to display'), _('REV')),
4129 ('', 'all', False, _("list files from all revisions"))],
4129 ('', 'all', False, _("list files from all revisions"))],
4130 _('[-r REV]'))
4130 _('[-r REV]'))
4131 def manifest(ui, repo, node=None, rev=None, **opts):
4131 def manifest(ui, repo, node=None, rev=None, **opts):
4132 """output the current or given revision of the project manifest
4132 """output the current or given revision of the project manifest
4133
4133
4134 Print a list of version controlled files for the given revision.
4134 Print a list of version controlled files for the given revision.
4135 If no revision is given, the first parent of the working directory
4135 If no revision is given, the first parent of the working directory
4136 is used, or the null revision if no revision is checked out.
4136 is used, or the null revision if no revision is checked out.
4137
4137
4138 With -v, print file permissions, symlink and executable bits.
4138 With -v, print file permissions, symlink and executable bits.
4139 With --debug, print file revision hashes.
4139 With --debug, print file revision hashes.
4140
4140
4141 If option --all is specified, the list of all files from all revisions
4141 If option --all is specified, the list of all files from all revisions
4142 is printed. This includes deleted and renamed files.
4142 is printed. This includes deleted and renamed files.
4143
4143
4144 Returns 0 on success.
4144 Returns 0 on success.
4145 """
4145 """
4146
4146
4147 fm = ui.formatter('manifest', opts)
4147 fm = ui.formatter('manifest', opts)
4148
4148
4149 if opts.get('all'):
4149 if opts.get('all'):
4150 if rev or node:
4150 if rev or node:
4151 raise util.Abort(_("can't specify a revision with --all"))
4151 raise util.Abort(_("can't specify a revision with --all"))
4152
4152
4153 res = []
4153 res = []
4154 prefix = "data/"
4154 prefix = "data/"
4155 suffix = ".i"
4155 suffix = ".i"
4156 plen = len(prefix)
4156 plen = len(prefix)
4157 slen = len(suffix)
4157 slen = len(suffix)
4158 lock = repo.lock()
4158 lock = repo.lock()
4159 try:
4159 try:
4160 for fn, b, size in repo.store.datafiles():
4160 for fn, b, size in repo.store.datafiles():
4161 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4161 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4162 res.append(fn[plen:-slen])
4162 res.append(fn[plen:-slen])
4163 finally:
4163 finally:
4164 lock.release()
4164 lock.release()
4165 for f in res:
4165 for f in res:
4166 fm.startitem()
4166 fm.startitem()
4167 fm.write("path", '%s\n', f)
4167 fm.write("path", '%s\n', f)
4168 fm.end()
4168 fm.end()
4169 return
4169 return
4170
4170
4171 if rev and node:
4171 if rev and node:
4172 raise util.Abort(_("please specify just one revision"))
4172 raise util.Abort(_("please specify just one revision"))
4173
4173
4174 if not node:
4174 if not node:
4175 node = rev
4175 node = rev
4176
4176
4177 char = {'l': '@', 'x': '*', '': ''}
4177 char = {'l': '@', 'x': '*', '': ''}
4178 mode = {'l': '644', 'x': '755', '': '644'}
4178 mode = {'l': '644', 'x': '755', '': '644'}
4179 ctx = scmutil.revsingle(repo, node)
4179 ctx = scmutil.revsingle(repo, node)
4180 mf = ctx.manifest()
4180 mf = ctx.manifest()
4181 for f in ctx:
4181 for f in ctx:
4182 fm.startitem()
4182 fm.startitem()
4183 fl = ctx[f].flags()
4183 fl = ctx[f].flags()
4184 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4184 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4185 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4185 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4186 fm.write('path', '%s\n', f)
4186 fm.write('path', '%s\n', f)
4187 fm.end()
4187 fm.end()
4188
4188
4189 @command('^merge',
4189 @command('^merge',
4190 [('f', 'force', None,
4190 [('f', 'force', None,
4191 _('force a merge including outstanding changes (DEPRECATED)')),
4191 _('force a merge including outstanding changes (DEPRECATED)')),
4192 ('r', 'rev', '', _('revision to merge'), _('REV')),
4192 ('r', 'rev', '', _('revision to merge'), _('REV')),
4193 ('P', 'preview', None,
4193 ('P', 'preview', None,
4194 _('review revisions to merge (no merge is performed)'))
4194 _('review revisions to merge (no merge is performed)'))
4195 ] + mergetoolopts,
4195 ] + mergetoolopts,
4196 _('[-P] [-f] [[-r] REV]'))
4196 _('[-P] [-f] [[-r] REV]'))
4197 def merge(ui, repo, node=None, **opts):
4197 def merge(ui, repo, node=None, **opts):
4198 """merge working directory with another revision
4198 """merge working directory with another revision
4199
4199
4200 The current working directory is updated with all changes made in
4200 The current working directory is updated with all changes made in
4201 the requested revision since the last common predecessor revision.
4201 the requested revision since the last common predecessor revision.
4202
4202
4203 Files that changed between either parent are marked as changed for
4203 Files that changed between either parent are marked as changed for
4204 the next commit and a commit must be performed before any further
4204 the next commit and a commit must be performed before any further
4205 updates to the repository are allowed. The next commit will have
4205 updates to the repository are allowed. The next commit will have
4206 two parents.
4206 two parents.
4207
4207
4208 ``--tool`` can be used to specify the merge tool used for file
4208 ``--tool`` can be used to specify the merge tool used for file
4209 merges. It overrides the HGMERGE environment variable and your
4209 merges. It overrides the HGMERGE environment variable and your
4210 configuration files. See :hg:`help merge-tools` for options.
4210 configuration files. See :hg:`help merge-tools` for options.
4211
4211
4212 If no revision is specified, the working directory's parent is a
4212 If no revision is specified, the working directory's parent is a
4213 head revision, and the current branch contains exactly one other
4213 head revision, and the current branch contains exactly one other
4214 head, the other head is merged with by default. Otherwise, an
4214 head, the other head is merged with by default. Otherwise, an
4215 explicit revision with which to merge with must be provided.
4215 explicit revision with which to merge with must be provided.
4216
4216
4217 :hg:`resolve` must be used to resolve unresolved files.
4217 :hg:`resolve` must be used to resolve unresolved files.
4218
4218
4219 To undo an uncommitted merge, use :hg:`update --clean .` which
4219 To undo an uncommitted merge, use :hg:`update --clean .` which
4220 will check out a clean copy of the original merge parent, losing
4220 will check out a clean copy of the original merge parent, losing
4221 all changes.
4221 all changes.
4222
4222
4223 Returns 0 on success, 1 if there are unresolved files.
4223 Returns 0 on success, 1 if there are unresolved files.
4224 """
4224 """
4225
4225
4226 if opts.get('rev') and node:
4226 if opts.get('rev') and node:
4227 raise util.Abort(_("please specify just one revision"))
4227 raise util.Abort(_("please specify just one revision"))
4228 if not node:
4228 if not node:
4229 node = opts.get('rev')
4229 node = opts.get('rev')
4230
4230
4231 if node:
4231 if node:
4232 node = scmutil.revsingle(repo, node).node()
4232 node = scmutil.revsingle(repo, node).node()
4233
4233
4234 if not node and repo._bookmarkcurrent:
4234 if not node and repo._bookmarkcurrent:
4235 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4235 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4236 curhead = repo[repo._bookmarkcurrent].node()
4236 curhead = repo[repo._bookmarkcurrent].node()
4237 if len(bmheads) == 2:
4237 if len(bmheads) == 2:
4238 if curhead == bmheads[0]:
4238 if curhead == bmheads[0]:
4239 node = bmheads[1]
4239 node = bmheads[1]
4240 else:
4240 else:
4241 node = bmheads[0]
4241 node = bmheads[0]
4242 elif len(bmheads) > 2:
4242 elif len(bmheads) > 2:
4243 raise util.Abort(_("multiple matching bookmarks to merge - "
4243 raise util.Abort(_("multiple matching bookmarks to merge - "
4244 "please merge with an explicit rev or bookmark"),
4244 "please merge with an explicit rev or bookmark"),
4245 hint=_("run 'hg heads' to see all heads"))
4245 hint=_("run 'hg heads' to see all heads"))
4246 elif len(bmheads) <= 1:
4246 elif len(bmheads) <= 1:
4247 raise util.Abort(_("no matching bookmark to merge - "
4247 raise util.Abort(_("no matching bookmark to merge - "
4248 "please merge with an explicit rev or bookmark"),
4248 "please merge with an explicit rev or bookmark"),
4249 hint=_("run 'hg heads' to see all heads"))
4249 hint=_("run 'hg heads' to see all heads"))
4250
4250
4251 if not node and not repo._bookmarkcurrent:
4251 if not node and not repo._bookmarkcurrent:
4252 branch = repo[None].branch()
4252 branch = repo[None].branch()
4253 bheads = repo.branchheads(branch)
4253 bheads = repo.branchheads(branch)
4254 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4254 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4255
4255
4256 if len(nbhs) > 2:
4256 if len(nbhs) > 2:
4257 raise util.Abort(_("branch '%s' has %d heads - "
4257 raise util.Abort(_("branch '%s' has %d heads - "
4258 "please merge with an explicit rev")
4258 "please merge with an explicit rev")
4259 % (branch, len(bheads)),
4259 % (branch, len(bheads)),
4260 hint=_("run 'hg heads .' to see heads"))
4260 hint=_("run 'hg heads .' to see heads"))
4261
4261
4262 parent = repo.dirstate.p1()
4262 parent = repo.dirstate.p1()
4263 if len(nbhs) <= 1:
4263 if len(nbhs) <= 1:
4264 if len(bheads) > 1:
4264 if len(bheads) > 1:
4265 raise util.Abort(_("heads are bookmarked - "
4265 raise util.Abort(_("heads are bookmarked - "
4266 "please merge with an explicit rev"),
4266 "please merge with an explicit rev"),
4267 hint=_("run 'hg heads' to see all heads"))
4267 hint=_("run 'hg heads' to see all heads"))
4268 if len(repo.heads()) > 1:
4268 if len(repo.heads()) > 1:
4269 raise util.Abort(_("branch '%s' has one head - "
4269 raise util.Abort(_("branch '%s' has one head - "
4270 "please merge with an explicit rev")
4270 "please merge with an explicit rev")
4271 % branch,
4271 % branch,
4272 hint=_("run 'hg heads' to see all heads"))
4272 hint=_("run 'hg heads' to see all heads"))
4273 msg, hint = _('nothing to merge'), None
4273 msg, hint = _('nothing to merge'), None
4274 if parent != repo.lookup(branch):
4274 if parent != repo.lookup(branch):
4275 hint = _("use 'hg update' instead")
4275 hint = _("use 'hg update' instead")
4276 raise util.Abort(msg, hint=hint)
4276 raise util.Abort(msg, hint=hint)
4277
4277
4278 if parent not in bheads:
4278 if parent not in bheads:
4279 raise util.Abort(_('working directory not at a head revision'),
4279 raise util.Abort(_('working directory not at a head revision'),
4280 hint=_("use 'hg update' or merge with an "
4280 hint=_("use 'hg update' or merge with an "
4281 "explicit revision"))
4281 "explicit revision"))
4282 if parent == nbhs[0]:
4282 if parent == nbhs[0]:
4283 node = nbhs[-1]
4283 node = nbhs[-1]
4284 else:
4284 else:
4285 node = nbhs[0]
4285 node = nbhs[0]
4286
4286
4287 if opts.get('preview'):
4287 if opts.get('preview'):
4288 # find nodes that are ancestors of p2 but not of p1
4288 # find nodes that are ancestors of p2 but not of p1
4289 p1 = repo.lookup('.')
4289 p1 = repo.lookup('.')
4290 p2 = repo.lookup(node)
4290 p2 = repo.lookup(node)
4291 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4291 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4292
4292
4293 displayer = cmdutil.show_changeset(ui, repo, opts)
4293 displayer = cmdutil.show_changeset(ui, repo, opts)
4294 for node in nodes:
4294 for node in nodes:
4295 displayer.show(repo[node])
4295 displayer.show(repo[node])
4296 displayer.close()
4296 displayer.close()
4297 return 0
4297 return 0
4298
4298
4299 try:
4299 try:
4300 # ui.forcemerge is an internal variable, do not document
4300 # ui.forcemerge is an internal variable, do not document
4301 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4301 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4302 return hg.merge(repo, node, force=opts.get('force'))
4302 return hg.merge(repo, node, force=opts.get('force'))
4303 finally:
4303 finally:
4304 ui.setconfig('ui', 'forcemerge', '')
4304 ui.setconfig('ui', 'forcemerge', '')
4305
4305
4306 @command('outgoing|out',
4306 @command('outgoing|out',
4307 [('f', 'force', None, _('run even when the destination is unrelated')),
4307 [('f', 'force', None, _('run even when the destination is unrelated')),
4308 ('r', 'rev', [],
4308 ('r', 'rev', [],
4309 _('a changeset intended to be included in the destination'), _('REV')),
4309 _('a changeset intended to be included in the destination'), _('REV')),
4310 ('n', 'newest-first', None, _('show newest record first')),
4310 ('n', 'newest-first', None, _('show newest record first')),
4311 ('B', 'bookmarks', False, _('compare bookmarks')),
4311 ('B', 'bookmarks', False, _('compare bookmarks')),
4312 ('b', 'branch', [], _('a specific branch you would like to push'),
4312 ('b', 'branch', [], _('a specific branch you would like to push'),
4313 _('BRANCH')),
4313 _('BRANCH')),
4314 ] + logopts + remoteopts + subrepoopts,
4314 ] + logopts + remoteopts + subrepoopts,
4315 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4315 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4316 def outgoing(ui, repo, dest=None, **opts):
4316 def outgoing(ui, repo, dest=None, **opts):
4317 """show changesets not found in the destination
4317 """show changesets not found in the destination
4318
4318
4319 Show changesets not found in the specified destination repository
4319 Show changesets not found in the specified destination repository
4320 or the default push location. These are the changesets that would
4320 or the default push location. These are the changesets that would
4321 be pushed if a push was requested.
4321 be pushed if a push was requested.
4322
4322
4323 See pull for details of valid destination formats.
4323 See pull for details of valid destination formats.
4324
4324
4325 Returns 0 if there are outgoing changes, 1 otherwise.
4325 Returns 0 if there are outgoing changes, 1 otherwise.
4326 """
4326 """
4327 if opts.get('graph'):
4327 if opts.get('graph'):
4328 cmdutil.checkunsupportedgraphflags([], opts)
4328 cmdutil.checkunsupportedgraphflags([], opts)
4329 o = hg._outgoing(ui, repo, dest, opts)
4329 o = hg._outgoing(ui, repo, dest, opts)
4330 if o is None:
4330 if o is None:
4331 return
4331 return
4332
4332
4333 revdag = cmdutil.graphrevs(repo, o, opts)
4333 revdag = cmdutil.graphrevs(repo, o, opts)
4334 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4334 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4335 showparents = [ctx.node() for ctx in repo[None].parents()]
4335 showparents = [ctx.node() for ctx in repo[None].parents()]
4336 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4336 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4337 graphmod.asciiedges)
4337 graphmod.asciiedges)
4338 return 0
4338 return 0
4339
4339
4340 if opts.get('bookmarks'):
4340 if opts.get('bookmarks'):
4341 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4341 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4342 dest, branches = hg.parseurl(dest, opts.get('branch'))
4342 dest, branches = hg.parseurl(dest, opts.get('branch'))
4343 other = hg.peer(repo, opts, dest)
4343 other = hg.peer(repo, opts, dest)
4344 if 'bookmarks' not in other.listkeys('namespaces'):
4344 if 'bookmarks' not in other.listkeys('namespaces'):
4345 ui.warn(_("remote doesn't support bookmarks\n"))
4345 ui.warn(_("remote doesn't support bookmarks\n"))
4346 return 0
4346 return 0
4347 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4347 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4348 return bookmarks.diff(ui, other, repo)
4348 return bookmarks.diff(ui, other, repo)
4349
4349
4350 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4350 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4351 try:
4351 try:
4352 return hg.outgoing(ui, repo, dest, opts)
4352 return hg.outgoing(ui, repo, dest, opts)
4353 finally:
4353 finally:
4354 del repo._subtoppath
4354 del repo._subtoppath
4355
4355
4356 @command('parents',
4356 @command('parents',
4357 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4357 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4358 ] + templateopts,
4358 ] + templateopts,
4359 _('[-r REV] [FILE]'))
4359 _('[-r REV] [FILE]'))
4360 def parents(ui, repo, file_=None, **opts):
4360 def parents(ui, repo, file_=None, **opts):
4361 """show the parents of the working directory or revision
4361 """show the parents of the working directory or revision
4362
4362
4363 Print the working directory's parent revisions. If a revision is
4363 Print the working directory's parent revisions. If a revision is
4364 given via -r/--rev, the parent of that revision will be printed.
4364 given via -r/--rev, the parent of that revision will be printed.
4365 If a file argument is given, the revision in which the file was
4365 If a file argument is given, the revision in which the file was
4366 last changed (before the working directory revision or the
4366 last changed (before the working directory revision or the
4367 argument to --rev if given) is printed.
4367 argument to --rev if given) is printed.
4368
4368
4369 Returns 0 on success.
4369 Returns 0 on success.
4370 """
4370 """
4371
4371
4372 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4372 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4373
4373
4374 if file_:
4374 if file_:
4375 m = scmutil.match(ctx, (file_,), opts)
4375 m = scmutil.match(ctx, (file_,), opts)
4376 if m.anypats() or len(m.files()) != 1:
4376 if m.anypats() or len(m.files()) != 1:
4377 raise util.Abort(_('can only specify an explicit filename'))
4377 raise util.Abort(_('can only specify an explicit filename'))
4378 file_ = m.files()[0]
4378 file_ = m.files()[0]
4379 filenodes = []
4379 filenodes = []
4380 for cp in ctx.parents():
4380 for cp in ctx.parents():
4381 if not cp:
4381 if not cp:
4382 continue
4382 continue
4383 try:
4383 try:
4384 filenodes.append(cp.filenode(file_))
4384 filenodes.append(cp.filenode(file_))
4385 except error.LookupError:
4385 except error.LookupError:
4386 pass
4386 pass
4387 if not filenodes:
4387 if not filenodes:
4388 raise util.Abort(_("'%s' not found in manifest!") % file_)
4388 raise util.Abort(_("'%s' not found in manifest!") % file_)
4389 p = []
4389 p = []
4390 for fn in filenodes:
4390 for fn in filenodes:
4391 fctx = repo.filectx(file_, fileid=fn)
4391 fctx = repo.filectx(file_, fileid=fn)
4392 p.append(fctx.node())
4392 p.append(fctx.node())
4393 else:
4393 else:
4394 p = [cp.node() for cp in ctx.parents()]
4394 p = [cp.node() for cp in ctx.parents()]
4395
4395
4396 displayer = cmdutil.show_changeset(ui, repo, opts)
4396 displayer = cmdutil.show_changeset(ui, repo, opts)
4397 for n in p:
4397 for n in p:
4398 if n != nullid:
4398 if n != nullid:
4399 displayer.show(repo[n])
4399 displayer.show(repo[n])
4400 displayer.close()
4400 displayer.close()
4401
4401
4402 @command('paths', [], _('[NAME]'))
4402 @command('paths', [], _('[NAME]'))
4403 def paths(ui, repo, search=None):
4403 def paths(ui, repo, search=None):
4404 """show aliases for remote repositories
4404 """show aliases for remote repositories
4405
4405
4406 Show definition of symbolic path name NAME. If no name is given,
4406 Show definition of symbolic path name NAME. If no name is given,
4407 show definition of all available names.
4407 show definition of all available names.
4408
4408
4409 Option -q/--quiet suppresses all output when searching for NAME
4409 Option -q/--quiet suppresses all output when searching for NAME
4410 and shows only the path names when listing all definitions.
4410 and shows only the path names when listing all definitions.
4411
4411
4412 Path names are defined in the [paths] section of your
4412 Path names are defined in the [paths] section of your
4413 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4413 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4414 repository, ``.hg/hgrc`` is used, too.
4414 repository, ``.hg/hgrc`` is used, too.
4415
4415
4416 The path names ``default`` and ``default-push`` have a special
4416 The path names ``default`` and ``default-push`` have a special
4417 meaning. When performing a push or pull operation, they are used
4417 meaning. When performing a push or pull operation, they are used
4418 as fallbacks if no location is specified on the command-line.
4418 as fallbacks if no location is specified on the command-line.
4419 When ``default-push`` is set, it will be used for push and
4419 When ``default-push`` is set, it will be used for push and
4420 ``default`` will be used for pull; otherwise ``default`` is used
4420 ``default`` will be used for pull; otherwise ``default`` is used
4421 as the fallback for both. When cloning a repository, the clone
4421 as the fallback for both. When cloning a repository, the clone
4422 source is written as ``default`` in ``.hg/hgrc``. Note that
4422 source is written as ``default`` in ``.hg/hgrc``. Note that
4423 ``default`` and ``default-push`` apply to all inbound (e.g.
4423 ``default`` and ``default-push`` apply to all inbound (e.g.
4424 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4424 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4425 :hg:`bundle`) operations.
4425 :hg:`bundle`) operations.
4426
4426
4427 See :hg:`help urls` for more information.
4427 See :hg:`help urls` for more information.
4428
4428
4429 Returns 0 on success.
4429 Returns 0 on success.
4430 """
4430 """
4431 if search:
4431 if search:
4432 for name, path in ui.configitems("paths"):
4432 for name, path in ui.configitems("paths"):
4433 if name == search:
4433 if name == search:
4434 ui.status("%s\n" % util.hidepassword(path))
4434 ui.status("%s\n" % util.hidepassword(path))
4435 return
4435 return
4436 if not ui.quiet:
4436 if not ui.quiet:
4437 ui.warn(_("not found!\n"))
4437 ui.warn(_("not found!\n"))
4438 return 1
4438 return 1
4439 else:
4439 else:
4440 for name, path in ui.configitems("paths"):
4440 for name, path in ui.configitems("paths"):
4441 if ui.quiet:
4441 if ui.quiet:
4442 ui.write("%s\n" % name)
4442 ui.write("%s\n" % name)
4443 else:
4443 else:
4444 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4444 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4445
4445
4446 @command('phase',
4446 @command('phase',
4447 [('p', 'public', False, _('set changeset phase to public')),
4447 [('p', 'public', False, _('set changeset phase to public')),
4448 ('d', 'draft', False, _('set changeset phase to draft')),
4448 ('d', 'draft', False, _('set changeset phase to draft')),
4449 ('s', 'secret', False, _('set changeset phase to secret')),
4449 ('s', 'secret', False, _('set changeset phase to secret')),
4450 ('f', 'force', False, _('allow to move boundary backward')),
4450 ('f', 'force', False, _('allow to move boundary backward')),
4451 ('r', 'rev', [], _('target revision'), _('REV')),
4451 ('r', 'rev', [], _('target revision'), _('REV')),
4452 ],
4452 ],
4453 _('[-p|-d|-s] [-f] [-r] REV...'))
4453 _('[-p|-d|-s] [-f] [-r] REV...'))
4454 def phase(ui, repo, *revs, **opts):
4454 def phase(ui, repo, *revs, **opts):
4455 """set or show the current phase name
4455 """set or show the current phase name
4456
4456
4457 With no argument, show the phase name of specified revisions.
4457 With no argument, show the phase name of specified revisions.
4458
4458
4459 With one of -p/--public, -d/--draft or -s/--secret, change the
4459 With one of -p/--public, -d/--draft or -s/--secret, change the
4460 phase value of the specified revisions.
4460 phase value of the specified revisions.
4461
4461
4462 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4462 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4463 lower phase to an higher phase. Phases are ordered as follows::
4463 lower phase to an higher phase. Phases are ordered as follows::
4464
4464
4465 public < draft < secret
4465 public < draft < secret
4466
4466
4467 Return 0 on success, 1 if no phases were changed or some could not
4467 Return 0 on success, 1 if no phases were changed or some could not
4468 be changed.
4468 be changed.
4469 """
4469 """
4470 # search for a unique phase argument
4470 # search for a unique phase argument
4471 targetphase = None
4471 targetphase = None
4472 for idx, name in enumerate(phases.phasenames):
4472 for idx, name in enumerate(phases.phasenames):
4473 if opts[name]:
4473 if opts[name]:
4474 if targetphase is not None:
4474 if targetphase is not None:
4475 raise util.Abort(_('only one phase can be specified'))
4475 raise util.Abort(_('only one phase can be specified'))
4476 targetphase = idx
4476 targetphase = idx
4477
4477
4478 # look for specified revision
4478 # look for specified revision
4479 revs = list(revs)
4479 revs = list(revs)
4480 revs.extend(opts['rev'])
4480 revs.extend(opts['rev'])
4481 if not revs:
4481 if not revs:
4482 raise util.Abort(_('no revisions specified'))
4482 raise util.Abort(_('no revisions specified'))
4483
4483
4484 revs = scmutil.revrange(repo, revs)
4484 revs = scmutil.revrange(repo, revs)
4485
4485
4486 lock = None
4486 lock = None
4487 ret = 0
4487 ret = 0
4488 if targetphase is None:
4488 if targetphase is None:
4489 # display
4489 # display
4490 for r in revs:
4490 for r in revs:
4491 ctx = repo[r]
4491 ctx = repo[r]
4492 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4492 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4493 else:
4493 else:
4494 lock = repo.lock()
4494 lock = repo.lock()
4495 try:
4495 try:
4496 # set phase
4496 # set phase
4497 if not revs:
4497 if not revs:
4498 raise util.Abort(_('empty revision set'))
4498 raise util.Abort(_('empty revision set'))
4499 nodes = [repo[r].node() for r in revs]
4499 nodes = [repo[r].node() for r in revs]
4500 olddata = repo._phasecache.getphaserevs(repo)[:]
4500 olddata = repo._phasecache.getphaserevs(repo)[:]
4501 phases.advanceboundary(repo, targetphase, nodes)
4501 phases.advanceboundary(repo, targetphase, nodes)
4502 if opts['force']:
4502 if opts['force']:
4503 phases.retractboundary(repo, targetphase, nodes)
4503 phases.retractboundary(repo, targetphase, nodes)
4504 finally:
4504 finally:
4505 lock.release()
4505 lock.release()
4506 # moving revision from public to draft may hide them
4506 # moving revision from public to draft may hide them
4507 # We have to check result on an unfiltered repository
4507 # We have to check result on an unfiltered repository
4508 unfi = repo.unfiltered()
4508 unfi = repo.unfiltered()
4509 newdata = repo._phasecache.getphaserevs(unfi)
4509 newdata = repo._phasecache.getphaserevs(unfi)
4510 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4510 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4511 cl = unfi.changelog
4511 cl = unfi.changelog
4512 rejected = [n for n in nodes
4512 rejected = [n for n in nodes
4513 if newdata[cl.rev(n)] < targetphase]
4513 if newdata[cl.rev(n)] < targetphase]
4514 if rejected:
4514 if rejected:
4515 ui.warn(_('cannot move %i changesets to a more permissive '
4515 ui.warn(_('cannot move %i changesets to a more permissive '
4516 'phase, use --force\n') % len(rejected))
4516 'phase, use --force\n') % len(rejected))
4517 ret = 1
4517 ret = 1
4518 if changes:
4518 if changes:
4519 msg = _('phase changed for %i changesets\n') % changes
4519 msg = _('phase changed for %i changesets\n') % changes
4520 if ret:
4520 if ret:
4521 ui.status(msg)
4521 ui.status(msg)
4522 else:
4522 else:
4523 ui.note(msg)
4523 ui.note(msg)
4524 else:
4524 else:
4525 ui.warn(_('no phases changed\n'))
4525 ui.warn(_('no phases changed\n'))
4526 ret = 1
4526 ret = 1
4527 return ret
4527 return ret
4528
4528
4529 def postincoming(ui, repo, modheads, optupdate, checkout):
4529 def postincoming(ui, repo, modheads, optupdate, checkout):
4530 if modheads == 0:
4530 if modheads == 0:
4531 return
4531 return
4532 if optupdate:
4532 if optupdate:
4533 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4533 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4534 try:
4534 try:
4535 ret = hg.update(repo, checkout)
4535 ret = hg.update(repo, checkout)
4536 except util.Abort, inst:
4536 except util.Abort, inst:
4537 ui.warn(_("not updating: %s\n") % str(inst))
4537 ui.warn(_("not updating: %s\n") % str(inst))
4538 if inst.hint:
4538 if inst.hint:
4539 ui.warn(_("(%s)\n") % inst.hint)
4539 ui.warn(_("(%s)\n") % inst.hint)
4540 return 0
4540 return 0
4541 if not ret and not checkout:
4541 if not ret and not checkout:
4542 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4542 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4543 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4543 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4544 return ret
4544 return ret
4545 if modheads > 1:
4545 if modheads > 1:
4546 currentbranchheads = len(repo.branchheads())
4546 currentbranchheads = len(repo.branchheads())
4547 if currentbranchheads == modheads:
4547 if currentbranchheads == modheads:
4548 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4548 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4549 elif currentbranchheads > 1:
4549 elif currentbranchheads > 1:
4550 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4550 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4551 "merge)\n"))
4551 "merge)\n"))
4552 else:
4552 else:
4553 ui.status(_("(run 'hg heads' to see heads)\n"))
4553 ui.status(_("(run 'hg heads' to see heads)\n"))
4554 else:
4554 else:
4555 ui.status(_("(run 'hg update' to get a working copy)\n"))
4555 ui.status(_("(run 'hg update' to get a working copy)\n"))
4556
4556
4557 @command('^pull',
4557 @command('^pull',
4558 [('u', 'update', None,
4558 [('u', 'update', None,
4559 _('update to new branch head if changesets were pulled')),
4559 _('update to new branch head if changesets were pulled')),
4560 ('f', 'force', None, _('run even when remote repository is unrelated')),
4560 ('f', 'force', None, _('run even when remote repository is unrelated')),
4561 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4561 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4562 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4562 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4563 ('b', 'branch', [], _('a specific branch you would like to pull'),
4563 ('b', 'branch', [], _('a specific branch you would like to pull'),
4564 _('BRANCH')),
4564 _('BRANCH')),
4565 ] + remoteopts,
4565 ] + remoteopts,
4566 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4566 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4567 def pull(ui, repo, source="default", **opts):
4567 def pull(ui, repo, source="default", **opts):
4568 """pull changes from the specified source
4568 """pull changes from the specified source
4569
4569
4570 Pull changes from a remote repository to a local one.
4570 Pull changes from a remote repository to a local one.
4571
4571
4572 This finds all changes from the repository at the specified path
4572 This finds all changes from the repository at the specified path
4573 or URL and adds them to a local repository (the current one unless
4573 or URL and adds them to a local repository (the current one unless
4574 -R is specified). By default, this does not update the copy of the
4574 -R is specified). By default, this does not update the copy of the
4575 project in the working directory.
4575 project in the working directory.
4576
4576
4577 Use :hg:`incoming` if you want to see what would have been added
4577 Use :hg:`incoming` if you want to see what would have been added
4578 by a pull at the time you issued this command. If you then decide
4578 by a pull at the time you issued this command. If you then decide
4579 to add those changes to the repository, you should use :hg:`pull
4579 to add those changes to the repository, you should use :hg:`pull
4580 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4580 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4581
4581
4582 If SOURCE is omitted, the 'default' path will be used.
4582 If SOURCE is omitted, the 'default' path will be used.
4583 See :hg:`help urls` for more information.
4583 See :hg:`help urls` for more information.
4584
4584
4585 Returns 0 on success, 1 if an update had unresolved files.
4585 Returns 0 on success, 1 if an update had unresolved files.
4586 """
4586 """
4587 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4587 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4588 other = hg.peer(repo, opts, source)
4588 other = hg.peer(repo, opts, source)
4589 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4589 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4590 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4590 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4591
4591
4592 remotebookmarks = other.listkeys('bookmarks')
4592 remotebookmarks = other.listkeys('bookmarks')
4593
4593
4594 if opts.get('bookmark'):
4594 if opts.get('bookmark'):
4595 if not revs:
4595 if not revs:
4596 revs = []
4596 revs = []
4597 for b in opts['bookmark']:
4597 for b in opts['bookmark']:
4598 if b not in remotebookmarks:
4598 if b not in remotebookmarks:
4599 raise util.Abort(_('remote bookmark %s not found!') % b)
4599 raise util.Abort(_('remote bookmark %s not found!') % b)
4600 revs.append(remotebookmarks[b])
4600 revs.append(remotebookmarks[b])
4601
4601
4602 if revs:
4602 if revs:
4603 try:
4603 try:
4604 revs = [other.lookup(rev) for rev in revs]
4604 revs = [other.lookup(rev) for rev in revs]
4605 except error.CapabilityError:
4605 except error.CapabilityError:
4606 err = _("other repository doesn't support revision lookup, "
4606 err = _("other repository doesn't support revision lookup, "
4607 "so a rev cannot be specified.")
4607 "so a rev cannot be specified.")
4608 raise util.Abort(err)
4608 raise util.Abort(err)
4609
4609
4610 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4610 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4611 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4611 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4612 if checkout:
4612 if checkout:
4613 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4613 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4614 repo._subtoppath = source
4614 repo._subtoppath = source
4615 try:
4615 try:
4616 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4616 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4617
4617
4618 finally:
4618 finally:
4619 del repo._subtoppath
4619 del repo._subtoppath
4620
4620
4621 # update specified bookmarks
4621 # update specified bookmarks
4622 if opts.get('bookmark'):
4622 if opts.get('bookmark'):
4623 marks = repo._bookmarks
4623 marks = repo._bookmarks
4624 for b in opts['bookmark']:
4624 for b in opts['bookmark']:
4625 # explicit pull overrides local bookmark if any
4625 # explicit pull overrides local bookmark if any
4626 ui.status(_("importing bookmark %s\n") % b)
4626 ui.status(_("importing bookmark %s\n") % b)
4627 marks[b] = repo[remotebookmarks[b]].node()
4627 marks[b] = repo[remotebookmarks[b]].node()
4628 marks.write()
4628 marks.write()
4629
4629
4630 return ret
4630 return ret
4631
4631
4632 @command('^push',
4632 @command('^push',
4633 [('f', 'force', None, _('force push')),
4633 [('f', 'force', None, _('force push')),
4634 ('r', 'rev', [],
4634 ('r', 'rev', [],
4635 _('a changeset intended to be included in the destination'),
4635 _('a changeset intended to be included in the destination'),
4636 _('REV')),
4636 _('REV')),
4637 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4637 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4638 ('b', 'branch', [],
4638 ('b', 'branch', [],
4639 _('a specific branch you would like to push'), _('BRANCH')),
4639 _('a specific branch you would like to push'), _('BRANCH')),
4640 ('', 'new-branch', False, _('allow pushing a new branch')),
4640 ('', 'new-branch', False, _('allow pushing a new branch')),
4641 ] + remoteopts,
4641 ] + remoteopts,
4642 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4642 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4643 def push(ui, repo, dest=None, **opts):
4643 def push(ui, repo, dest=None, **opts):
4644 """push changes to the specified destination
4644 """push changes to the specified destination
4645
4645
4646 Push changesets from the local repository to the specified
4646 Push changesets from the local repository to the specified
4647 destination.
4647 destination.
4648
4648
4649 This operation is symmetrical to pull: it is identical to a pull
4649 This operation is symmetrical to pull: it is identical to a pull
4650 in the destination repository from the current one.
4650 in the destination repository from the current one.
4651
4651
4652 By default, push will not allow creation of new heads at the
4652 By default, push will not allow creation of new heads at the
4653 destination, since multiple heads would make it unclear which head
4653 destination, since multiple heads would make it unclear which head
4654 to use. In this situation, it is recommended to pull and merge
4654 to use. In this situation, it is recommended to pull and merge
4655 before pushing.
4655 before pushing.
4656
4656
4657 Use --new-branch if you want to allow push to create a new named
4657 Use --new-branch if you want to allow push to create a new named
4658 branch that is not present at the destination. This allows you to
4658 branch that is not present at the destination. This allows you to
4659 only create a new branch without forcing other changes.
4659 only create a new branch without forcing other changes.
4660
4660
4661 .. note::
4661 .. note::
4662
4662
4663 Extra care should be taken with the -f/--force option,
4663 Extra care should be taken with the -f/--force option,
4664 which will push all new heads on all branches, an action which will
4664 which will push all new heads on all branches, an action which will
4665 almost always cause confusion for collaborators.
4665 almost always cause confusion for collaborators.
4666
4666
4667 If -r/--rev is used, the specified revision and all its ancestors
4667 If -r/--rev is used, the specified revision and all its ancestors
4668 will be pushed to the remote repository.
4668 will be pushed to the remote repository.
4669
4669
4670 If -B/--bookmark is used, the specified bookmarked revision, its
4670 If -B/--bookmark is used, the specified bookmarked revision, its
4671 ancestors, and the bookmark will be pushed to the remote
4671 ancestors, and the bookmark will be pushed to the remote
4672 repository.
4672 repository.
4673
4673
4674 Please see :hg:`help urls` for important details about ``ssh://``
4674 Please see :hg:`help urls` for important details about ``ssh://``
4675 URLs. If DESTINATION is omitted, a default path will be used.
4675 URLs. If DESTINATION is omitted, a default path will be used.
4676
4676
4677 Returns 0 if push was successful, 1 if nothing to push.
4677 Returns 0 if push was successful, 1 if nothing to push.
4678 """
4678 """
4679
4679
4680 if opts.get('bookmark'):
4680 if opts.get('bookmark'):
4681 for b in opts['bookmark']:
4681 for b in opts['bookmark']:
4682 # translate -B options to -r so changesets get pushed
4682 # translate -B options to -r so changesets get pushed
4683 if b in repo._bookmarks:
4683 if b in repo._bookmarks:
4684 opts.setdefault('rev', []).append(b)
4684 opts.setdefault('rev', []).append(b)
4685 else:
4685 else:
4686 # if we try to push a deleted bookmark, translate it to null
4686 # if we try to push a deleted bookmark, translate it to null
4687 # this lets simultaneous -r, -b options continue working
4687 # this lets simultaneous -r, -b options continue working
4688 opts.setdefault('rev', []).append("null")
4688 opts.setdefault('rev', []).append("null")
4689
4689
4690 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4690 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4691 dest, branches = hg.parseurl(dest, opts.get('branch'))
4691 dest, branches = hg.parseurl(dest, opts.get('branch'))
4692 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4692 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4693 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4693 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4694 other = hg.peer(repo, opts, dest)
4694 other = hg.peer(repo, opts, dest)
4695 if revs:
4695 if revs:
4696 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4696 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4697
4697
4698 repo._subtoppath = dest
4698 repo._subtoppath = dest
4699 try:
4699 try:
4700 # push subrepos depth-first for coherent ordering
4700 # push subrepos depth-first for coherent ordering
4701 c = repo['']
4701 c = repo['']
4702 subs = c.substate # only repos that are committed
4702 subs = c.substate # only repos that are committed
4703 for s in sorted(subs):
4703 for s in sorted(subs):
4704 if c.sub(s).push(opts) == 0:
4704 if c.sub(s).push(opts) == 0:
4705 return False
4705 return False
4706 finally:
4706 finally:
4707 del repo._subtoppath
4707 del repo._subtoppath
4708 result = repo.push(other, opts.get('force'), revs=revs,
4708 result = repo.push(other, opts.get('force'), revs=revs,
4709 newbranch=opts.get('new_branch'))
4709 newbranch=opts.get('new_branch'))
4710
4710
4711 result = not result
4711 result = not result
4712
4712
4713 if opts.get('bookmark'):
4713 if opts.get('bookmark'):
4714 rb = other.listkeys('bookmarks')
4714 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4715 for b in opts['bookmark']:
4715 if bresult == 2:
4716 # explicit push overrides remote bookmark if any
4716 return 2
4717 if b in repo._bookmarks:
4717 if not result and bresult:
4718 ui.status(_("exporting bookmark %s\n") % b)
4718 result = 2
4719 new = repo[b].hex()
4720 elif b in rb:
4721 ui.status(_("deleting remote bookmark %s\n") % b)
4722 new = '' # delete
4723 else:
4724 ui.warn(_('bookmark %s does not exist on the local '
4725 'or remote repository!\n') % b)
4726 return 2
4727 old = rb.get(b, '')
4728 r = other.pushkey('bookmarks', b, old, new)
4729 if not r:
4730 ui.warn(_('updating bookmark %s failed!\n') % b)
4731 if not result:
4732 result = 2
4733
4719
4734 return result
4720 return result
4735
4721
4736 @command('recover', [])
4722 @command('recover', [])
4737 def recover(ui, repo):
4723 def recover(ui, repo):
4738 """roll back an interrupted transaction
4724 """roll back an interrupted transaction
4739
4725
4740 Recover from an interrupted commit or pull.
4726 Recover from an interrupted commit or pull.
4741
4727
4742 This command tries to fix the repository status after an
4728 This command tries to fix the repository status after an
4743 interrupted operation. It should only be necessary when Mercurial
4729 interrupted operation. It should only be necessary when Mercurial
4744 suggests it.
4730 suggests it.
4745
4731
4746 Returns 0 if successful, 1 if nothing to recover or verify fails.
4732 Returns 0 if successful, 1 if nothing to recover or verify fails.
4747 """
4733 """
4748 if repo.recover():
4734 if repo.recover():
4749 return hg.verify(repo)
4735 return hg.verify(repo)
4750 return 1
4736 return 1
4751
4737
4752 @command('^remove|rm',
4738 @command('^remove|rm',
4753 [('A', 'after', None, _('record delete for missing files')),
4739 [('A', 'after', None, _('record delete for missing files')),
4754 ('f', 'force', None,
4740 ('f', 'force', None,
4755 _('remove (and delete) file even if added or modified')),
4741 _('remove (and delete) file even if added or modified')),
4756 ] + walkopts,
4742 ] + walkopts,
4757 _('[OPTION]... FILE...'))
4743 _('[OPTION]... FILE...'))
4758 def remove(ui, repo, *pats, **opts):
4744 def remove(ui, repo, *pats, **opts):
4759 """remove the specified files on the next commit
4745 """remove the specified files on the next commit
4760
4746
4761 Schedule the indicated files for removal from the current branch.
4747 Schedule the indicated files for removal from the current branch.
4762
4748
4763 This command schedules the files to be removed at the next commit.
4749 This command schedules the files to be removed at the next commit.
4764 To undo a remove before that, see :hg:`revert`. To undo added
4750 To undo a remove before that, see :hg:`revert`. To undo added
4765 files, see :hg:`forget`.
4751 files, see :hg:`forget`.
4766
4752
4767 .. container:: verbose
4753 .. container:: verbose
4768
4754
4769 -A/--after can be used to remove only files that have already
4755 -A/--after can be used to remove only files that have already
4770 been deleted, -f/--force can be used to force deletion, and -Af
4756 been deleted, -f/--force can be used to force deletion, and -Af
4771 can be used to remove files from the next revision without
4757 can be used to remove files from the next revision without
4772 deleting them from the working directory.
4758 deleting them from the working directory.
4773
4759
4774 The following table details the behavior of remove for different
4760 The following table details the behavior of remove for different
4775 file states (columns) and option combinations (rows). The file
4761 file states (columns) and option combinations (rows). The file
4776 states are Added [A], Clean [C], Modified [M] and Missing [!]
4762 states are Added [A], Clean [C], Modified [M] and Missing [!]
4777 (as reported by :hg:`status`). The actions are Warn, Remove
4763 (as reported by :hg:`status`). The actions are Warn, Remove
4778 (from branch) and Delete (from disk):
4764 (from branch) and Delete (from disk):
4779
4765
4780 ========= == == == ==
4766 ========= == == == ==
4781 opt/state A C M !
4767 opt/state A C M !
4782 ========= == == == ==
4768 ========= == == == ==
4783 none W RD W R
4769 none W RD W R
4784 -f R RD RD R
4770 -f R RD RD R
4785 -A W W W R
4771 -A W W W R
4786 -Af R R R R
4772 -Af R R R R
4787 ========= == == == ==
4773 ========= == == == ==
4788
4774
4789 Note that remove never deletes files in Added [A] state from the
4775 Note that remove never deletes files in Added [A] state from the
4790 working directory, not even if option --force is specified.
4776 working directory, not even if option --force is specified.
4791
4777
4792 Returns 0 on success, 1 if any warnings encountered.
4778 Returns 0 on success, 1 if any warnings encountered.
4793 """
4779 """
4794
4780
4795 ret = 0
4781 ret = 0
4796 after, force = opts.get('after'), opts.get('force')
4782 after, force = opts.get('after'), opts.get('force')
4797 if not pats and not after:
4783 if not pats and not after:
4798 raise util.Abort(_('no files specified'))
4784 raise util.Abort(_('no files specified'))
4799
4785
4800 m = scmutil.match(repo[None], pats, opts)
4786 m = scmutil.match(repo[None], pats, opts)
4801 s = repo.status(match=m, clean=True)
4787 s = repo.status(match=m, clean=True)
4802 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4788 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4803
4789
4804 # warn about failure to delete explicit files/dirs
4790 # warn about failure to delete explicit files/dirs
4805 wctx = repo[None]
4791 wctx = repo[None]
4806 for f in m.files():
4792 for f in m.files():
4807 if f in repo.dirstate or f in wctx.dirs():
4793 if f in repo.dirstate or f in wctx.dirs():
4808 continue
4794 continue
4809 if os.path.exists(m.rel(f)):
4795 if os.path.exists(m.rel(f)):
4810 if os.path.isdir(m.rel(f)):
4796 if os.path.isdir(m.rel(f)):
4811 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4797 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4812 else:
4798 else:
4813 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4799 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4814 # missing files will generate a warning elsewhere
4800 # missing files will generate a warning elsewhere
4815 ret = 1
4801 ret = 1
4816
4802
4817 if force:
4803 if force:
4818 list = modified + deleted + clean + added
4804 list = modified + deleted + clean + added
4819 elif after:
4805 elif after:
4820 list = deleted
4806 list = deleted
4821 for f in modified + added + clean:
4807 for f in modified + added + clean:
4822 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4808 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4823 ret = 1
4809 ret = 1
4824 else:
4810 else:
4825 list = deleted + clean
4811 list = deleted + clean
4826 for f in modified:
4812 for f in modified:
4827 ui.warn(_('not removing %s: file is modified (use -f'
4813 ui.warn(_('not removing %s: file is modified (use -f'
4828 ' to force removal)\n') % m.rel(f))
4814 ' to force removal)\n') % m.rel(f))
4829 ret = 1
4815 ret = 1
4830 for f in added:
4816 for f in added:
4831 ui.warn(_('not removing %s: file has been marked for add'
4817 ui.warn(_('not removing %s: file has been marked for add'
4832 ' (use forget to undo)\n') % m.rel(f))
4818 ' (use forget to undo)\n') % m.rel(f))
4833 ret = 1
4819 ret = 1
4834
4820
4835 for f in sorted(list):
4821 for f in sorted(list):
4836 if ui.verbose or not m.exact(f):
4822 if ui.verbose or not m.exact(f):
4837 ui.status(_('removing %s\n') % m.rel(f))
4823 ui.status(_('removing %s\n') % m.rel(f))
4838
4824
4839 wlock = repo.wlock()
4825 wlock = repo.wlock()
4840 try:
4826 try:
4841 if not after:
4827 if not after:
4842 for f in list:
4828 for f in list:
4843 if f in added:
4829 if f in added:
4844 continue # we never unlink added files on remove
4830 continue # we never unlink added files on remove
4845 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4831 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4846 repo[None].forget(list)
4832 repo[None].forget(list)
4847 finally:
4833 finally:
4848 wlock.release()
4834 wlock.release()
4849
4835
4850 return ret
4836 return ret
4851
4837
4852 @command('rename|move|mv',
4838 @command('rename|move|mv',
4853 [('A', 'after', None, _('record a rename that has already occurred')),
4839 [('A', 'after', None, _('record a rename that has already occurred')),
4854 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4840 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4855 ] + walkopts + dryrunopts,
4841 ] + walkopts + dryrunopts,
4856 _('[OPTION]... SOURCE... DEST'))
4842 _('[OPTION]... SOURCE... DEST'))
4857 def rename(ui, repo, *pats, **opts):
4843 def rename(ui, repo, *pats, **opts):
4858 """rename files; equivalent of copy + remove
4844 """rename files; equivalent of copy + remove
4859
4845
4860 Mark dest as copies of sources; mark sources for deletion. If dest
4846 Mark dest as copies of sources; mark sources for deletion. If dest
4861 is a directory, copies are put in that directory. If dest is a
4847 is a directory, copies are put in that directory. If dest is a
4862 file, there can only be one source.
4848 file, there can only be one source.
4863
4849
4864 By default, this command copies the contents of files as they
4850 By default, this command copies the contents of files as they
4865 exist in the working directory. If invoked with -A/--after, the
4851 exist in the working directory. If invoked with -A/--after, the
4866 operation is recorded, but no copying is performed.
4852 operation is recorded, but no copying is performed.
4867
4853
4868 This command takes effect at the next commit. To undo a rename
4854 This command takes effect at the next commit. To undo a rename
4869 before that, see :hg:`revert`.
4855 before that, see :hg:`revert`.
4870
4856
4871 Returns 0 on success, 1 if errors are encountered.
4857 Returns 0 on success, 1 if errors are encountered.
4872 """
4858 """
4873 wlock = repo.wlock(False)
4859 wlock = repo.wlock(False)
4874 try:
4860 try:
4875 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4861 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4876 finally:
4862 finally:
4877 wlock.release()
4863 wlock.release()
4878
4864
4879 @command('resolve',
4865 @command('resolve',
4880 [('a', 'all', None, _('select all unresolved files')),
4866 [('a', 'all', None, _('select all unresolved files')),
4881 ('l', 'list', None, _('list state of files needing merge')),
4867 ('l', 'list', None, _('list state of files needing merge')),
4882 ('m', 'mark', None, _('mark files as resolved')),
4868 ('m', 'mark', None, _('mark files as resolved')),
4883 ('u', 'unmark', None, _('mark files as unresolved')),
4869 ('u', 'unmark', None, _('mark files as unresolved')),
4884 ('n', 'no-status', None, _('hide status prefix'))]
4870 ('n', 'no-status', None, _('hide status prefix'))]
4885 + mergetoolopts + walkopts,
4871 + mergetoolopts + walkopts,
4886 _('[OPTION]... [FILE]...'))
4872 _('[OPTION]... [FILE]...'))
4887 def resolve(ui, repo, *pats, **opts):
4873 def resolve(ui, repo, *pats, **opts):
4888 """redo merges or set/view the merge status of files
4874 """redo merges or set/view the merge status of files
4889
4875
4890 Merges with unresolved conflicts are often the result of
4876 Merges with unresolved conflicts are often the result of
4891 non-interactive merging using the ``internal:merge`` configuration
4877 non-interactive merging using the ``internal:merge`` configuration
4892 setting, or a command-line merge tool like ``diff3``. The resolve
4878 setting, or a command-line merge tool like ``diff3``. The resolve
4893 command is used to manage the files involved in a merge, after
4879 command is used to manage the files involved in a merge, after
4894 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4880 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4895 working directory must have two parents). See :hg:`help
4881 working directory must have two parents). See :hg:`help
4896 merge-tools` for information on configuring merge tools.
4882 merge-tools` for information on configuring merge tools.
4897
4883
4898 The resolve command can be used in the following ways:
4884 The resolve command can be used in the following ways:
4899
4885
4900 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4886 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4901 files, discarding any previous merge attempts. Re-merging is not
4887 files, discarding any previous merge attempts. Re-merging is not
4902 performed for files already marked as resolved. Use ``--all/-a``
4888 performed for files already marked as resolved. Use ``--all/-a``
4903 to select all unresolved files. ``--tool`` can be used to specify
4889 to select all unresolved files. ``--tool`` can be used to specify
4904 the merge tool used for the given files. It overrides the HGMERGE
4890 the merge tool used for the given files. It overrides the HGMERGE
4905 environment variable and your configuration files. Previous file
4891 environment variable and your configuration files. Previous file
4906 contents are saved with a ``.orig`` suffix.
4892 contents are saved with a ``.orig`` suffix.
4907
4893
4908 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4894 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4909 (e.g. after having manually fixed-up the files). The default is
4895 (e.g. after having manually fixed-up the files). The default is
4910 to mark all unresolved files.
4896 to mark all unresolved files.
4911
4897
4912 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4898 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4913 default is to mark all resolved files.
4899 default is to mark all resolved files.
4914
4900
4915 - :hg:`resolve -l`: list files which had or still have conflicts.
4901 - :hg:`resolve -l`: list files which had or still have conflicts.
4916 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4902 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4917
4903
4918 Note that Mercurial will not let you commit files with unresolved
4904 Note that Mercurial will not let you commit files with unresolved
4919 merge conflicts. You must use :hg:`resolve -m ...` before you can
4905 merge conflicts. You must use :hg:`resolve -m ...` before you can
4920 commit after a conflicting merge.
4906 commit after a conflicting merge.
4921
4907
4922 Returns 0 on success, 1 if any files fail a resolve attempt.
4908 Returns 0 on success, 1 if any files fail a resolve attempt.
4923 """
4909 """
4924
4910
4925 all, mark, unmark, show, nostatus = \
4911 all, mark, unmark, show, nostatus = \
4926 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4912 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4927
4913
4928 if (show and (mark or unmark)) or (mark and unmark):
4914 if (show and (mark or unmark)) or (mark and unmark):
4929 raise util.Abort(_("too many options specified"))
4915 raise util.Abort(_("too many options specified"))
4930 if pats and all:
4916 if pats and all:
4931 raise util.Abort(_("can't specify --all and patterns"))
4917 raise util.Abort(_("can't specify --all and patterns"))
4932 if not (all or pats or show or mark or unmark):
4918 if not (all or pats or show or mark or unmark):
4933 raise util.Abort(_('no files or directories specified; '
4919 raise util.Abort(_('no files or directories specified; '
4934 'use --all to remerge all files'))
4920 'use --all to remerge all files'))
4935
4921
4936 ms = mergemod.mergestate(repo)
4922 ms = mergemod.mergestate(repo)
4937 m = scmutil.match(repo[None], pats, opts)
4923 m = scmutil.match(repo[None], pats, opts)
4938 ret = 0
4924 ret = 0
4939
4925
4940 for f in ms:
4926 for f in ms:
4941 if m(f):
4927 if m(f):
4942 if show:
4928 if show:
4943 if nostatus:
4929 if nostatus:
4944 ui.write("%s\n" % f)
4930 ui.write("%s\n" % f)
4945 else:
4931 else:
4946 ui.write("%s %s\n" % (ms[f].upper(), f),
4932 ui.write("%s %s\n" % (ms[f].upper(), f),
4947 label='resolve.' +
4933 label='resolve.' +
4948 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4934 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4949 elif mark:
4935 elif mark:
4950 ms.mark(f, "r")
4936 ms.mark(f, "r")
4951 elif unmark:
4937 elif unmark:
4952 ms.mark(f, "u")
4938 ms.mark(f, "u")
4953 else:
4939 else:
4954 wctx = repo[None]
4940 wctx = repo[None]
4955 mctx = wctx.parents()[-1]
4941 mctx = wctx.parents()[-1]
4956
4942
4957 # backup pre-resolve (merge uses .orig for its own purposes)
4943 # backup pre-resolve (merge uses .orig for its own purposes)
4958 a = repo.wjoin(f)
4944 a = repo.wjoin(f)
4959 util.copyfile(a, a + ".resolve")
4945 util.copyfile(a, a + ".resolve")
4960
4946
4961 try:
4947 try:
4962 # resolve file
4948 # resolve file
4963 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4949 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4964 if ms.resolve(f, wctx, mctx):
4950 if ms.resolve(f, wctx, mctx):
4965 ret = 1
4951 ret = 1
4966 finally:
4952 finally:
4967 ui.setconfig('ui', 'forcemerge', '')
4953 ui.setconfig('ui', 'forcemerge', '')
4968 ms.commit()
4954 ms.commit()
4969
4955
4970 # replace filemerge's .orig file with our resolve file
4956 # replace filemerge's .orig file with our resolve file
4971 util.rename(a + ".resolve", a + ".orig")
4957 util.rename(a + ".resolve", a + ".orig")
4972
4958
4973 ms.commit()
4959 ms.commit()
4974 return ret
4960 return ret
4975
4961
4976 @command('revert',
4962 @command('revert',
4977 [('a', 'all', None, _('revert all changes when no arguments given')),
4963 [('a', 'all', None, _('revert all changes when no arguments given')),
4978 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4964 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4979 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4965 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4980 ('C', 'no-backup', None, _('do not save backup copies of files')),
4966 ('C', 'no-backup', None, _('do not save backup copies of files')),
4981 ] + walkopts + dryrunopts,
4967 ] + walkopts + dryrunopts,
4982 _('[OPTION]... [-r REV] [NAME]...'))
4968 _('[OPTION]... [-r REV] [NAME]...'))
4983 def revert(ui, repo, *pats, **opts):
4969 def revert(ui, repo, *pats, **opts):
4984 """restore files to their checkout state
4970 """restore files to their checkout state
4985
4971
4986 .. note::
4972 .. note::
4987
4973
4988 To check out earlier revisions, you should use :hg:`update REV`.
4974 To check out earlier revisions, you should use :hg:`update REV`.
4989 To cancel an uncommitted merge (and lose your changes),
4975 To cancel an uncommitted merge (and lose your changes),
4990 use :hg:`update --clean .`.
4976 use :hg:`update --clean .`.
4991
4977
4992 With no revision specified, revert the specified files or directories
4978 With no revision specified, revert the specified files or directories
4993 to the contents they had in the parent of the working directory.
4979 to the contents they had in the parent of the working directory.
4994 This restores the contents of files to an unmodified
4980 This restores the contents of files to an unmodified
4995 state and unschedules adds, removes, copies, and renames. If the
4981 state and unschedules adds, removes, copies, and renames. If the
4996 working directory has two parents, you must explicitly specify a
4982 working directory has two parents, you must explicitly specify a
4997 revision.
4983 revision.
4998
4984
4999 Using the -r/--rev or -d/--date options, revert the given files or
4985 Using the -r/--rev or -d/--date options, revert the given files or
5000 directories to their states as of a specific revision. Because
4986 directories to their states as of a specific revision. Because
5001 revert does not change the working directory parents, this will
4987 revert does not change the working directory parents, this will
5002 cause these files to appear modified. This can be helpful to "back
4988 cause these files to appear modified. This can be helpful to "back
5003 out" some or all of an earlier change. See :hg:`backout` for a
4989 out" some or all of an earlier change. See :hg:`backout` for a
5004 related method.
4990 related method.
5005
4991
5006 Modified files are saved with a .orig suffix before reverting.
4992 Modified files are saved with a .orig suffix before reverting.
5007 To disable these backups, use --no-backup.
4993 To disable these backups, use --no-backup.
5008
4994
5009 See :hg:`help dates` for a list of formats valid for -d/--date.
4995 See :hg:`help dates` for a list of formats valid for -d/--date.
5010
4996
5011 Returns 0 on success.
4997 Returns 0 on success.
5012 """
4998 """
5013
4999
5014 if opts.get("date"):
5000 if opts.get("date"):
5015 if opts.get("rev"):
5001 if opts.get("rev"):
5016 raise util.Abort(_("you can't specify a revision and a date"))
5002 raise util.Abort(_("you can't specify a revision and a date"))
5017 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5003 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5018
5004
5019 parent, p2 = repo.dirstate.parents()
5005 parent, p2 = repo.dirstate.parents()
5020 if not opts.get('rev') and p2 != nullid:
5006 if not opts.get('rev') and p2 != nullid:
5021 # revert after merge is a trap for new users (issue2915)
5007 # revert after merge is a trap for new users (issue2915)
5022 raise util.Abort(_('uncommitted merge with no revision specified'),
5008 raise util.Abort(_('uncommitted merge with no revision specified'),
5023 hint=_('use "hg update" or see "hg help revert"'))
5009 hint=_('use "hg update" or see "hg help revert"'))
5024
5010
5025 ctx = scmutil.revsingle(repo, opts.get('rev'))
5011 ctx = scmutil.revsingle(repo, opts.get('rev'))
5026
5012
5027 if not pats and not opts.get('all'):
5013 if not pats and not opts.get('all'):
5028 msg = _("no files or directories specified")
5014 msg = _("no files or directories specified")
5029 if p2 != nullid:
5015 if p2 != nullid:
5030 hint = _("uncommitted merge, use --all to discard all changes,"
5016 hint = _("uncommitted merge, use --all to discard all changes,"
5031 " or 'hg update -C .' to abort the merge")
5017 " or 'hg update -C .' to abort the merge")
5032 raise util.Abort(msg, hint=hint)
5018 raise util.Abort(msg, hint=hint)
5033 dirty = util.any(repo.status())
5019 dirty = util.any(repo.status())
5034 node = ctx.node()
5020 node = ctx.node()
5035 if node != parent:
5021 if node != parent:
5036 if dirty:
5022 if dirty:
5037 hint = _("uncommitted changes, use --all to discard all"
5023 hint = _("uncommitted changes, use --all to discard all"
5038 " changes, or 'hg update %s' to update") % ctx.rev()
5024 " changes, or 'hg update %s' to update") % ctx.rev()
5039 else:
5025 else:
5040 hint = _("use --all to revert all files,"
5026 hint = _("use --all to revert all files,"
5041 " or 'hg update %s' to update") % ctx.rev()
5027 " or 'hg update %s' to update") % ctx.rev()
5042 elif dirty:
5028 elif dirty:
5043 hint = _("uncommitted changes, use --all to discard all changes")
5029 hint = _("uncommitted changes, use --all to discard all changes")
5044 else:
5030 else:
5045 hint = _("use --all to revert all files")
5031 hint = _("use --all to revert all files")
5046 raise util.Abort(msg, hint=hint)
5032 raise util.Abort(msg, hint=hint)
5047
5033
5048 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5034 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5049
5035
5050 @command('rollback', dryrunopts +
5036 @command('rollback', dryrunopts +
5051 [('f', 'force', False, _('ignore safety measures'))])
5037 [('f', 'force', False, _('ignore safety measures'))])
5052 def rollback(ui, repo, **opts):
5038 def rollback(ui, repo, **opts):
5053 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5039 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5054
5040
5055 Please use :hg:`commit --amend` instead of rollback to correct
5041 Please use :hg:`commit --amend` instead of rollback to correct
5056 mistakes in the last commit.
5042 mistakes in the last commit.
5057
5043
5058 This command should be used with care. There is only one level of
5044 This command should be used with care. There is only one level of
5059 rollback, and there is no way to undo a rollback. It will also
5045 rollback, and there is no way to undo a rollback. It will also
5060 restore the dirstate at the time of the last transaction, losing
5046 restore the dirstate at the time of the last transaction, losing
5061 any dirstate changes since that time. This command does not alter
5047 any dirstate changes since that time. This command does not alter
5062 the working directory.
5048 the working directory.
5063
5049
5064 Transactions are used to encapsulate the effects of all commands
5050 Transactions are used to encapsulate the effects of all commands
5065 that create new changesets or propagate existing changesets into a
5051 that create new changesets or propagate existing changesets into a
5066 repository.
5052 repository.
5067
5053
5068 .. container:: verbose
5054 .. container:: verbose
5069
5055
5070 For example, the following commands are transactional, and their
5056 For example, the following commands are transactional, and their
5071 effects can be rolled back:
5057 effects can be rolled back:
5072
5058
5073 - commit
5059 - commit
5074 - import
5060 - import
5075 - pull
5061 - pull
5076 - push (with this repository as the destination)
5062 - push (with this repository as the destination)
5077 - unbundle
5063 - unbundle
5078
5064
5079 To avoid permanent data loss, rollback will refuse to rollback a
5065 To avoid permanent data loss, rollback will refuse to rollback a
5080 commit transaction if it isn't checked out. Use --force to
5066 commit transaction if it isn't checked out. Use --force to
5081 override this protection.
5067 override this protection.
5082
5068
5083 This command is not intended for use on public repositories. Once
5069 This command is not intended for use on public repositories. Once
5084 changes are visible for pull by other users, rolling a transaction
5070 changes are visible for pull by other users, rolling a transaction
5085 back locally is ineffective (someone else may already have pulled
5071 back locally is ineffective (someone else may already have pulled
5086 the changes). Furthermore, a race is possible with readers of the
5072 the changes). Furthermore, a race is possible with readers of the
5087 repository; for example an in-progress pull from the repository
5073 repository; for example an in-progress pull from the repository
5088 may fail if a rollback is performed.
5074 may fail if a rollback is performed.
5089
5075
5090 Returns 0 on success, 1 if no rollback data is available.
5076 Returns 0 on success, 1 if no rollback data is available.
5091 """
5077 """
5092 return repo.rollback(dryrun=opts.get('dry_run'),
5078 return repo.rollback(dryrun=opts.get('dry_run'),
5093 force=opts.get('force'))
5079 force=opts.get('force'))
5094
5080
5095 @command('root', [])
5081 @command('root', [])
5096 def root(ui, repo):
5082 def root(ui, repo):
5097 """print the root (top) of the current working directory
5083 """print the root (top) of the current working directory
5098
5084
5099 Print the root directory of the current repository.
5085 Print the root directory of the current repository.
5100
5086
5101 Returns 0 on success.
5087 Returns 0 on success.
5102 """
5088 """
5103 ui.write(repo.root + "\n")
5089 ui.write(repo.root + "\n")
5104
5090
5105 @command('^serve',
5091 @command('^serve',
5106 [('A', 'accesslog', '', _('name of access log file to write to'),
5092 [('A', 'accesslog', '', _('name of access log file to write to'),
5107 _('FILE')),
5093 _('FILE')),
5108 ('d', 'daemon', None, _('run server in background')),
5094 ('d', 'daemon', None, _('run server in background')),
5109 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5095 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5110 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5096 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5111 # use string type, then we can check if something was passed
5097 # use string type, then we can check if something was passed
5112 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5098 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5113 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5099 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5114 _('ADDR')),
5100 _('ADDR')),
5115 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5101 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5116 _('PREFIX')),
5102 _('PREFIX')),
5117 ('n', 'name', '',
5103 ('n', 'name', '',
5118 _('name to show in web pages (default: working directory)'), _('NAME')),
5104 _('name to show in web pages (default: working directory)'), _('NAME')),
5119 ('', 'web-conf', '',
5105 ('', 'web-conf', '',
5120 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5106 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5121 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5107 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5122 _('FILE')),
5108 _('FILE')),
5123 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5109 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5124 ('', 'stdio', None, _('for remote clients')),
5110 ('', 'stdio', None, _('for remote clients')),
5125 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5111 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5126 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5112 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5127 ('', 'style', '', _('template style to use'), _('STYLE')),
5113 ('', 'style', '', _('template style to use'), _('STYLE')),
5128 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5114 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5129 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5115 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5130 _('[OPTION]...'))
5116 _('[OPTION]...'))
5131 def serve(ui, repo, **opts):
5117 def serve(ui, repo, **opts):
5132 """start stand-alone webserver
5118 """start stand-alone webserver
5133
5119
5134 Start a local HTTP repository browser and pull server. You can use
5120 Start a local HTTP repository browser and pull server. You can use
5135 this for ad-hoc sharing and browsing of repositories. It is
5121 this for ad-hoc sharing and browsing of repositories. It is
5136 recommended to use a real web server to serve a repository for
5122 recommended to use a real web server to serve a repository for
5137 longer periods of time.
5123 longer periods of time.
5138
5124
5139 Please note that the server does not implement access control.
5125 Please note that the server does not implement access control.
5140 This means that, by default, anybody can read from the server and
5126 This means that, by default, anybody can read from the server and
5141 nobody can write to it by default. Set the ``web.allow_push``
5127 nobody can write to it by default. Set the ``web.allow_push``
5142 option to ``*`` to allow everybody to push to the server. You
5128 option to ``*`` to allow everybody to push to the server. You
5143 should use a real web server if you need to authenticate users.
5129 should use a real web server if you need to authenticate users.
5144
5130
5145 By default, the server logs accesses to stdout and errors to
5131 By default, the server logs accesses to stdout and errors to
5146 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5132 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5147 files.
5133 files.
5148
5134
5149 To have the server choose a free port number to listen on, specify
5135 To have the server choose a free port number to listen on, specify
5150 a port number of 0; in this case, the server will print the port
5136 a port number of 0; in this case, the server will print the port
5151 number it uses.
5137 number it uses.
5152
5138
5153 Returns 0 on success.
5139 Returns 0 on success.
5154 """
5140 """
5155
5141
5156 if opts["stdio"] and opts["cmdserver"]:
5142 if opts["stdio"] and opts["cmdserver"]:
5157 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5143 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5158
5144
5159 def checkrepo():
5145 def checkrepo():
5160 if repo is None:
5146 if repo is None:
5161 raise error.RepoError(_("there is no Mercurial repository here"
5147 raise error.RepoError(_("there is no Mercurial repository here"
5162 " (.hg not found)"))
5148 " (.hg not found)"))
5163
5149
5164 if opts["stdio"]:
5150 if opts["stdio"]:
5165 checkrepo()
5151 checkrepo()
5166 s = sshserver.sshserver(ui, repo)
5152 s = sshserver.sshserver(ui, repo)
5167 s.serve_forever()
5153 s.serve_forever()
5168
5154
5169 if opts["cmdserver"]:
5155 if opts["cmdserver"]:
5170 checkrepo()
5156 checkrepo()
5171 s = commandserver.server(ui, repo, opts["cmdserver"])
5157 s = commandserver.server(ui, repo, opts["cmdserver"])
5172 return s.serve()
5158 return s.serve()
5173
5159
5174 # this way we can check if something was given in the command-line
5160 # this way we can check if something was given in the command-line
5175 if opts.get('port'):
5161 if opts.get('port'):
5176 opts['port'] = util.getport(opts.get('port'))
5162 opts['port'] = util.getport(opts.get('port'))
5177
5163
5178 baseui = repo and repo.baseui or ui
5164 baseui = repo and repo.baseui or ui
5179 optlist = ("name templates style address port prefix ipv6"
5165 optlist = ("name templates style address port prefix ipv6"
5180 " accesslog errorlog certificate encoding")
5166 " accesslog errorlog certificate encoding")
5181 for o in optlist.split():
5167 for o in optlist.split():
5182 val = opts.get(o, '')
5168 val = opts.get(o, '')
5183 if val in (None, ''): # should check against default options instead
5169 if val in (None, ''): # should check against default options instead
5184 continue
5170 continue
5185 baseui.setconfig("web", o, val)
5171 baseui.setconfig("web", o, val)
5186 if repo and repo.ui != baseui:
5172 if repo and repo.ui != baseui:
5187 repo.ui.setconfig("web", o, val)
5173 repo.ui.setconfig("web", o, val)
5188
5174
5189 o = opts.get('web_conf') or opts.get('webdir_conf')
5175 o = opts.get('web_conf') or opts.get('webdir_conf')
5190 if not o:
5176 if not o:
5191 if not repo:
5177 if not repo:
5192 raise error.RepoError(_("there is no Mercurial repository"
5178 raise error.RepoError(_("there is no Mercurial repository"
5193 " here (.hg not found)"))
5179 " here (.hg not found)"))
5194 o = repo
5180 o = repo
5195
5181
5196 app = hgweb.hgweb(o, baseui=baseui)
5182 app = hgweb.hgweb(o, baseui=baseui)
5197 service = httpservice(ui, app, opts)
5183 service = httpservice(ui, app, opts)
5198 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5184 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5199
5185
5200 class httpservice(object):
5186 class httpservice(object):
5201 def __init__(self, ui, app, opts):
5187 def __init__(self, ui, app, opts):
5202 self.ui = ui
5188 self.ui = ui
5203 self.app = app
5189 self.app = app
5204 self.opts = opts
5190 self.opts = opts
5205
5191
5206 def init(self):
5192 def init(self):
5207 util.setsignalhandler()
5193 util.setsignalhandler()
5208 self.httpd = hgweb_server.create_server(self.ui, self.app)
5194 self.httpd = hgweb_server.create_server(self.ui, self.app)
5209
5195
5210 if self.opts['port'] and not self.ui.verbose:
5196 if self.opts['port'] and not self.ui.verbose:
5211 return
5197 return
5212
5198
5213 if self.httpd.prefix:
5199 if self.httpd.prefix:
5214 prefix = self.httpd.prefix.strip('/') + '/'
5200 prefix = self.httpd.prefix.strip('/') + '/'
5215 else:
5201 else:
5216 prefix = ''
5202 prefix = ''
5217
5203
5218 port = ':%d' % self.httpd.port
5204 port = ':%d' % self.httpd.port
5219 if port == ':80':
5205 if port == ':80':
5220 port = ''
5206 port = ''
5221
5207
5222 bindaddr = self.httpd.addr
5208 bindaddr = self.httpd.addr
5223 if bindaddr == '0.0.0.0':
5209 if bindaddr == '0.0.0.0':
5224 bindaddr = '*'
5210 bindaddr = '*'
5225 elif ':' in bindaddr: # IPv6
5211 elif ':' in bindaddr: # IPv6
5226 bindaddr = '[%s]' % bindaddr
5212 bindaddr = '[%s]' % bindaddr
5227
5213
5228 fqaddr = self.httpd.fqaddr
5214 fqaddr = self.httpd.fqaddr
5229 if ':' in fqaddr:
5215 if ':' in fqaddr:
5230 fqaddr = '[%s]' % fqaddr
5216 fqaddr = '[%s]' % fqaddr
5231 if self.opts['port']:
5217 if self.opts['port']:
5232 write = self.ui.status
5218 write = self.ui.status
5233 else:
5219 else:
5234 write = self.ui.write
5220 write = self.ui.write
5235 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5221 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5236 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5222 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5237
5223
5238 def run(self):
5224 def run(self):
5239 self.httpd.serve_forever()
5225 self.httpd.serve_forever()
5240
5226
5241
5227
5242 @command('showconfig|debugconfig',
5228 @command('showconfig|debugconfig',
5243 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5229 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5244 _('[-u] [NAME]...'))
5230 _('[-u] [NAME]...'))
5245 def showconfig(ui, repo, *values, **opts):
5231 def showconfig(ui, repo, *values, **opts):
5246 """show combined config settings from all hgrc files
5232 """show combined config settings from all hgrc files
5247
5233
5248 With no arguments, print names and values of all config items.
5234 With no arguments, print names and values of all config items.
5249
5235
5250 With one argument of the form section.name, print just the value
5236 With one argument of the form section.name, print just the value
5251 of that config item.
5237 of that config item.
5252
5238
5253 With multiple arguments, print names and values of all config
5239 With multiple arguments, print names and values of all config
5254 items with matching section names.
5240 items with matching section names.
5255
5241
5256 With --debug, the source (filename and line number) is printed
5242 With --debug, the source (filename and line number) is printed
5257 for each config item.
5243 for each config item.
5258
5244
5259 Returns 0 on success.
5245 Returns 0 on success.
5260 """
5246 """
5261
5247
5262 for f in scmutil.rcpath():
5248 for f in scmutil.rcpath():
5263 ui.debug('read config from: %s\n' % f)
5249 ui.debug('read config from: %s\n' % f)
5264 untrusted = bool(opts.get('untrusted'))
5250 untrusted = bool(opts.get('untrusted'))
5265 if values:
5251 if values:
5266 sections = [v for v in values if '.' not in v]
5252 sections = [v for v in values if '.' not in v]
5267 items = [v for v in values if '.' in v]
5253 items = [v for v in values if '.' in v]
5268 if len(items) > 1 or items and sections:
5254 if len(items) > 1 or items and sections:
5269 raise util.Abort(_('only one config item permitted'))
5255 raise util.Abort(_('only one config item permitted'))
5270 for section, name, value in ui.walkconfig(untrusted=untrusted):
5256 for section, name, value in ui.walkconfig(untrusted=untrusted):
5271 value = str(value).replace('\n', '\\n')
5257 value = str(value).replace('\n', '\\n')
5272 sectname = section + '.' + name
5258 sectname = section + '.' + name
5273 if values:
5259 if values:
5274 for v in values:
5260 for v in values:
5275 if v == section:
5261 if v == section:
5276 ui.debug('%s: ' %
5262 ui.debug('%s: ' %
5277 ui.configsource(section, name, untrusted))
5263 ui.configsource(section, name, untrusted))
5278 ui.write('%s=%s\n' % (sectname, value))
5264 ui.write('%s=%s\n' % (sectname, value))
5279 elif v == sectname:
5265 elif v == sectname:
5280 ui.debug('%s: ' %
5266 ui.debug('%s: ' %
5281 ui.configsource(section, name, untrusted))
5267 ui.configsource(section, name, untrusted))
5282 ui.write(value, '\n')
5268 ui.write(value, '\n')
5283 else:
5269 else:
5284 ui.debug('%s: ' %
5270 ui.debug('%s: ' %
5285 ui.configsource(section, name, untrusted))
5271 ui.configsource(section, name, untrusted))
5286 ui.write('%s=%s\n' % (sectname, value))
5272 ui.write('%s=%s\n' % (sectname, value))
5287
5273
5288 @command('^status|st',
5274 @command('^status|st',
5289 [('A', 'all', None, _('show status of all files')),
5275 [('A', 'all', None, _('show status of all files')),
5290 ('m', 'modified', None, _('show only modified files')),
5276 ('m', 'modified', None, _('show only modified files')),
5291 ('a', 'added', None, _('show only added files')),
5277 ('a', 'added', None, _('show only added files')),
5292 ('r', 'removed', None, _('show only removed files')),
5278 ('r', 'removed', None, _('show only removed files')),
5293 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5279 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5294 ('c', 'clean', None, _('show only files without changes')),
5280 ('c', 'clean', None, _('show only files without changes')),
5295 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5281 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5296 ('i', 'ignored', None, _('show only ignored files')),
5282 ('i', 'ignored', None, _('show only ignored files')),
5297 ('n', 'no-status', None, _('hide status prefix')),
5283 ('n', 'no-status', None, _('hide status prefix')),
5298 ('C', 'copies', None, _('show source of copied files')),
5284 ('C', 'copies', None, _('show source of copied files')),
5299 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5285 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5300 ('', 'rev', [], _('show difference from revision'), _('REV')),
5286 ('', 'rev', [], _('show difference from revision'), _('REV')),
5301 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5287 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5302 ] + walkopts + subrepoopts,
5288 ] + walkopts + subrepoopts,
5303 _('[OPTION]... [FILE]...'))
5289 _('[OPTION]... [FILE]...'))
5304 def status(ui, repo, *pats, **opts):
5290 def status(ui, repo, *pats, **opts):
5305 """show changed files in the working directory
5291 """show changed files in the working directory
5306
5292
5307 Show status of files in the repository. If names are given, only
5293 Show status of files in the repository. If names are given, only
5308 files that match are shown. Files that are clean or ignored or
5294 files that match are shown. Files that are clean or ignored or
5309 the source of a copy/move operation, are not listed unless
5295 the source of a copy/move operation, are not listed unless
5310 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5296 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5311 Unless options described with "show only ..." are given, the
5297 Unless options described with "show only ..." are given, the
5312 options -mardu are used.
5298 options -mardu are used.
5313
5299
5314 Option -q/--quiet hides untracked (unknown and ignored) files
5300 Option -q/--quiet hides untracked (unknown and ignored) files
5315 unless explicitly requested with -u/--unknown or -i/--ignored.
5301 unless explicitly requested with -u/--unknown or -i/--ignored.
5316
5302
5317 .. note::
5303 .. note::
5318
5304
5319 status may appear to disagree with diff if permissions have
5305 status may appear to disagree with diff if permissions have
5320 changed or a merge has occurred. The standard diff format does
5306 changed or a merge has occurred. The standard diff format does
5321 not report permission changes and diff only reports changes
5307 not report permission changes and diff only reports changes
5322 relative to one merge parent.
5308 relative to one merge parent.
5323
5309
5324 If one revision is given, it is used as the base revision.
5310 If one revision is given, it is used as the base revision.
5325 If two revisions are given, the differences between them are
5311 If two revisions are given, the differences between them are
5326 shown. The --change option can also be used as a shortcut to list
5312 shown. The --change option can also be used as a shortcut to list
5327 the changed files of a revision from its first parent.
5313 the changed files of a revision from its first parent.
5328
5314
5329 The codes used to show the status of files are::
5315 The codes used to show the status of files are::
5330
5316
5331 M = modified
5317 M = modified
5332 A = added
5318 A = added
5333 R = removed
5319 R = removed
5334 C = clean
5320 C = clean
5335 ! = missing (deleted by non-hg command, but still tracked)
5321 ! = missing (deleted by non-hg command, but still tracked)
5336 ? = not tracked
5322 ? = not tracked
5337 I = ignored
5323 I = ignored
5338 = origin of the previous file listed as A (added)
5324 = origin of the previous file listed as A (added)
5339
5325
5340 .. container:: verbose
5326 .. container:: verbose
5341
5327
5342 Examples:
5328 Examples:
5343
5329
5344 - show changes in the working directory relative to a
5330 - show changes in the working directory relative to a
5345 changeset::
5331 changeset::
5346
5332
5347 hg status --rev 9353
5333 hg status --rev 9353
5348
5334
5349 - show all changes including copies in an existing changeset::
5335 - show all changes including copies in an existing changeset::
5350
5336
5351 hg status --copies --change 9353
5337 hg status --copies --change 9353
5352
5338
5353 - get a NUL separated list of added files, suitable for xargs::
5339 - get a NUL separated list of added files, suitable for xargs::
5354
5340
5355 hg status -an0
5341 hg status -an0
5356
5342
5357 Returns 0 on success.
5343 Returns 0 on success.
5358 """
5344 """
5359
5345
5360 revs = opts.get('rev')
5346 revs = opts.get('rev')
5361 change = opts.get('change')
5347 change = opts.get('change')
5362
5348
5363 if revs and change:
5349 if revs and change:
5364 msg = _('cannot specify --rev and --change at the same time')
5350 msg = _('cannot specify --rev and --change at the same time')
5365 raise util.Abort(msg)
5351 raise util.Abort(msg)
5366 elif change:
5352 elif change:
5367 node2 = scmutil.revsingle(repo, change, None).node()
5353 node2 = scmutil.revsingle(repo, change, None).node()
5368 node1 = repo[node2].p1().node()
5354 node1 = repo[node2].p1().node()
5369 else:
5355 else:
5370 node1, node2 = scmutil.revpair(repo, revs)
5356 node1, node2 = scmutil.revpair(repo, revs)
5371
5357
5372 cwd = (pats and repo.getcwd()) or ''
5358 cwd = (pats and repo.getcwd()) or ''
5373 end = opts.get('print0') and '\0' or '\n'
5359 end = opts.get('print0') and '\0' or '\n'
5374 copy = {}
5360 copy = {}
5375 states = 'modified added removed deleted unknown ignored clean'.split()
5361 states = 'modified added removed deleted unknown ignored clean'.split()
5376 show = [k for k in states if opts.get(k)]
5362 show = [k for k in states if opts.get(k)]
5377 if opts.get('all'):
5363 if opts.get('all'):
5378 show += ui.quiet and (states[:4] + ['clean']) or states
5364 show += ui.quiet and (states[:4] + ['clean']) or states
5379 if not show:
5365 if not show:
5380 show = ui.quiet and states[:4] or states[:5]
5366 show = ui.quiet and states[:4] or states[:5]
5381
5367
5382 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5368 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5383 'ignored' in show, 'clean' in show, 'unknown' in show,
5369 'ignored' in show, 'clean' in show, 'unknown' in show,
5384 opts.get('subrepos'))
5370 opts.get('subrepos'))
5385 changestates = zip(states, 'MAR!?IC', stat)
5371 changestates = zip(states, 'MAR!?IC', stat)
5386
5372
5387 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5373 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5388 copy = copies.pathcopies(repo[node1], repo[node2])
5374 copy = copies.pathcopies(repo[node1], repo[node2])
5389
5375
5390 fm = ui.formatter('status', opts)
5376 fm = ui.formatter('status', opts)
5391 fmt = '%s' + end
5377 fmt = '%s' + end
5392 showchar = not opts.get('no_status')
5378 showchar = not opts.get('no_status')
5393
5379
5394 for state, char, files in changestates:
5380 for state, char, files in changestates:
5395 if state in show:
5381 if state in show:
5396 label = 'status.' + state
5382 label = 'status.' + state
5397 for f in files:
5383 for f in files:
5398 fm.startitem()
5384 fm.startitem()
5399 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5385 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5400 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5386 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5401 if f in copy:
5387 if f in copy:
5402 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5388 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5403 label='status.copied')
5389 label='status.copied')
5404 fm.end()
5390 fm.end()
5405
5391
5406 @command('^summary|sum',
5392 @command('^summary|sum',
5407 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5393 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5408 def summary(ui, repo, **opts):
5394 def summary(ui, repo, **opts):
5409 """summarize working directory state
5395 """summarize working directory state
5410
5396
5411 This generates a brief summary of the working directory state,
5397 This generates a brief summary of the working directory state,
5412 including parents, branch, commit status, and available updates.
5398 including parents, branch, commit status, and available updates.
5413
5399
5414 With the --remote option, this will check the default paths for
5400 With the --remote option, this will check the default paths for
5415 incoming and outgoing changes. This can be time-consuming.
5401 incoming and outgoing changes. This can be time-consuming.
5416
5402
5417 Returns 0 on success.
5403 Returns 0 on success.
5418 """
5404 """
5419
5405
5420 ctx = repo[None]
5406 ctx = repo[None]
5421 parents = ctx.parents()
5407 parents = ctx.parents()
5422 pnode = parents[0].node()
5408 pnode = parents[0].node()
5423 marks = []
5409 marks = []
5424
5410
5425 for p in parents:
5411 for p in parents:
5426 # label with log.changeset (instead of log.parent) since this
5412 # label with log.changeset (instead of log.parent) since this
5427 # shows a working directory parent *changeset*:
5413 # shows a working directory parent *changeset*:
5428 # i18n: column positioning for "hg summary"
5414 # i18n: column positioning for "hg summary"
5429 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5415 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5430 label='log.changeset changeset.%s' % p.phasestr())
5416 label='log.changeset changeset.%s' % p.phasestr())
5431 ui.write(' '.join(p.tags()), label='log.tag')
5417 ui.write(' '.join(p.tags()), label='log.tag')
5432 if p.bookmarks():
5418 if p.bookmarks():
5433 marks.extend(p.bookmarks())
5419 marks.extend(p.bookmarks())
5434 if p.rev() == -1:
5420 if p.rev() == -1:
5435 if not len(repo):
5421 if not len(repo):
5436 ui.write(_(' (empty repository)'))
5422 ui.write(_(' (empty repository)'))
5437 else:
5423 else:
5438 ui.write(_(' (no revision checked out)'))
5424 ui.write(_(' (no revision checked out)'))
5439 ui.write('\n')
5425 ui.write('\n')
5440 if p.description():
5426 if p.description():
5441 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5427 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5442 label='log.summary')
5428 label='log.summary')
5443
5429
5444 branch = ctx.branch()
5430 branch = ctx.branch()
5445 bheads = repo.branchheads(branch)
5431 bheads = repo.branchheads(branch)
5446 # i18n: column positioning for "hg summary"
5432 # i18n: column positioning for "hg summary"
5447 m = _('branch: %s\n') % branch
5433 m = _('branch: %s\n') % branch
5448 if branch != 'default':
5434 if branch != 'default':
5449 ui.write(m, label='log.branch')
5435 ui.write(m, label='log.branch')
5450 else:
5436 else:
5451 ui.status(m, label='log.branch')
5437 ui.status(m, label='log.branch')
5452
5438
5453 if marks:
5439 if marks:
5454 current = repo._bookmarkcurrent
5440 current = repo._bookmarkcurrent
5455 # i18n: column positioning for "hg summary"
5441 # i18n: column positioning for "hg summary"
5456 ui.write(_('bookmarks:'), label='log.bookmark')
5442 ui.write(_('bookmarks:'), label='log.bookmark')
5457 if current is not None:
5443 if current is not None:
5458 if current in marks:
5444 if current in marks:
5459 ui.write(' *' + current, label='bookmarks.current')
5445 ui.write(' *' + current, label='bookmarks.current')
5460 marks.remove(current)
5446 marks.remove(current)
5461 else:
5447 else:
5462 ui.write(' [%s]' % current, label='bookmarks.current')
5448 ui.write(' [%s]' % current, label='bookmarks.current')
5463 for m in marks:
5449 for m in marks:
5464 ui.write(' ' + m, label='log.bookmark')
5450 ui.write(' ' + m, label='log.bookmark')
5465 ui.write('\n', label='log.bookmark')
5451 ui.write('\n', label='log.bookmark')
5466
5452
5467 st = list(repo.status(unknown=True))[:6]
5453 st = list(repo.status(unknown=True))[:6]
5468
5454
5469 c = repo.dirstate.copies()
5455 c = repo.dirstate.copies()
5470 copied, renamed = [], []
5456 copied, renamed = [], []
5471 for d, s in c.iteritems():
5457 for d, s in c.iteritems():
5472 if s in st[2]:
5458 if s in st[2]:
5473 st[2].remove(s)
5459 st[2].remove(s)
5474 renamed.append(d)
5460 renamed.append(d)
5475 else:
5461 else:
5476 copied.append(d)
5462 copied.append(d)
5477 if d in st[1]:
5463 if d in st[1]:
5478 st[1].remove(d)
5464 st[1].remove(d)
5479 st.insert(3, renamed)
5465 st.insert(3, renamed)
5480 st.insert(4, copied)
5466 st.insert(4, copied)
5481
5467
5482 ms = mergemod.mergestate(repo)
5468 ms = mergemod.mergestate(repo)
5483 st.append([f for f in ms if ms[f] == 'u'])
5469 st.append([f for f in ms if ms[f] == 'u'])
5484
5470
5485 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5471 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5486 st.append(subs)
5472 st.append(subs)
5487
5473
5488 labels = [ui.label(_('%d modified'), 'status.modified'),
5474 labels = [ui.label(_('%d modified'), 'status.modified'),
5489 ui.label(_('%d added'), 'status.added'),
5475 ui.label(_('%d added'), 'status.added'),
5490 ui.label(_('%d removed'), 'status.removed'),
5476 ui.label(_('%d removed'), 'status.removed'),
5491 ui.label(_('%d renamed'), 'status.copied'),
5477 ui.label(_('%d renamed'), 'status.copied'),
5492 ui.label(_('%d copied'), 'status.copied'),
5478 ui.label(_('%d copied'), 'status.copied'),
5493 ui.label(_('%d deleted'), 'status.deleted'),
5479 ui.label(_('%d deleted'), 'status.deleted'),
5494 ui.label(_('%d unknown'), 'status.unknown'),
5480 ui.label(_('%d unknown'), 'status.unknown'),
5495 ui.label(_('%d ignored'), 'status.ignored'),
5481 ui.label(_('%d ignored'), 'status.ignored'),
5496 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5482 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5497 ui.label(_('%d subrepos'), 'status.modified')]
5483 ui.label(_('%d subrepos'), 'status.modified')]
5498 t = []
5484 t = []
5499 for s, l in zip(st, labels):
5485 for s, l in zip(st, labels):
5500 if s:
5486 if s:
5501 t.append(l % len(s))
5487 t.append(l % len(s))
5502
5488
5503 t = ', '.join(t)
5489 t = ', '.join(t)
5504 cleanworkdir = False
5490 cleanworkdir = False
5505
5491
5506 if repo.vfs.exists('updatestate'):
5492 if repo.vfs.exists('updatestate'):
5507 t += _(' (interrupted update)')
5493 t += _(' (interrupted update)')
5508 elif len(parents) > 1:
5494 elif len(parents) > 1:
5509 t += _(' (merge)')
5495 t += _(' (merge)')
5510 elif branch != parents[0].branch():
5496 elif branch != parents[0].branch():
5511 t += _(' (new branch)')
5497 t += _(' (new branch)')
5512 elif (parents[0].closesbranch() and
5498 elif (parents[0].closesbranch() and
5513 pnode in repo.branchheads(branch, closed=True)):
5499 pnode in repo.branchheads(branch, closed=True)):
5514 t += _(' (head closed)')
5500 t += _(' (head closed)')
5515 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5501 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5516 t += _(' (clean)')
5502 t += _(' (clean)')
5517 cleanworkdir = True
5503 cleanworkdir = True
5518 elif pnode not in bheads:
5504 elif pnode not in bheads:
5519 t += _(' (new branch head)')
5505 t += _(' (new branch head)')
5520
5506
5521 if cleanworkdir:
5507 if cleanworkdir:
5522 # i18n: column positioning for "hg summary"
5508 # i18n: column positioning for "hg summary"
5523 ui.status(_('commit: %s\n') % t.strip())
5509 ui.status(_('commit: %s\n') % t.strip())
5524 else:
5510 else:
5525 # i18n: column positioning for "hg summary"
5511 # i18n: column positioning for "hg summary"
5526 ui.write(_('commit: %s\n') % t.strip())
5512 ui.write(_('commit: %s\n') % t.strip())
5527
5513
5528 # all ancestors of branch heads - all ancestors of parent = new csets
5514 # all ancestors of branch heads - all ancestors of parent = new csets
5529 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5515 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5530 bheads))
5516 bheads))
5531
5517
5532 if new == 0:
5518 if new == 0:
5533 # i18n: column positioning for "hg summary"
5519 # i18n: column positioning for "hg summary"
5534 ui.status(_('update: (current)\n'))
5520 ui.status(_('update: (current)\n'))
5535 elif pnode not in bheads:
5521 elif pnode not in bheads:
5536 # i18n: column positioning for "hg summary"
5522 # i18n: column positioning for "hg summary"
5537 ui.write(_('update: %d new changesets (update)\n') % new)
5523 ui.write(_('update: %d new changesets (update)\n') % new)
5538 else:
5524 else:
5539 # i18n: column positioning for "hg summary"
5525 # i18n: column positioning for "hg summary"
5540 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5526 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5541 (new, len(bheads)))
5527 (new, len(bheads)))
5542
5528
5543 cmdutil.summaryhooks(ui, repo)
5529 cmdutil.summaryhooks(ui, repo)
5544
5530
5545 if opts.get('remote'):
5531 if opts.get('remote'):
5546 t = []
5532 t = []
5547 source, branches = hg.parseurl(ui.expandpath('default'))
5533 source, branches = hg.parseurl(ui.expandpath('default'))
5548 sbranch = branches[0]
5534 sbranch = branches[0]
5549 other = hg.peer(repo, {}, source)
5535 other = hg.peer(repo, {}, source)
5550 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5536 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5551 if revs:
5537 if revs:
5552 revs = [other.lookup(rev) for rev in revs]
5538 revs = [other.lookup(rev) for rev in revs]
5553 ui.debug('comparing with %s\n' % util.hidepassword(source))
5539 ui.debug('comparing with %s\n' % util.hidepassword(source))
5554 repo.ui.pushbuffer()
5540 repo.ui.pushbuffer()
5555 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5541 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5556 _common, incoming, _rheads = commoninc
5542 _common, incoming, _rheads = commoninc
5557 repo.ui.popbuffer()
5543 repo.ui.popbuffer()
5558 if incoming:
5544 if incoming:
5559 t.append(_('1 or more incoming'))
5545 t.append(_('1 or more incoming'))
5560
5546
5561 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5547 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5562 dbranch = branches[0]
5548 dbranch = branches[0]
5563 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5549 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5564 if source != dest:
5550 if source != dest:
5565 other = hg.peer(repo, {}, dest)
5551 other = hg.peer(repo, {}, dest)
5566 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5552 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5567 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5553 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5568 commoninc = None
5554 commoninc = None
5569 if revs:
5555 if revs:
5570 revs = [repo.lookup(rev) for rev in revs]
5556 revs = [repo.lookup(rev) for rev in revs]
5571 repo.ui.pushbuffer()
5557 repo.ui.pushbuffer()
5572 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5558 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5573 commoninc=commoninc)
5559 commoninc=commoninc)
5574 repo.ui.popbuffer()
5560 repo.ui.popbuffer()
5575 o = outgoing.missing
5561 o = outgoing.missing
5576 if o:
5562 if o:
5577 t.append(_('%d outgoing') % len(o))
5563 t.append(_('%d outgoing') % len(o))
5578 if 'bookmarks' in other.listkeys('namespaces'):
5564 if 'bookmarks' in other.listkeys('namespaces'):
5579 lmarks = repo.listkeys('bookmarks')
5565 lmarks = repo.listkeys('bookmarks')
5580 rmarks = other.listkeys('bookmarks')
5566 rmarks = other.listkeys('bookmarks')
5581 diff = set(rmarks) - set(lmarks)
5567 diff = set(rmarks) - set(lmarks)
5582 if len(diff) > 0:
5568 if len(diff) > 0:
5583 t.append(_('%d incoming bookmarks') % len(diff))
5569 t.append(_('%d incoming bookmarks') % len(diff))
5584 diff = set(lmarks) - set(rmarks)
5570 diff = set(lmarks) - set(rmarks)
5585 if len(diff) > 0:
5571 if len(diff) > 0:
5586 t.append(_('%d outgoing bookmarks') % len(diff))
5572 t.append(_('%d outgoing bookmarks') % len(diff))
5587
5573
5588 if t:
5574 if t:
5589 # i18n: column positioning for "hg summary"
5575 # i18n: column positioning for "hg summary"
5590 ui.write(_('remote: %s\n') % (', '.join(t)))
5576 ui.write(_('remote: %s\n') % (', '.join(t)))
5591 else:
5577 else:
5592 # i18n: column positioning for "hg summary"
5578 # i18n: column positioning for "hg summary"
5593 ui.status(_('remote: (synced)\n'))
5579 ui.status(_('remote: (synced)\n'))
5594
5580
5595 @command('tag',
5581 @command('tag',
5596 [('f', 'force', None, _('force tag')),
5582 [('f', 'force', None, _('force tag')),
5597 ('l', 'local', None, _('make the tag local')),
5583 ('l', 'local', None, _('make the tag local')),
5598 ('r', 'rev', '', _('revision to tag'), _('REV')),
5584 ('r', 'rev', '', _('revision to tag'), _('REV')),
5599 ('', 'remove', None, _('remove a tag')),
5585 ('', 'remove', None, _('remove a tag')),
5600 # -l/--local is already there, commitopts cannot be used
5586 # -l/--local is already there, commitopts cannot be used
5601 ('e', 'edit', None, _('edit commit message')),
5587 ('e', 'edit', None, _('edit commit message')),
5602 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5588 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5603 ] + commitopts2,
5589 ] + commitopts2,
5604 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5590 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5605 def tag(ui, repo, name1, *names, **opts):
5591 def tag(ui, repo, name1, *names, **opts):
5606 """add one or more tags for the current or given revision
5592 """add one or more tags for the current or given revision
5607
5593
5608 Name a particular revision using <name>.
5594 Name a particular revision using <name>.
5609
5595
5610 Tags are used to name particular revisions of the repository and are
5596 Tags are used to name particular revisions of the repository and are
5611 very useful to compare different revisions, to go back to significant
5597 very useful to compare different revisions, to go back to significant
5612 earlier versions or to mark branch points as releases, etc. Changing
5598 earlier versions or to mark branch points as releases, etc. Changing
5613 an existing tag is normally disallowed; use -f/--force to override.
5599 an existing tag is normally disallowed; use -f/--force to override.
5614
5600
5615 If no revision is given, the parent of the working directory is
5601 If no revision is given, the parent of the working directory is
5616 used.
5602 used.
5617
5603
5618 To facilitate version control, distribution, and merging of tags,
5604 To facilitate version control, distribution, and merging of tags,
5619 they are stored as a file named ".hgtags" which is managed similarly
5605 they are stored as a file named ".hgtags" which is managed similarly
5620 to other project files and can be hand-edited if necessary. This
5606 to other project files and can be hand-edited if necessary. This
5621 also means that tagging creates a new commit. The file
5607 also means that tagging creates a new commit. The file
5622 ".hg/localtags" is used for local tags (not shared among
5608 ".hg/localtags" is used for local tags (not shared among
5623 repositories).
5609 repositories).
5624
5610
5625 Tag commits are usually made at the head of a branch. If the parent
5611 Tag commits are usually made at the head of a branch. If the parent
5626 of the working directory is not a branch head, :hg:`tag` aborts; use
5612 of the working directory is not a branch head, :hg:`tag` aborts; use
5627 -f/--force to force the tag commit to be based on a non-head
5613 -f/--force to force the tag commit to be based on a non-head
5628 changeset.
5614 changeset.
5629
5615
5630 See :hg:`help dates` for a list of formats valid for -d/--date.
5616 See :hg:`help dates` for a list of formats valid for -d/--date.
5631
5617
5632 Since tag names have priority over branch names during revision
5618 Since tag names have priority over branch names during revision
5633 lookup, using an existing branch name as a tag name is discouraged.
5619 lookup, using an existing branch name as a tag name is discouraged.
5634
5620
5635 Returns 0 on success.
5621 Returns 0 on success.
5636 """
5622 """
5637 wlock = lock = None
5623 wlock = lock = None
5638 try:
5624 try:
5639 wlock = repo.wlock()
5625 wlock = repo.wlock()
5640 lock = repo.lock()
5626 lock = repo.lock()
5641 rev_ = "."
5627 rev_ = "."
5642 names = [t.strip() for t in (name1,) + names]
5628 names = [t.strip() for t in (name1,) + names]
5643 if len(names) != len(set(names)):
5629 if len(names) != len(set(names)):
5644 raise util.Abort(_('tag names must be unique'))
5630 raise util.Abort(_('tag names must be unique'))
5645 for n in names:
5631 for n in names:
5646 scmutil.checknewlabel(repo, n, 'tag')
5632 scmutil.checknewlabel(repo, n, 'tag')
5647 if not n:
5633 if not n:
5648 raise util.Abort(_('tag names cannot consist entirely of '
5634 raise util.Abort(_('tag names cannot consist entirely of '
5649 'whitespace'))
5635 'whitespace'))
5650 if opts.get('rev') and opts.get('remove'):
5636 if opts.get('rev') and opts.get('remove'):
5651 raise util.Abort(_("--rev and --remove are incompatible"))
5637 raise util.Abort(_("--rev and --remove are incompatible"))
5652 if opts.get('rev'):
5638 if opts.get('rev'):
5653 rev_ = opts['rev']
5639 rev_ = opts['rev']
5654 message = opts.get('message')
5640 message = opts.get('message')
5655 if opts.get('remove'):
5641 if opts.get('remove'):
5656 expectedtype = opts.get('local') and 'local' or 'global'
5642 expectedtype = opts.get('local') and 'local' or 'global'
5657 for n in names:
5643 for n in names:
5658 if not repo.tagtype(n):
5644 if not repo.tagtype(n):
5659 raise util.Abort(_("tag '%s' does not exist") % n)
5645 raise util.Abort(_("tag '%s' does not exist") % n)
5660 if repo.tagtype(n) != expectedtype:
5646 if repo.tagtype(n) != expectedtype:
5661 if expectedtype == 'global':
5647 if expectedtype == 'global':
5662 raise util.Abort(_("tag '%s' is not a global tag") % n)
5648 raise util.Abort(_("tag '%s' is not a global tag") % n)
5663 else:
5649 else:
5664 raise util.Abort(_("tag '%s' is not a local tag") % n)
5650 raise util.Abort(_("tag '%s' is not a local tag") % n)
5665 rev_ = nullid
5651 rev_ = nullid
5666 if not message:
5652 if not message:
5667 # we don't translate commit messages
5653 # we don't translate commit messages
5668 message = 'Removed tag %s' % ', '.join(names)
5654 message = 'Removed tag %s' % ', '.join(names)
5669 elif not opts.get('force'):
5655 elif not opts.get('force'):
5670 for n in names:
5656 for n in names:
5671 if n in repo.tags():
5657 if n in repo.tags():
5672 raise util.Abort(_("tag '%s' already exists "
5658 raise util.Abort(_("tag '%s' already exists "
5673 "(use -f to force)") % n)
5659 "(use -f to force)") % n)
5674 if not opts.get('local'):
5660 if not opts.get('local'):
5675 p1, p2 = repo.dirstate.parents()
5661 p1, p2 = repo.dirstate.parents()
5676 if p2 != nullid:
5662 if p2 != nullid:
5677 raise util.Abort(_('uncommitted merge'))
5663 raise util.Abort(_('uncommitted merge'))
5678 bheads = repo.branchheads()
5664 bheads = repo.branchheads()
5679 if not opts.get('force') and bheads and p1 not in bheads:
5665 if not opts.get('force') and bheads and p1 not in bheads:
5680 raise util.Abort(_('not at a branch head (use -f to force)'))
5666 raise util.Abort(_('not at a branch head (use -f to force)'))
5681 r = scmutil.revsingle(repo, rev_).node()
5667 r = scmutil.revsingle(repo, rev_).node()
5682
5668
5683 if not message:
5669 if not message:
5684 # we don't translate commit messages
5670 # we don't translate commit messages
5685 message = ('Added tag %s for changeset %s' %
5671 message = ('Added tag %s for changeset %s' %
5686 (', '.join(names), short(r)))
5672 (', '.join(names), short(r)))
5687
5673
5688 date = opts.get('date')
5674 date = opts.get('date')
5689 if date:
5675 if date:
5690 date = util.parsedate(date)
5676 date = util.parsedate(date)
5691
5677
5692 if opts.get('edit'):
5678 if opts.get('edit'):
5693 message = ui.edit(message, ui.username())
5679 message = ui.edit(message, ui.username())
5694
5680
5695 # don't allow tagging the null rev
5681 # don't allow tagging the null rev
5696 if (not opts.get('remove') and
5682 if (not opts.get('remove') and
5697 scmutil.revsingle(repo, rev_).rev() == nullrev):
5683 scmutil.revsingle(repo, rev_).rev() == nullrev):
5698 raise util.Abort(_("cannot tag null revision"))
5684 raise util.Abort(_("cannot tag null revision"))
5699
5685
5700 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5686 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5701 finally:
5687 finally:
5702 release(lock, wlock)
5688 release(lock, wlock)
5703
5689
5704 @command('tags', [], '')
5690 @command('tags', [], '')
5705 def tags(ui, repo, **opts):
5691 def tags(ui, repo, **opts):
5706 """list repository tags
5692 """list repository tags
5707
5693
5708 This lists both regular and local tags. When the -v/--verbose
5694 This lists both regular and local tags. When the -v/--verbose
5709 switch is used, a third column "local" is printed for local tags.
5695 switch is used, a third column "local" is printed for local tags.
5710
5696
5711 Returns 0 on success.
5697 Returns 0 on success.
5712 """
5698 """
5713
5699
5714 fm = ui.formatter('tags', opts)
5700 fm = ui.formatter('tags', opts)
5715 hexfunc = ui.debugflag and hex or short
5701 hexfunc = ui.debugflag and hex or short
5716 tagtype = ""
5702 tagtype = ""
5717
5703
5718 for t, n in reversed(repo.tagslist()):
5704 for t, n in reversed(repo.tagslist()):
5719 hn = hexfunc(n)
5705 hn = hexfunc(n)
5720 label = 'tags.normal'
5706 label = 'tags.normal'
5721 tagtype = ''
5707 tagtype = ''
5722 if repo.tagtype(t) == 'local':
5708 if repo.tagtype(t) == 'local':
5723 label = 'tags.local'
5709 label = 'tags.local'
5724 tagtype = 'local'
5710 tagtype = 'local'
5725
5711
5726 fm.startitem()
5712 fm.startitem()
5727 fm.write('tag', '%s', t, label=label)
5713 fm.write('tag', '%s', t, label=label)
5728 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5714 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5729 fm.condwrite(not ui.quiet, 'rev id', fmt,
5715 fm.condwrite(not ui.quiet, 'rev id', fmt,
5730 repo.changelog.rev(n), hn, label=label)
5716 repo.changelog.rev(n), hn, label=label)
5731 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5717 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5732 tagtype, label=label)
5718 tagtype, label=label)
5733 fm.plain('\n')
5719 fm.plain('\n')
5734 fm.end()
5720 fm.end()
5735
5721
5736 @command('tip',
5722 @command('tip',
5737 [('p', 'patch', None, _('show patch')),
5723 [('p', 'patch', None, _('show patch')),
5738 ('g', 'git', None, _('use git extended diff format')),
5724 ('g', 'git', None, _('use git extended diff format')),
5739 ] + templateopts,
5725 ] + templateopts,
5740 _('[-p] [-g]'))
5726 _('[-p] [-g]'))
5741 def tip(ui, repo, **opts):
5727 def tip(ui, repo, **opts):
5742 """show the tip revision (DEPRECATED)
5728 """show the tip revision (DEPRECATED)
5743
5729
5744 The tip revision (usually just called the tip) is the changeset
5730 The tip revision (usually just called the tip) is the changeset
5745 most recently added to the repository (and therefore the most
5731 most recently added to the repository (and therefore the most
5746 recently changed head).
5732 recently changed head).
5747
5733
5748 If you have just made a commit, that commit will be the tip. If
5734 If you have just made a commit, that commit will be the tip. If
5749 you have just pulled changes from another repository, the tip of
5735 you have just pulled changes from another repository, the tip of
5750 that repository becomes the current tip. The "tip" tag is special
5736 that repository becomes the current tip. The "tip" tag is special
5751 and cannot be renamed or assigned to a different changeset.
5737 and cannot be renamed or assigned to a different changeset.
5752
5738
5753 This command is deprecated, please use :hg:`heads` instead.
5739 This command is deprecated, please use :hg:`heads` instead.
5754
5740
5755 Returns 0 on success.
5741 Returns 0 on success.
5756 """
5742 """
5757 displayer = cmdutil.show_changeset(ui, repo, opts)
5743 displayer = cmdutil.show_changeset(ui, repo, opts)
5758 displayer.show(repo['tip'])
5744 displayer.show(repo['tip'])
5759 displayer.close()
5745 displayer.close()
5760
5746
5761 @command('unbundle',
5747 @command('unbundle',
5762 [('u', 'update', None,
5748 [('u', 'update', None,
5763 _('update to new branch head if changesets were unbundled'))],
5749 _('update to new branch head if changesets were unbundled'))],
5764 _('[-u] FILE...'))
5750 _('[-u] FILE...'))
5765 def unbundle(ui, repo, fname1, *fnames, **opts):
5751 def unbundle(ui, repo, fname1, *fnames, **opts):
5766 """apply one or more changegroup files
5752 """apply one or more changegroup files
5767
5753
5768 Apply one or more compressed changegroup files generated by the
5754 Apply one or more compressed changegroup files generated by the
5769 bundle command.
5755 bundle command.
5770
5756
5771 Returns 0 on success, 1 if an update has unresolved files.
5757 Returns 0 on success, 1 if an update has unresolved files.
5772 """
5758 """
5773 fnames = (fname1,) + fnames
5759 fnames = (fname1,) + fnames
5774
5760
5775 lock = repo.lock()
5761 lock = repo.lock()
5776 wc = repo['.']
5762 wc = repo['.']
5777 try:
5763 try:
5778 for fname in fnames:
5764 for fname in fnames:
5779 f = hg.openpath(ui, fname)
5765 f = hg.openpath(ui, fname)
5780 gen = changegroup.readbundle(f, fname)
5766 gen = changegroup.readbundle(f, fname)
5781 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5767 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5782 finally:
5768 finally:
5783 lock.release()
5769 lock.release()
5784 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5770 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5785 return postincoming(ui, repo, modheads, opts.get('update'), None)
5771 return postincoming(ui, repo, modheads, opts.get('update'), None)
5786
5772
5787 @command('^update|up|checkout|co',
5773 @command('^update|up|checkout|co',
5788 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5774 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5789 ('c', 'check', None,
5775 ('c', 'check', None,
5790 _('update across branches if no uncommitted changes')),
5776 _('update across branches if no uncommitted changes')),
5791 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5777 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5792 ('r', 'rev', '', _('revision'), _('REV'))],
5778 ('r', 'rev', '', _('revision'), _('REV'))],
5793 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5779 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5794 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5780 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5795 """update working directory (or switch revisions)
5781 """update working directory (or switch revisions)
5796
5782
5797 Update the repository's working directory to the specified
5783 Update the repository's working directory to the specified
5798 changeset. If no changeset is specified, update to the tip of the
5784 changeset. If no changeset is specified, update to the tip of the
5799 current named branch and move the current bookmark (see :hg:`help
5785 current named branch and move the current bookmark (see :hg:`help
5800 bookmarks`).
5786 bookmarks`).
5801
5787
5802 Update sets the working directory's parent revision to the specified
5788 Update sets the working directory's parent revision to the specified
5803 changeset (see :hg:`help parents`).
5789 changeset (see :hg:`help parents`).
5804
5790
5805 If the changeset is not a descendant or ancestor of the working
5791 If the changeset is not a descendant or ancestor of the working
5806 directory's parent, the update is aborted. With the -c/--check
5792 directory's parent, the update is aborted. With the -c/--check
5807 option, the working directory is checked for uncommitted changes; if
5793 option, the working directory is checked for uncommitted changes; if
5808 none are found, the working directory is updated to the specified
5794 none are found, the working directory is updated to the specified
5809 changeset.
5795 changeset.
5810
5796
5811 .. container:: verbose
5797 .. container:: verbose
5812
5798
5813 The following rules apply when the working directory contains
5799 The following rules apply when the working directory contains
5814 uncommitted changes:
5800 uncommitted changes:
5815
5801
5816 1. If neither -c/--check nor -C/--clean is specified, and if
5802 1. If neither -c/--check nor -C/--clean is specified, and if
5817 the requested changeset is an ancestor or descendant of
5803 the requested changeset is an ancestor or descendant of
5818 the working directory's parent, the uncommitted changes
5804 the working directory's parent, the uncommitted changes
5819 are merged into the requested changeset and the merged
5805 are merged into the requested changeset and the merged
5820 result is left uncommitted. If the requested changeset is
5806 result is left uncommitted. If the requested changeset is
5821 not an ancestor or descendant (that is, it is on another
5807 not an ancestor or descendant (that is, it is on another
5822 branch), the update is aborted and the uncommitted changes
5808 branch), the update is aborted and the uncommitted changes
5823 are preserved.
5809 are preserved.
5824
5810
5825 2. With the -c/--check option, the update is aborted and the
5811 2. With the -c/--check option, the update is aborted and the
5826 uncommitted changes are preserved.
5812 uncommitted changes are preserved.
5827
5813
5828 3. With the -C/--clean option, uncommitted changes are discarded and
5814 3. With the -C/--clean option, uncommitted changes are discarded and
5829 the working directory is updated to the requested changeset.
5815 the working directory is updated to the requested changeset.
5830
5816
5831 To cancel an uncommitted merge (and lose your changes), use
5817 To cancel an uncommitted merge (and lose your changes), use
5832 :hg:`update --clean .`.
5818 :hg:`update --clean .`.
5833
5819
5834 Use null as the changeset to remove the working directory (like
5820 Use null as the changeset to remove the working directory (like
5835 :hg:`clone -U`).
5821 :hg:`clone -U`).
5836
5822
5837 If you want to revert just one file to an older revision, use
5823 If you want to revert just one file to an older revision, use
5838 :hg:`revert [-r REV] NAME`.
5824 :hg:`revert [-r REV] NAME`.
5839
5825
5840 See :hg:`help dates` for a list of formats valid for -d/--date.
5826 See :hg:`help dates` for a list of formats valid for -d/--date.
5841
5827
5842 Returns 0 on success, 1 if there are unresolved files.
5828 Returns 0 on success, 1 if there are unresolved files.
5843 """
5829 """
5844 if rev and node:
5830 if rev and node:
5845 raise util.Abort(_("please specify just one revision"))
5831 raise util.Abort(_("please specify just one revision"))
5846
5832
5847 if rev is None or rev == '':
5833 if rev is None or rev == '':
5848 rev = node
5834 rev = node
5849
5835
5850 cmdutil.clearunfinished(repo)
5836 cmdutil.clearunfinished(repo)
5851
5837
5852 # with no argument, we also move the current bookmark, if any
5838 # with no argument, we also move the current bookmark, if any
5853 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5839 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5854
5840
5855 # if we defined a bookmark, we have to remember the original bookmark name
5841 # if we defined a bookmark, we have to remember the original bookmark name
5856 brev = rev
5842 brev = rev
5857 rev = scmutil.revsingle(repo, rev, rev).rev()
5843 rev = scmutil.revsingle(repo, rev, rev).rev()
5858
5844
5859 if check and clean:
5845 if check and clean:
5860 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5846 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5861
5847
5862 if date:
5848 if date:
5863 if rev is not None:
5849 if rev is not None:
5864 raise util.Abort(_("you can't specify a revision and a date"))
5850 raise util.Abort(_("you can't specify a revision and a date"))
5865 rev = cmdutil.finddate(ui, repo, date)
5851 rev = cmdutil.finddate(ui, repo, date)
5866
5852
5867 if check:
5853 if check:
5868 c = repo[None]
5854 c = repo[None]
5869 if c.dirty(merge=False, branch=False, missing=True):
5855 if c.dirty(merge=False, branch=False, missing=True):
5870 raise util.Abort(_("uncommitted changes"))
5856 raise util.Abort(_("uncommitted changes"))
5871 if rev is None:
5857 if rev is None:
5872 rev = repo[repo[None].branch()].rev()
5858 rev = repo[repo[None].branch()].rev()
5873 mergemod._checkunknown(repo, repo[None], repo[rev])
5859 mergemod._checkunknown(repo, repo[None], repo[rev])
5874
5860
5875 if clean:
5861 if clean:
5876 ret = hg.clean(repo, rev)
5862 ret = hg.clean(repo, rev)
5877 else:
5863 else:
5878 ret = hg.update(repo, rev)
5864 ret = hg.update(repo, rev)
5879
5865
5880 if not ret and movemarkfrom:
5866 if not ret and movemarkfrom:
5881 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5867 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5882 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5868 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5883 elif brev in repo._bookmarks:
5869 elif brev in repo._bookmarks:
5884 bookmarks.setcurrent(repo, brev)
5870 bookmarks.setcurrent(repo, brev)
5885 elif brev:
5871 elif brev:
5886 bookmarks.unsetcurrent(repo)
5872 bookmarks.unsetcurrent(repo)
5887
5873
5888 return ret
5874 return ret
5889
5875
5890 @command('verify', [])
5876 @command('verify', [])
5891 def verify(ui, repo):
5877 def verify(ui, repo):
5892 """verify the integrity of the repository
5878 """verify the integrity of the repository
5893
5879
5894 Verify the integrity of the current repository.
5880 Verify the integrity of the current repository.
5895
5881
5896 This will perform an extensive check of the repository's
5882 This will perform an extensive check of the repository's
5897 integrity, validating the hashes and checksums of each entry in
5883 integrity, validating the hashes and checksums of each entry in
5898 the changelog, manifest, and tracked files, as well as the
5884 the changelog, manifest, and tracked files, as well as the
5899 integrity of their crosslinks and indices.
5885 integrity of their crosslinks and indices.
5900
5886
5901 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5887 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5902 for more information about recovery from corruption of the
5888 for more information about recovery from corruption of the
5903 repository.
5889 repository.
5904
5890
5905 Returns 0 on success, 1 if errors are encountered.
5891 Returns 0 on success, 1 if errors are encountered.
5906 """
5892 """
5907 return hg.verify(repo)
5893 return hg.verify(repo)
5908
5894
5909 @command('version', [])
5895 @command('version', [])
5910 def version_(ui):
5896 def version_(ui):
5911 """output version and copyright information"""
5897 """output version and copyright information"""
5912 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5898 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5913 % util.version())
5899 % util.version())
5914 ui.status(_(
5900 ui.status(_(
5915 "(see http://mercurial.selenic.com for more information)\n"
5901 "(see http://mercurial.selenic.com for more information)\n"
5916 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5902 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5917 "This is free software; see the source for copying conditions. "
5903 "This is free software; see the source for copying conditions. "
5918 "There is NO\nwarranty; "
5904 "There is NO\nwarranty; "
5919 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5905 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5920 ))
5906 ))
5921
5907
5922 norepo = ("clone init version help debugcommands debugcomplete"
5908 norepo = ("clone init version help debugcommands debugcomplete"
5923 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5909 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5924 " debugknown debuggetbundle debugbundle")
5910 " debugknown debuggetbundle debugbundle")
5925 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5911 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5926 " debugdata debugindex debugindexdot debugrevlog")
5912 " debugdata debugindex debugindexdot debugrevlog")
5927 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5913 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5928 " remove resolve status debugwalk")
5914 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now